diff --git a/src/config/double-tap.ts b/src/config/double-tap.ts index 9fe6c1e..460d7ff 100644 --- a/src/config/double-tap.ts +++ b/src/config/double-tap.ts @@ -13,9 +13,9 @@ import { BuildContext } from '../utils/build-context' import { FromModifierParam } from './modifier' import { FromModifierOverloadParam, - FromOptionalModifierParam, parseFromModifierOverload, } from '../utils/from-modifier-overload' +import { FromOptionalModifierParam } from '../utils/optional-modifiers' export const defaultDoubleTapParameters = { 'double_tap.delay_milliseconds': 200, diff --git a/src/config/from.test.ts b/src/config/from.test.ts index f5b174d..1a03b98 100644 --- a/src/config/from.test.ts +++ b/src/config/from.test.ts @@ -14,10 +14,12 @@ test('map()', () => { modifiers: { optional: ['command'] }, }) - expect(map(1, 'optionalAny').to(2).build()[0].from).toEqual({ - key_code: '1', - modifiers: { optional: ['any'] }, - }) + for (const optionalAny of ['optionalAny', '?any', '??'] as const) { + expect(map(1, optionalAny).to(2).build()[0].from).toEqual({ + key_code: '1', + modifiers: { optional: ['any'] }, + }) + } expect(map(1, { optional: 'any' }).to(2).build()[0].from).toEqual({ key_code: '1', @@ -28,6 +30,13 @@ test('map()', () => { key_code: '1', modifiers: { optional: ['command', 'option'] }, }) + + expect(map(1, '?⌘⌥').to(2).build()[0].from).toEqual({ + key_code: '1', + modifiers: { optional: ['command', 'option'] }, + }) + + expect(() => map(1, '?⌘⌥x' as any)).toThrow() }) test('mapConsumerKey()', () => { diff --git a/src/config/from.ts b/src/config/from.ts index 51cad72..2a604f6 100644 --- a/src/config/from.ts +++ b/src/config/from.ts @@ -7,9 +7,9 @@ import { FromConsumerKeyCode } from '../karabiner/consumer-key-code' import { PointingButton } from '../karabiner/pointing-button' import { FromModifierOverloadParam, - FromOptionalModifierParam, parseFromModifierOverload, } from '../utils/from-modifier-overload' +import { FromOptionalModifierParam } from '../utils/optional-modifiers' export type FromKeyParam = FromKeyCode | KeyAlias | NumberKeyValue diff --git a/src/config/simlayer.ts b/src/config/simlayer.ts index 18ad38e..d50f8bd 100644 --- a/src/config/simlayer.ts +++ b/src/config/simlayer.ts @@ -14,10 +14,10 @@ import { LayerKeyCode, LayerKeyParam, layerToggleManipulator } from './layer' import { BuildContext } from '../utils/build-context' import { FromModifierOverloadParam, - FromOptionalModifierParam, parseFromModifierOverload, } from '../utils/from-modifier-overload' import { FromModifierParam } from './modifier' +import { FromOptionalModifierParam } from '../utils/optional-modifiers' export const defaultSimlayerParameters = { 'simlayer.threshold_milliseconds': 200, diff --git a/src/config/simultaneous.ts b/src/config/simultaneous.ts index 7f6678c..aff4e95 100644 --- a/src/config/simultaneous.ts +++ b/src/config/simultaneous.ts @@ -9,10 +9,10 @@ import { FromKeyCode } from '../karabiner/key-code' import { FromKeyParam } from './from' import { FromModifierOverloadParam, - FromOptionalModifierParam, parseFromModifierOverload, } from '../utils/from-modifier-overload' import { FromModifierParam } from './modifier' +import { FromOptionalModifierParam } from '../utils/optional-modifiers' /** Start a manipulator with from.simultaneous */ export function mapSimultaneous( diff --git a/src/utils/from-modifier-overload.ts b/src/utils/from-modifier-overload.ts index 47a362d..5ab0b77 100644 --- a/src/utils/from-modifier-overload.ts +++ b/src/utils/from-modifier-overload.ts @@ -1,8 +1,14 @@ -import { FromModifierParam, parseFromModifierParams } from '../config/modifier' - -export type FromOptionalModifierParam = - | 'optionalAny' - | { optional: FromModifierParam } +import { + FromModifierParam, + ModifierParam, + parseFromModifierParams, + parseModifierParam, +} from '../config/modifier' +import { + FromOptionalModifierParam, + isOptionalAnyAlias, + isOptionalModifierAlias, +} from './optional-modifiers' export type FromModifierOverloadParam = | FromModifierParam @@ -16,14 +22,29 @@ export function parseFromModifierOverload( ) { if (!mandatoryModifiers) { return parseFromModifierParams(mandatoryModifiers, optionalModifiers) - } else if (mandatoryModifiers === 'optionalAny') { + } + + if (isOptionalAnyAlias(mandatoryModifiers)) { return parseFromModifierParams('', 'any') - } else if ( + } + + if (typeof mandatoryModifiers === 'string') { + if (isOptionalModifierAlias(mandatoryModifiers)) { + return parseFromModifierParams( + '', + parseModifierParam(mandatoryModifiers.slice(1) as ModifierParam), + ) + } else if (mandatoryModifiers.startsWith('?')) { + throw new Error(`${mandatoryModifiers} is not valid optional alias`) + } + } + + if ( typeof mandatoryModifiers === 'object' && 'optional' in mandatoryModifiers ) { return parseFromModifierParams('', mandatoryModifiers.optional) - } else { - return parseFromModifierParams(mandatoryModifiers, optionalModifiers) } + + return parseFromModifierParams(mandatoryModifiers, optionalModifiers) } diff --git a/src/utils/optional-modifiers.ts b/src/utils/optional-modifiers.ts new file mode 100644 index 0000000..7d7c5a8 --- /dev/null +++ b/src/utils/optional-modifiers.ts @@ -0,0 +1,29 @@ +import { FromModifierParam } from '../config/modifier' +import { ModifierKeyAlias, modifierKeyAliases } from './key-alias' +import { MultiModifierAlias, multiModifierAliases } from './multi-modifier' + +const optionalAnyAliases = ['optionalAny', '?any', '??'] as const +export type OptionalAnyAlias = (typeof optionalAnyAliases)[number] + +export type OptionalModifierAlias = `?${ModifierKeyAlias | MultiModifierAlias}` + +export function isOptionalAnyAlias(src: any): src is OptionalAnyAlias { + if (!src || typeof src !== 'string') return false + return optionalAnyAliases.includes(src as OptionalAnyAlias) +} + +export type FromOptionalModifierParam = + | OptionalAnyAlias + | { optional: FromModifierParam } + | OptionalModifierAlias + +const optionalModifierAliases = [ + ...Object.keys(modifierKeyAliases), + ...Object.keys(multiModifierAliases), +].map((v) => `?${v}`) + +export function isOptionalModifierAlias( + src: string, +): src is OptionalModifierAlias { + return optionalModifierAliases.includes(src) +} diff --git a/src/utils/with-modifier.ts b/src/utils/with-modifier.ts index f2ebbbb..c702955 100644 --- a/src/utils/with-modifier.ts +++ b/src/utils/with-modifier.ts @@ -2,10 +2,8 @@ import { Manipulator, Modifier } from '../karabiner/karabiner-config' import { FromModifierParam } from '../config/modifier' import { buildManipulators, ManipulatorBuilder } from '../config/manipulator' import { BuildContext } from './build-context' -import { - FromOptionalModifierParam, - parseFromModifierOverload, -} from './from-modifier-overload' +import { parseFromModifierOverload } from './from-modifier-overload' +import { FromOptionalModifierParam } from './optional-modifiers' /** * A high-order function to add modifiers to a group of manipulators