Skip to content

Commit

Permalink
🐛 Fix double tap on layer leader mode (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
evan-liu authored Dec 21, 2024
1 parent 0875f8c commit 9e4fce0
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/config/double-tap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('mapDoubleTap()', () => {
from: { key_code: '1' },
to: [{ key_code: '2' }],
conditions: [{ name: 'double-tap-1', type: 'variable_if', value: 1 }],
description: '__support__manipulator',
},
{
type: 'basic',
Expand Down Expand Up @@ -56,6 +57,7 @@ describe('mapDoubleTap()', () => {
from: { key_code: '1' },
to: [{ key_code: '2' }],
conditions: [{ name: 'double-tap-1', type: 'variable_if', value: 1 }],
description: '__support__manipulator',
},
{
type: 'basic',
Expand Down
9 changes: 5 additions & 4 deletions src/config/double-tap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { FromOptionalModifierParam } from '../utils/optional-modifiers.ts'
import { ifVar } from './condition.ts'
import { BasicManipulatorBuilder } from './manipulator.ts'
import { FromModifierParam } from './modifier.ts'
import { supportManipulator } from './support-manipulator.ts'
import { toSetVar } from './to.ts'

export const defaultDoubleTapParameters = {
Expand Down Expand Up @@ -144,15 +145,15 @@ export class DoubleTapManipulatorBuilder extends BasicManipulatorBuilder {
const onCondition = ifVar(varName).build()
const offCondition = ifVar(varName).unless().build()

const baseManipulator: BasicManipulator = {
const baseManipulator = supportManipulator({
...this.manipulator,
conditions: [...(this.manipulator.conditions || []), onCondition],
}
conditions: [onCondition],
})

const toggleManipulator: BasicManipulator = {
...this.manipulator,
to: [toSetVar(varName, 1)],
conditions: [offCondition],
conditions: [...(this.manipulator.conditions || []), offCondition],
to_delayed_action: {
to_if_invoked: [
...(this.singleTapEvent ? [this.singleTapEvent] : []),
Expand Down
6 changes: 5 additions & 1 deletion src/config/duo-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { buildCondition, ConditionBuilder, ifVar } from './condition.ts'
import { LayerKeyParam } from './layer.ts'
import { BasicRuleBuilder } from './rule.ts'
import { mapSimultaneous } from './simultaneous.ts'
import { isSupportManipulator } from './support-manipulator.ts'
import {
toNotificationMessage,
toRemoveNotificationMessage,
Expand Down Expand Up @@ -143,7 +144,10 @@ export class DuoLayerRuleBuilder extends BasicRuleBuilder {
if (this.leaderModeOptions) {
if (!this.leaderModeOptions.sticky) {
rule.manipulators.forEach(
(v) => v.type === 'basic' && (v.to = (v.to || []).concat(deactivate)),
(v) =>
v.type === 'basic' &&
!isSupportManipulator(v) &&
(v.to = (v.to || []).concat(deactivate)),
)
}
rule.manipulators.push(
Expand Down
37 changes: 37 additions & 0 deletions src/config/layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {

import { complexModifications } from './complex-modifications'
import { ifVar } from './condition'
import { mapDoubleTap } from './double-tap.ts'
import { map } from './from'
import { hyperLayer, layer, LayerRuleBuilder } from './layer'
import { mouseMotionToScroll } from './mouse-motion-to-scroll'
Expand Down Expand Up @@ -447,4 +448,40 @@ describe('layer() leader mode', () => {
expect(manipulators[3].conditions).toEqual([ifOn])
expect(manipulators[3].to).toEqual([toOff, toLayerVarOff, remove])
})

test('leader() and mapDoubleTap()', () => {
const rule = layer('a')
.leaderMode({ sticky: true })
.notification()
.manipulators([mapDoubleTap(1).to(2).singleTap(toKey(3))])
.build()
const manipulators = rule.manipulators as BasicManipulator[]
expect(manipulators.length).toBe(5)

const ifOn = ifVar('layer-a', 1).build()
const toOff = toSetVar('layer-a', 0)
const toLayerVarOff = toSetVar('__layer', 0)
const remove = toRemoveNotificationMessage('layer-layer-a')

// the second tap
expect(manipulators[1].to).toEqual([{ key_code: '2' }])
expect(manipulators[1].conditions).toEqual([
{ name: 'double-tap-1', type: 'variable_if', value: 1 },
])

// the first tap
expect(manipulators[2].to).toEqual([
{ set_variable: { name: 'double-tap-1', value: 1 } },
])
expect(manipulators[2].conditions).toEqual([
{ name: 'double-tap-1', type: 'variable_unless', value: 1 },
ifOn,
])

// escape keys
expect(manipulators[3].conditions).toEqual([ifOn])
expect(manipulators[3].to).toEqual([toOff, toLayerVarOff, remove])
expect(manipulators[4].conditions).toEqual([ifOn])
expect(manipulators[4].to).toEqual([toOff, toLayerVarOff, remove])
})
})
6 changes: 5 additions & 1 deletion src/config/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
SideModifierAlias,
} from './modifier.ts'
import { BasicRuleBuilder } from './rule.ts'
import { isSupportManipulator } from './support-manipulator.ts'
import { toRemoveNotificationMessage, toSetVar } from './to.ts'

export type LayerKeyCode = Exclude<
Expand Down Expand Up @@ -192,7 +193,10 @@ export class LayerRuleBuilder extends BasicRuleBuilder {
}
if (!this.leaderModeOptions.sticky) {
rule.manipulators.forEach(
(v) => v.type === 'basic' && (v.to = (v.to || []).concat(toOff)),
(v) =>
v.type === 'basic' &&
!isSupportManipulator(v) &&
(v.to = (v.to || []).concat(toOff)),
)
}
rule.manipulators.push(
Expand Down
3 changes: 2 additions & 1 deletion src/config/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ManipulatorBuilder,
ManipulatorMap,
} from './manipulator.ts'
import { isSupportManipulator } from './support-manipulator.ts'

export function rule(
description: string,
Expand Down Expand Up @@ -69,7 +70,7 @@ export class BasicRuleBuilder implements RuleBuilder {

const conditions = this.conditions.map(buildCondition)
rule.manipulators = rule.manipulators.map((v) =>
v.type === 'basic'
v.type === 'basic' && !isSupportManipulator(v)
? { ...v, conditions: [...(v.conditions || []), ...conditions] }
: { ...v },
)
Expand Down
13 changes: 13 additions & 0 deletions src/config/support-manipulator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BasicManipulator, Manipulator } from '../karabiner/karabiner-config.ts'

const suffix = '__support__manipulator'

/** Manipulators only to support normal manipulators. */
export function supportManipulator(manipulator: BasicManipulator) {
manipulator.description = (manipulator.description || '') + suffix
return manipulator
}

export function isSupportManipulator(manipulator: Manipulator) {
return (manipulator as BasicManipulator).description?.endsWith(suffix)
}

0 comments on commit 9e4fce0

Please sign in to comment.