Skip to content

Swapper и Tabber

Это специальные макросы для Alt+Tab, Gui+Tab, Ctrl+Tab, которые позволяют циклично переключать окна и вкладки.

Макросы предназначены для использования в слое.

При зажатии клавиши слоя и первичном нажатии на макрос, происходит зажатие Alt/Gui/Ctrl и однократное нажатие Tab. При повторном вызове макроса — нажимается лишь Tab.

При отжатии клавиши слоя модификаторы Alt/Gui/Ctrl отпускаются.

При этом, можно дополнительно зажать клавишу Shift, чтобы инвертировать направление переключения.

Реализация в QMK. Источник callum-oakley
c
#pragma once

#include QMK_KEYBOARD_H

// Implements cmd-tab like behaviour on a single key. On first tap of trigger
// cmdish is held and tabish is tapped -- cmdish then remains held until some
// other key is hit or released. For example:
//
//     trigger, trigger, a -> cmd down, tab, tab, cmd up, a
//     nav down, trigger, nav up -> nav down, cmd down, tab, cmd up, nav up
//
// This behaviour is useful for more than just cmd-tab, hence: cmdish, tabish.
void update_swapper(
    bool *active,
    uint16_t cmdish,
    uint16_t tabish,
    uint16_t trigger,
    uint16_t reverse_key,
    uint16_t keycode,
    keyrecord_t *record
);
c
#include "swapper.h"

void update_swapper(
    bool *active,
    uint16_t cmdish,
    uint16_t tabish,
    uint16_t trigger,
    uint16_t reverse_key,
    uint16_t keycode,
    keyrecord_t *record
) {
    if (keycode == trigger) {
        if (record->event.pressed) {
            if (!*active) {
                *active = true;
                register_code(cmdish);
            }
            register_code(tabish);
        } else {
            unregister_code(tabish);
        }
    } else if (*active
        && keycode != reverse_key
        && keycode != KC_LEFT
        && keycode != KC_RIGHT
    ) {
        unregister_code(cmdish);
        *active = false;
    }
}
c
enum keycodes {
    OS_SHFT = SAFE_RANGE,

    SW_ALT_TAB,  // Switch to next window (Windows) (alt-tab)
    SW_CMD_TAB,  // Switch to next window (macOS)   (cmd-tab)
    SW_CTRL_TAB, // Switch to next browser tab      (ctrl-tab)
};

bool sw_alt_tab_active = false;
bool sw_cmd_tab_active = false;
bool sw_ctrl_tab_active = false;

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    update_swapper(
        &sw_alt_tab_active, KC_LALT, KC_TAB, SW_ALT_TAB, OS_SHFT,
        keycode, record
    );
    update_swapper(
        &sw_cmd_tab_active, KC_LGUI, KC_TAB, SW_CMD_TAB, OS_SHFT,
        keycode, record
    );
    update_swapper(
        &sw_ctrl_tab_active, KC_LCTL, KC_TAB, SW_CTRL_TAB, OS_SHFT,
        keycode, record
    );
    return true
}
Реализация в ZMK
c
// Макрос предназначен для использования в слое, поэтому будет необходимо
// сбросить зажатые модификаторы LCTL, LGUI или LALT, например
// при отпускании слоя с помощью macro_release &kp LCTRL &kp LGUI &kp LALT
//
// Реализация этого дела остаётся за пользователем.

#define PARAM_1 0
#define PARAM_2 0

#define MACRO_TWO_PARAM(NAME, BINDINGS) MACRO(NAME, "zmk,behavior-macro-two-param", 2, BINDINGS)

#define MODMORPH(NAME, NORMAL, MORPHED, MODS, KEEP_MODS) \
    NAME: NAME { \
        compatible = "zmk,behavior-mod-morph"; \
        #binding-cells = <0>; \
        bindings = <NORMAL>, <MORPHED>; \
        mods = <(MODS)>; \
        keep-mods = <(KEEP_MODS)>; \
    };

/ {
    behaviors {
        MACRO_TWO_PARAM(
            m_hold_mod_press_key,
            &macro_press
                &macro_param_1to1 &kp PARAM_1
            &macro_tap
                &macro_param_2to1 &kp PARAM_2
        )

        MODMORPH(
            ctrl_tab,
            &m_hold_mod_press_key LCTRL TAB,
            &kp TAB,
            MOD_LCTL,
            MOD_LCTL
        )

        MODMORPH(
            cmd_tab,
            &m_hold_mod_press_key LGUI TAB,
            &kp TAB,
            MOD_LGUI,
            MOD_LGUI
        )

        MODMORPH(
            alt_tab,
            &m_hold_mod_press_key LALT TAB,
            &kp TAB,
            MOD_LALT,
            MOD_LALT
        )

    };
};