Repository: evan-liu/karabiner.ts
Pull request #11 (2023-04-24 03:22:35)

✨ Add mapSimultaneous()


Patch:
diff --git a/src/config/from.ts b/src/config/from.ts
index 56830a9..99466d6 100644
--- a/src/config/from.ts
+++ b/src/config/from.ts
@@ -2,6 +2,7 @@ import { FromKeyCode } from '../karabiner/key-code'
 import { getKeyWithAlias, KeyAlias, NumberKeyValue } from '../utils/key-alias'
 import { FromModifierParam, parseFromModifierParams } from './modifier'
 import { ManipulatorBuilder } from './manipulator'
+import { SimultaneousOptions } from '../karabiner/karabiner-config'
 
 export type FromKeyParam = FromKeyCode | KeyAlias | NumberKeyValue
 
@@ -15,3 +16,19 @@ export function map(
     modifiers: parseFromModifierParams(mandatoryModifiers, optionalModifiers),
   })
 }
+
+export function mapSimultaneous(
+  keys: FromKeyParam[],
+  options?: SimultaneousOptions,
+  threshold?: number,
+) {
+  const manipulatorBuilder = new ManipulatorBuilder({
+    simultaneous: keys.map((v) => ({ key_code: getKeyWithAlias(v) })),
+    simultaneous_options: options,
+  })
+  return threshold
+    ? manipulatorBuilder.parameters({
+        'basic.simultaneous_threshold_milliseconds': threshold,
+      })
+    : manipulatorBuilder
+}
diff --git a/src/karabiner/karabiner-config.ts b/src/karabiner/karabiner-config.ts
index e507e3a..7e79f10 100644
--- a/src/karabiner/karabiner-config.ts
+++ b/src/karabiner/karabiner-config.ts
@@ -12,6 +12,14 @@ export type Modifier =
   | 'option'
   | 'shift'
 
+export type SimultaneousOptions = {
+  detect_key_down_uninterruptedly?: boolean
+  key_down_order?: 'insensitive' | 'strict' | 'strict_inverse'
+  key_up_order?: 'insensitive' | 'strict' | 'strict_inverse'
+  key_up_when?: 'any' | 'all'
+  to_after_key_up?: ToEvent[]
+}
+
 /** @see https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/from/ */
 export type FromEvent = (
   | { key_code: FromKeyCode }
@@ -22,13 +30,7 @@ export type FromEvent = (
       /** @see https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/from/simultaneous/ */
       simultaneous: Array<{ key_code: string }>
       /** @see https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/from/simultaneous-options/ */
-      simultaneous_options?: {
-        detect_key_down_uninterruptedly?: boolean
-        key_down_order?: 'insensitive' | 'strict' | 'strict_inverse'
-        key_up_order?: 'insensitive' | 'strict' | 'strict_inverse'
-        key_up_when?: 'any' | 'all'
-        to_after_key_up?: ToEvent[]
-      }
+      simultaneous_options?: SimultaneousOptions
     }
 ) & {
   /** @see https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/from/modifiers/ */


Test patch:
diff --git a/src/config/from.test.ts b/src/config/from.test.ts
index c80e741..784b694 100644
--- a/src/config/from.test.ts
+++ b/src/config/from.test.ts
@@ -1,5 +1,5 @@
 import { expect, test } from 'vitest'
-import { map } from './from'
+import { map, mapSimultaneous } from './from'
 
 test('map()', () => {
   expect(map('/', '⌘⌥', '⌃').build().from).toEqual({
@@ -7,3 +7,22 @@ test('map()', () => {
     modifiers: { mandatory: ['command', 'option'], optional: ['control'] },
   })
 })
+
+test('mapSimultaneous()', () => {
+  const { from, parameters } = mapSimultaneous(
+    ['a', '←', 2],
+    { key_up_order: 'strict' },
+    123,
+  ).build()
+  expect(from).toEqual({
+    simultaneous: [
+      { key_code: 'a' },
+      { key_code: 'left_arrow' },
+      { key_code: '2' },
+    ],
+    simultaneous_options: { key_up_order: 'strict' },
+  })
+  expect(parameters).toEqual({
+    'basic.simultaneous_threshold_milliseconds': 123,
+  })
+})