Skip to content
CleverKeys Wiki
planned v1.3.0 (planned) User guide

Circle Gestures Technical Specification

Overview

Planned feature for detecting circular finger movements to trigger undo/redo actions.

Current Status

[!NOTE] Circle gesture detection is not yet implemented. This spec documents the planned design.

Planned Components

ComponentFilePurpose
CircleDetectorCircleDetector.kt (planned)Analyze touch path for circles
PointersPointers.ktIntegration point
GestureConfigConfig.ktCircle detection parameters

Detection Algorithm (Planned)

Point Collection

// Collect touch points during swipe
data class TouchPoint(val x: Float, val y: Float, val time: Long)
val path: MutableList<TouchPoint> = mutableListOf()

Angle Calculation

// Calculate cumulative angle change
fun calculateTotalAngle(points: List<TouchPoint>): Float {
    var totalAngle = 0f

    for (i in 2 until points.size) {
        val v1 = Vector(points[i-1].x - points[i-2].x,
                       points[i-1].y - points[i-2].y)
        val v2 = Vector(points[i].x - points[i-1].x,
                       points[i].y - points[i-1].y)

        totalAngle += angleBetween(v1, v2)
    }

    return totalAngle
}

Circle Detection

// Detect complete circle
fun detectCircle(points: List<TouchPoint>): CircleResult? {
    if (points.size < MIN_POINTS) return null

    val totalAngle = calculateTotalAngle(points)

    return when {
        totalAngle >= 300f -> CircleResult.CLOCKWISE      // Redo
        totalAngle <= -300f -> CircleResult.COUNTER_CW    // Undo
        else -> null
    }
}

Planned Configuration

SettingKeyDefaultRange
Circle Gesturescircle_gestures_enabledtrueboolean
Min Anglecircle_min_angle300°270-360
Max Timecircle_max_time1000ms500-2000
Min Radiuscircle_min_radius30px20-50

Action Mapping (Planned)

Circle DirectionDefault ActionCustomizable
ClockwiseRedo (Ctrl+Y)Yes
Counter-clockwiseUndo (Ctrl+Z)Yes

Integration Points

Pointers.kt

// In onTouchMove, if swipe mode not yet determined
if (!isSwipeTyping && !isShortSwipe) {
    circleDetector.addPoint(ptr.x, ptr.y, currentTime)

    val result = circleDetector.detectCircle()
    if (result != null) {
        handleCircleGesture(result)
        return
    }
}

KeyEventHandler.kt

fun handleCircleGesture(result: CircleResult) {
    when (result) {
        CircleResult.CLOCKWISE -> sendKeyCombo(CTRL, 'Y')
        CircleResult.COUNTER_CW -> sendKeyCombo(CTRL, 'Z')
    }
}

Challenges

  1. Disambiguation: Must not interfere with swipe typing
  2. Performance: Real-time angle calculation during touch
  3. User feedback: Visual indication of circle progress
  4. Accessibility: Alternative access for users who can’t draw circles