Keyboard.io M01 and alt + tab

One thing I like about the UHK is that, by default, mod + d is an equivalent to alt + tab.

Figure 1: UHK window switching keys

Figure 1: UHK window switching keys

Moreover, it’s possible to keep mod key pressed, making it act just like alt + tab. It seems that the mod layer remembers the last sent modifier key and keep sending this modifier key as long as mod is being pressed.

Another way to see it is: let’s suppose mod + d is a simple shortcut to alt + tab. When releasing d, it would be equivalent to releasing alt and tab altogether. Since this is not what happens, something else is going on.

The way UHK behave is nice, since it lets us switch windows just like a regular alt + tab would do.

Switching windows with the M01

On the M01. There is no custom way to switching windows. You are expected to hit alt + tab, however, alt and tab are on different halves of the keyboard. Thus, the default way to switch windows on the M01 requires both hands, which is quite frustrating. ( ͡° ͜ʖ ͡°)

Figure 2: Default keybinding of the Keyboard.io Model 01

Figure 2: Default keybinding of the Keyboard.io Model 01

The naive way, Bind alt + tab to fn + d

One would try to map fn + d to alt + tab but this would not work. Actually the problem is already depicted in this thread here (along with a partial solution). In summary, mapping fn + d to alt + tab would act like a simple shortcut: In fn + d chord, releasing d key would be like releasing alt and tab altogether.

It’s complicated, let’s change the firmware

Let’s be honest, solving this issue is harder than it looks. One way to look at it is to imagine an abstract concept of transcient switching window session (basically a fancy term I came up with which represents the user inputing alt + tab + … + tab).

Figure 3: This is a transcient window switching session

Figure 3: This is a transcient window switching session

On the keyboard, we can try to represent a TWSS with these characteristics:

Table 1: Table of shortcuts
Key Bound to
fn + d alt + tab
fn + f
fn + e
fn + c
fn + s

The key bindings mentionned above are purely suggestions, they override default mouse control on the M01 since I don’t use this function. You may find useful to bind them differently.

We represent our TWSS session with this kaleidoscope plugin:

/** In charge of keeping alt pressed on during alt tab session
 * Alt tab session ends when stopping key release are detected */
class WindowsSwitcherTranscient : public kaleidoscope::Plugin {
public:
  enum State { NOT_SWITCHING, SWITCHING };

  const static int stopping_array_s = 2;
  Key stopping_keys[stopping_array_s] =
    { Key_Escape, ShiftToLayer(FUNCTION) };

  WindowsSwitcherTranscient() { };
  void activate() { alt_press_on(); }

  kaleidoscope::EventHandlerResult onKeyswitchEvent(Key &mapped_key, KeyAddr key_addr, uint8_t keyState) {

    if (state == NOT_SWITCHING)
      return kaleidoscope::EventHandlerResult::OK;

    for (int i = 0; i < stopping_array_s; i++) {
      Key k = stopping_keys[i];
      if (mapped_key == k && keyToggledOff(keyState)) {
        alt_press_off();
        break;
      }
    }

    return kaleidoscope::EventHandlerResult::OK;
  }
  kaleidoscope::EventHandlerResult beforeReportingState() {
    if (state == NOT_SWITCHING)
      return kaleidoscope::EventHandlerResult::OK;

    handleKeyswitchEvent(Key_LeftAlt, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED | INJECTED);
    return kaleidoscope::EventHandlerResult::OK;
  }
private:
  void alt_press_on() { state = SWITCHING; };
  void alt_press_off() { state = NOT_SWITCHING; };
  State state = NOT_SWITCHING;
} WindowsSwitcherTranscient;
Code Snippet 1: WindowsSwitcherTranscient plugin

A macro is defined which is bound to fn + d, it calls

static void windowSwitch(uint8_t keyState) {
  kaleidoscope::hid::pressKey(Key_Tab, keyToggledOn(keyState));
  WindowsSwitcherTranscient.activate();
}
Code Snippet 2: Macro enabling the alt + tab transcient mode

You can find a complete example firmware here with no dependencies on external plugin: complete example. Also, there is a third party plugin available here: https://github.com/Nimamoh/Kaleidoscope-TranscientWindowSwitchingState. The third party plugin is the more likely to be maintained

It is certainly not the best solution as I am sure we could find a nice usage of M01 layers to help us solve this problem but it get the job done without much hassle