From 23d15fe16ee1e3e8b3ffc14e59d84473c04667ed Mon Sep 17 00:00:00 2001 From: Karel Tucek Date: Mon, 6 Nov 2023 14:20:37 +0100 Subject: [PATCH] Implement touchpad hold continuation timeout. --- doc-dev/reference-manual.md | 3 +++ right/src/macros/set_command.c | 5 ++++ right/src/mouse_controller.c | 42 +++++++++++++++++++++++++++++++--- right/src/mouse_controller.h | 1 + 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/doc-dev/reference-manual.md b/doc-dev/reference-manual.md index 91f359963..84eb26150 100644 --- a/doc-dev/reference-manual.md +++ b/doc-dev/reference-manual.md @@ -109,6 +109,7 @@ The following grammar is supported: COMMAND = set module.MODULEID.invertScrollDirectionY BOOL COMMAND = set module.touchpad.pinchZoomDivisor <1-100 (FLOAT)> COMMAND = set module.touchpad.pinchZoomMode NAVIGATION_MODE + COMMAND = set module.touchpad.holdContinuationTimeout <0-65535 (INT)> COMMAND = set secondaryRole.defaultStrategy { simple | advanced } COMMAND = set secondaryRole.advanced.timeout COMMAND = set secondaryRole.advanced.timeoutAction { primary | secondary } @@ -565,6 +566,8 @@ Internally, values are saved in one of the following types, and types are automa - `scrollAxisLock BOOL` - turns axis locking on for scroll mode. Default for keycluster trackball. - `caretAxisLock BOOL` - turns axis locking on for all discrete modes. +- `set module.touchpad.holdContinuationTimeout <0-65535 (INT)>` If non-zero, touchpad allows you to release your finger for the specified amount of time during drag-and-drop (without the left click getting released). + - Remapping keys: - `set navigationModeAction.{caret|media}.{DIRECTION|none} ACTION` can be used to customize the caret or media mode behaviour by binding directions to macros. This action is global and reversible only by powercycling. - `set keymapAction.LAYERID.KEYID ACTION` can be used to remap any action that lives in a keymap. Most remappable ids can be retrieved with `resolveNextKeyId`. Keyid can also be constructed manually - see `KEYID`. Binding applies only until the next keymap switch. E.g., `set keymapAction.base.64 keystroke escape` (maps `~` key to escape), or `set keymapAction.fn.193 macro TouchpadAction` (maps touchpad two-finger gesture to a macro named `TouchpadAction`). diff --git a/right/src/macros/set_command.c b/right/src/macros/set_command.c index ccecc78a9..66e7393d9 100644 --- a/right/src/macros/set_command.c +++ b/right/src/macros/set_command.c @@ -252,9 +252,14 @@ static macro_variable_t module(parser_context_t* ctx, set_command_action_t actio ConsumeUntilDot(ctx); return moduleNavigationMode(ctx, action, module); } + else if (ConsumeToken(ctx, "holdContinuationTimeout") && moduleId == ModuleId_TouchpadRight) { + DEFINE_INT_LIMITS(0, 65535); + ASSIGN_INT(HoldContinuationTimeout); + } else { return moduleSpeed(ctx, action, module, moduleId); } + return noneVar(); } static macro_variable_t secondaryRoleAdvanced(parser_context_t* ctx, set_command_action_t action) diff --git a/right/src/mouse_controller.c b/right/src/mouse_controller.c index 6b4db5d5c..e602ecb0e 100644 --- a/right/src/mouse_controller.c +++ b/right/src/mouse_controller.c @@ -108,7 +108,8 @@ static float computeModuleSpeed(float x, float y, uint8_t moduleId) typedef enum { State_Zero, State_Tap, - State_TapAndHold + State_TapAndHold, + State_HoldContinuationDelay, } tap_hold_state_t; typedef enum { @@ -118,6 +119,7 @@ typedef enum { Event_FingerIn, Event_FingerOut, Event_TapAndHold, + Event_HoldContinuationTimeout, } tap_hold_event_t; typedef enum { @@ -125,10 +127,13 @@ typedef enum { Action_Press = 2, Action_Release = 4, Action_Doubletap = 8, + Action_ResetHoldContinuationTimeout = 16, } tap_hold_action_t; static tap_hold_state_t tapHoldAutomatonState = State_Zero; +uint16_t HoldContinuationTimeout = 0; + static tap_hold_action_t tapHoldStateMachine(tap_hold_event_t event) { switch (tapHoldAutomatonState) { @@ -168,6 +173,26 @@ static tap_hold_action_t tapHoldStateMachine(tap_hold_event_t event) tapHoldAutomatonState = State_Tap; return Action_ResetTimer | Action_Doubletap; case Event_FingerOut: + if (HoldContinuationTimeout == 0) { + tapHoldAutomatonState = State_Zero; + return Action_Release; + } else { + tapHoldAutomatonState = State_HoldContinuationDelay; + return Action_ResetHoldContinuationTimeout; + } + default: + return 0; + } + case State_HoldContinuationDelay: + switch (event) { + case Event_NewTap: + tapHoldAutomatonState = State_Tap; + return Action_ResetTimer | Action_Doubletap; + case Event_TapAndHold: + case Event_FingerIn: + tapHoldAutomatonState = State_TapAndHold; + return 0; + case Event_HoldContinuationTimeout: tapHoldAutomatonState = State_Zero; return Action_Release; default: @@ -184,9 +209,12 @@ static void feedTapHoldStateMachine(touchpad_events_t events) // Or add artificial delay bellow. const uint16_t tapTimeout = 200; static uint32_t lastSingleTapTime = 0; + static uint32_t continuationDelayStart = 0; static bool lastFinger = false; static bool lastSingleTapValue = false; static bool lastTapAndHoldValue = false; + static bool lastSingleTapTimerActive = false; + static bool holdContinuationTimerActive = false; tap_hold_action_t action = 0; tap_hold_event_t event = 0; @@ -200,14 +228,19 @@ static void feedTapHoldStateMachine(touchpad_events_t events) } else if (lastFinger != (events.noFingers == 1)) { event = lastFinger ? Event_FingerOut : Event_FingerIn ; lastFinger = !lastFinger; - } else if(lastSingleTapTime + tapTimeout < CurrentTime) { + } else if (lastSingleTapTimerActive && lastSingleTapTime + tapTimeout < CurrentTime) { event = Event_Timeout; + lastSingleTapTimerActive = false; + } else if (holdContinuationTimerActive && continuationDelayStart + HoldContinuationTimeout < CurrentTime) { + event = Event_HoldContinuationTimeout; + holdContinuationTimerActive = false; } action = tapHoldStateMachine(event); if (action & Action_ResetTimer) { lastSingleTapTime = CurrentTime; + lastSingleTapTimerActive = true; } if (action & Action_Release) { PostponerCore_TrackKeyEvent(singleTap, false, 0xff); @@ -220,7 +253,10 @@ static void feedTapHoldStateMachine(touchpad_events_t events) PostponerCore_TrackDelay(20); PostponerCore_TrackKeyEvent(singleTap, true, 0xff); } - + if (action & Action_ResetHoldContinuationTimeout) { + continuationDelayStart = CurrentTime; + holdContinuationTimerActive = true; + } lastSingleTapValue &= events.singleTap; lastTapAndHoldValue &= events.tapAndHold; diff --git a/right/src/mouse_controller.h b/right/src/mouse_controller.h index efb29f181..c163d7c02 100644 --- a/right/src/mouse_controller.h +++ b/right/src/mouse_controller.h @@ -29,6 +29,7 @@ // Variables: + extern uint16_t HoldContinuationTimeout; // Functions: void MouseController_ProcessMouseActions();