diff --git a/astro.config.mjs b/astro.config.mjs index a8f7f59..85b0c46 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -22,6 +22,7 @@ export default defineConfig({ mdx(), sitemap({ filter: (page) => + !page.includes("blog/building-a-hyper-key-tree") && !page.includes("blog/debates-as-competitions") && !page.includes("blog/my-approach-to-code-review") && !page.includes( diff --git a/src/pages/blog/building-a-data-driven-hyper-key-tree.md b/src/pages/blog/building-a-data-driven-hyper-key-tree.md deleted file mode 100644 index 7c694bc..0000000 --- a/src/pages/blog/building-a-data-driven-hyper-key-tree.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -layout: ../../layouts/BlogPostLayout.astro -categories: - - productivity -date: -draft: true -tags: - - hammerspoon -title: Building a Data-Driven Hyper Key Tree ---- - -One of my favorite efficiency hacks is to remap my caps lock key to function as -escape when tapped and control when held down. - -## Prior Art - -I eventually learned about the concept of a hyper key, which is to create a -personal modifier key. - -We commonly use shift, control, alt, option, command, and the Windows key. - -To create shortcuts for functionality, we can combine modifiers with each other. - -However, this means that we can end up with unwiedly combinations that require -us to contort our fingers. It's like we're playing Twister with our hands. - -Even for the standard control key, it's typically in the corner of the keyboard, -requiring you to ulnarlly deviate your wrist to hit it. - -## Hyper Key Tree - -I was playing around with Hammerspoon. It lets you automate macOS with Lua. - -I realized that I can use ; as a hyper key. There's never a case where I want to -hold it down. - -However, I'm still disatisfied by the fact that there are only so many other -keys on the keyboard. I don't want to be restrainted by the number of keys. - -One option would be to implement combinations once I'm in hyper mode. But that -still requires finger contortions that get progressively harder. - -### Mechanics - -My solution was to have each key act as a node in a tree. When I tap, I activate -a configured action. When I hold it down, I descend into that key's tree. - -### Advantages - -There are several benefits to this approach. - -The first is that semi-colon is on the home row, and I don't have to move any of -my fingers to start it. Even caps lock requires the left pinky to ove. - -The other is that order is what is important now, not combination. I only have -to type the path to the action, but I don't have to hold down the entire path at -once. Once I enter a subtree, I can release the previous key(s), and Hammerspoon -will keep me at my current node. - -This also means that I have infinite depth to work with because I can repeat -keys, something that isn't possible with traditional key combinations. For -example, I can have a shortcut that is triggered by ; > i > e > i. - -If you really wanted to, you could even have every key work as the top of the -tree. I didn't do this because there are enough cases where I want to hold down -a key that I think it'd be more annoying than it's worth. For example, video -games requiring me to hold down certain keys. - -### Disadvantages - -## Implementation - -I didn't know if Hammerspoon would be enough, but I had prior experience from -using it to handle my caps lock hack. I used to use Karabiner Elements but was -able to drop it and just use Hammerspoon. - -## Key Logger - -## Analysis - -## Future Improvements - -I can get collect stats on how many keystrokes I've saved. - -I can set up a system to alert me when I type something instead of using the -corresponding shortcut. diff --git a/src/pages/blog/building-a-hyper-key-tree.md b/src/pages/blog/building-a-hyper-key-tree.md new file mode 100644 index 0000000..db32ed5 --- /dev/null +++ b/src/pages/blog/building-a-hyper-key-tree.md @@ -0,0 +1,131 @@ +--- +layout: ../../layouts/BlogPostLayout.astro +categories: + - productivity +date: "2023-10-29" +unlisted: true +tags: + - hammerspoon +title: Building a Hyper Key Tree +--- + +One of my favorite efficiency hacks is to [remap my caps lock key](https://www.dannyguo.com/blog/remap-caps-lock-to-escape-and-control) to function as +escape when tapped and control when held down. I don't remember where I learned +that tip, but ever since then, I've been interested in using my keyboard more +efficiently than just using standard keyboard shortcuts. + +I later learned about the concept of a [hyper +key](https://docs.folivora.ai/docs/1004_hyper_key.html), which is a personal +modifier key. This allows you create your own shortcuts that are basically +guaranteed to not collide with any other shortcuts. A typical implementation +involves activating a hyper mode by simulating pressing all the modifiers (e.g. +`shift + control + option + command` on Macs) simultaneously. So you would make +one key serve as `hyper`, and then you can define an action for `hyper + s`, for +example. + +A few years ago, I thought of pushing this idea further by building a hyper key +tree that gives me unlimited keyboard shortcuts based on *sequences rather than +combinations* of keys. + +## Hyper Key Tree + +I use [Hammerspoon](https://www.hammerspoon.org/) to [automate various aspects +of my +Mac](https://github.com/dguo/dotfiles/blob/main/programs/hammerspoon/init.lua) +with [Lua](https://www.lua.org/about.html) scripts. And that's what I used to +[implement my +idea](https://github.com/dguo/dotfiles/blob/c7906074d196b6840ddac3585e7e912f1a5de53a/programs/hammerspoon/init.lua#L17). + +I configured an entire +[tree](https://en.wikipedia.org/wiki/Tree_(data_structure)) of keys. Each node, +which corresponds to a key, can do up to three things: + +1. If I tap it, I trigger a configured action. +2. If I hold it, and it's a leaf node that doesn't have any children, then the + configured action repeats. +3. If I hold it, and it does have children, then I descend into that node's + subtree. + +I chose semicolon (`;`) to serve as my root node. That's because a finger (my right +pinky) rests on it by default, and there's never a case where I want to hold +semicolon down to type it repeatedly. + +There are many nodes under semicolon. One node is `f`, and I configured it to +switch window focus to Firefox or open it if necessary. So by holding `;` and +then tapping `f`, it takes me just two keystrokes to switch. Another node is +`i`, which does the same thing but for iTerm. + +However, if I hold `i` instead of tapping it, I descend into `i`'s subtree. I +think of `i` as representing "insert" in this mode, and the idea is to type out +commonly used strings for me. For example, one node is `e` (for "email"), so if +I tap `e` at this point, the program will type out my personal email. That's +three keystrokes to type my email: `; -> i -> e`. If I want to type my work +email, it's the same sequence except with a `w` (for "work") at the end. + +## Standard Keyboard Shortcuts + +The standard approach to keyboard shortcuts is to use combinations of modifier +keys. For example, `command + w` closes a browser tab, but `command + shift + w` +closes the entire window. However, this means that we can end up with unwiedly +combinations that require us to contort our fingers. It's like we're playing +[Twister](https://en.wikipedia.org/wiki/Twister_(game)) with our hands. + +We also run into the problem of conflicting shortcuts. There are only so many +possible combinations that are reasonable, given the Twister problem. If we want +to define our own shortcuts, we have to be careful not to conflict with shortcuts +that our operating system or program already define. + +Furthermore, the modifier keys are less accessible. The control key is typically +at or near the corner of the keyboard, requiring [ulnar +deviation](https://www.crossfitinvictus.com/blog/simple-solutions-for-poor-wrist-mobility/) +to press. + +## Hyper Key Tree Advantages + +The sequence of keys is the critical aspect of the hyper key tree. It cares +about order, not combination. This comes with two advantages. + +The first is that I only have to type the path to the action. I don't have to +hold down the entire path at once. Once I enter a subtree, I can release the +previous key(s), and the program will keep me at my current node. For example, +to type my email, once I hold down `i`, I can let go of `;`! The program keeps +track of where I am in the tree, so the previous nodes become irrelevant. +Shortcuts become more like normal typing. + +The other advantage is that I have infinite depth to work with because I can +repeat keys in a sequence, something that isn't possible with standard key +combinations. For example, I can have an action that is triggered by `; -> i +-> e -> i`. + +I could even have every key work as a root node. But I didn't do this because +there are enough cases where I want to hold down a key that I think it'd be more +annoying than it's worth. For example, video games might require me to hold down +certain keys. + +## Experience + +The hyper key tree was an experiment to start, but I've been happily using it +for the past few years. I was concerned it would be hard to remember the +sequences, but that concern is true for standard shortcuts as well. In practice, +muscle memory took over quickly, and I stopped having to actively think to +execute my shortcuts. + +I use my tree to switch between programs, manage windows, type text, and +simulate arrow keys (i.e. `; -> h,j,k,l` replaces left, down, up, and right). +And with the power that comes with Hammerspoon, there are many more things that I +could create shortcuts for. + +I also separated logic from data. Hammerspoon powers the program, but I +configure the tree itself through a JSON file that I sync across machines with +Google Drive. + +## Future Improvements + +After implementing the tree itself, I built in a +[keylogger](https://en.wikipedia.org/wiki/Keystroke_logging). So the program +saves my keystrokes to a text file, and I plan to analyze this file to get +data-driven ideas for future shortcuts. + +I would also like to set up a system to alert me when I type or do something +without using a corresponding shortcut. This would train me to consistently use +all my shortcuts.