Skip to content

Commit

Permalink
Merge pull request #724 from kareltucek/hold_continuation_timeout
Browse files Browse the repository at this point in the history
Implement touchpad hold continuation timeout.
  • Loading branch information
mondalaci authored Nov 8, 2023
2 parents 9f5c27b + 23d15fe commit 3813741
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 3 deletions.
3 changes: 3 additions & 0 deletions doc-dev/reference-manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <ms, 0-500 (INT)>
COMMAND = set secondaryRole.advanced.timeoutAction { primary | secondary }
Expand Down Expand Up @@ -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`).
Expand Down
5 changes: 5 additions & 0 deletions right/src/macros/set_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
42 changes: 39 additions & 3 deletions right/src/mouse_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -118,17 +119,21 @@ typedef enum {
Event_FingerIn,
Event_FingerOut,
Event_TapAndHold,
Event_HoldContinuationTimeout,
} tap_hold_event_t;

typedef enum {
Action_ResetTimer = 1,
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) {
Expand Down Expand Up @@ -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:
Expand All @@ -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;

Expand All @@ -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);
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions right/src/mouse_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

// Variables:

extern uint16_t HoldContinuationTimeout;

// Functions:
void MouseController_ProcessMouseActions();
Expand Down

0 comments on commit 3813741

Please sign in to comment.