Duo-modifiers allow you to activate modifier keys (like Command, Option, Control, or Shift) by pressing two keys simultaneously instead of a single key. This approach is designed to mitigate the accidental triggers common with single-key home row mods.
Key considerations:
- Timing: Adjust the
basic.simultaneous_threshold_milliseconds setting to match your typing speed and habits to ensure modifiers trigger reliably. - Feedback: It is recommended to use notifications when modifiers are activated during the initial setup phase to verify the configuration is working as intended.
let rules = [
rule('duo-modifiers').manipulators(
duoModifiers({
'⌘': ['fd', 'jk'], // Command: triggered by f+d or j+k
'⌃': ['fs', 'jl'], // Control: triggered by f+s or j+l
'⌥': ['fa', 'j;'], // Option: triggered by f+a or j+;
'⇧': ['ds', 'kl'], // Shift
'⌘⇧': ['gd', 'hk'], // Cmd+Shift
'⌃⇧': ['gs', 'hl'], // Ctrl+Shift
'⌥⇧': ['ga', 'h;'], // Opt+Shift
'⌘⌥': ['vc', 'm,'], // Cmd+Opt
'⌘⌃': ['vx', 'm.'], // Cmd+Ctrl
'⌥⌃': ['cx', ',.'], // Opt+Ctrl
'⌘⌥⌃': ['vz', 'm/'], // Cmd+Opt+Ctrl
}),
),
]
function duoModifiers(
v: Partial<
Record<
'⌘' | '⌥' | '⌃' | '⇧' | MultiModifierAlias,
`${LetterKeyCode | KeyAlias}${LetterKeyCode | KeyAlias}`[]
>
>,
) {
let result = []
for (let [m, k] of Object.entries(v)) {
for (let keys of k) {
let id = k + m
let [firstMod, ...restMods] = (
m in modifierKeyAliases
? [modifierKeyAliases[m as ModifierKeyAlias]]
: multiModifierAliases[m as MultiModifierAlias]
) as Array<'command' | 'control' | 'option' | 'shift'>
let to_after_key_up = [toRemoveNotificationMessage(id)]
result.push(
mapSimultaneous(keys.split('') as (LetterKeyCode | KeyAlias)[], {
to_after_key_up,
})
.toNotificationMessage(id, m) // Must go first or to() doesn't work
.to(`left_${firstMod}`, restMods),
)
}
}
return result
}