Saturday, November 28, 2020

Remapping keys

Keyboards are more complicated than they first appear.

For example, suppose I want to map Shift + A to =.

I press Shift. A Shift keycode should be generated (the mapping isn't triggered yet). I press A. Now:

  • The A keycode should not be generated—the mapping consumes it.
  • The = keycode should be generated, because the mapping produced it.

But wait—there's another step. Shift is still down, and Shift + = gives a '+' sign. So before the = keycode is generated, the Shift needs to be released.

Now I release the A key. The = keycode should be released. But the Shift (physical key) is still down. Should the Shift keycode be reinstated now that it's no longer consumed by the mapping?

No, that's (for some reason) not how keyboards behave. Only pressing a key can cause a new keycode to be pressed, even where key combinations are used.

Try it with your Fn key: Hold down Fn, then press F1, then release Fn. This does not trigger an F1 keycode.

After puzzling over this logic for awhile, I eventually created a tool that let's you remap keys using rules like the following:

[
  { "from": [ "CAPSLOCK" ], "to": [] },
  { "from": [ "CAPSLOCK", "J" ], "to": [ "LEFT" ] },
  { "from": [ "CAPSLOCK", "I" ], "to": [ "UP" ] },
  { "from": [ "CAPSLOCK", "K" ], "to": [ "DOWN" ] },
  { "from": [ "CAPSLOCK", "L" ], "to": [ "RIGHT" ] },
  { "from": [ "CAPSLOCK", "H" ], "to": [ "HOME" ] },
  { "from": [ "CAPSLOCK", "SEMICOLON" ], "to": [ "END" ] },
  { "from": [ "CAPSLOCK", "U" ], "to": [ "PAGEUP" ] },
  { "from": [ "CAPSLOCK", "M" ], "to": [ "PAGEDOWN" ] },
  { "from": [ "CAPSLOCK", "N" ], "to": [ "LEFTCTRL", "LEFT" ] },
  { "from": [ "CAPSLOCK", "COMMA" ], "to": [ "LEFTCTRL", "RIGHT" ] }
]

Don't you wish any key could be a modifier? Now it can.

No comments:

Post a Comment