Refactor keymap remaps into a declarative rules table
Replace the per-keycode switch statement in process_record_user with a remap_rule_t table evaluated first-match-wins. Each rule specifies os_mask, app_mask, mods_from, key_from, mods_to, key_to. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,44 +14,104 @@ enum custom_keycodes {
|
|||||||
CK_NOREMAP, // hold to bypass all remaps
|
CK_NOREMAP, // hold to bypass all remaps
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Remap rules engine -------------------------------------------------
|
||||||
|
//
|
||||||
|
// Each rule defines a single key remap: when the trigger key is pressed with
|
||||||
|
// exactly the specified modifiers, on a matching OS and focused app, the
|
||||||
|
// modifiers are swapped and (optionally) the keycode is changed.
|
||||||
|
//
|
||||||
|
// Rules are evaluated in order; the first match wins.
|
||||||
|
|
||||||
|
// OS match bitmasks
|
||||||
|
#define OS_ANY 0xFF
|
||||||
|
#define OS_LINUX (1 << OS_MODE_LINUX)
|
||||||
|
#define OS_MAC (1 << OS_MODE_MAC)
|
||||||
|
#define OS_WIN (1 << OS_MODE_WINDOWS)
|
||||||
|
|
||||||
|
// App match bitmasks
|
||||||
|
#define APP_ANY 0xFF
|
||||||
|
#define APP(a) (1 << (a))
|
||||||
|
#define APP_NOT(a) (APP_ANY & ~APP(a))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t from;
|
uint8_t os_mask; // bitmask of OS modes that match
|
||||||
uint8_t to;
|
uint8_t app_mask; // bitmask of focused apps that match
|
||||||
} mod_rewrite_t;
|
uint8_t mods_from; // required modifiers (exact match after normalization)
|
||||||
|
uint16_t key_from; // trigger keycode
|
||||||
|
uint8_t mods_to; // replacement modifiers
|
||||||
|
uint16_t key_to; // output keycode (0 = same as trigger key)
|
||||||
|
} remap_rule_t;
|
||||||
|
|
||||||
static const mod_rewrite_t CTRL_TO_SUPER = { MOD_MASK_CTRL, MOD_MASK_GUI };
|
static const remap_rule_t remap_rules[] = {
|
||||||
static const mod_rewrite_t CTRL_SHIFT_TO_SUPER = { MOD_MASK_CTRL | MOD_MASK_SHIFT, MOD_MASK_GUI };
|
// --- Copy/paste (Mac) ---
|
||||||
static const mod_rewrite_t CTRL_SHIFT_TO_CMD_SHIFT = { MOD_MASK_CTRL | MOD_MASK_SHIFT, MOD_MASK_GUI | MOD_MASK_SHIFT };
|
// Ctrl+Shift+C/V -> Cmd+C/V (terminal copy/paste — Ctrl+Shift is the trigger in terminals)
|
||||||
static const mod_rewrite_t CTRL_ALT_TO_CTRL = { MOD_MASK_CTRL | MOD_MASK_ALT, MOD_MASK_CTRL };
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_C, MOD_MASK_GUI, 0 },
|
||||||
static const mod_rewrite_t CTRL_TO_ALT = { MOD_MASK_CTRL, MOD_MASK_ALT };
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_V, MOD_MASK_GUI, 0 },
|
||||||
static const mod_rewrite_t ALT_TO_SUPER = { MOD_MASK_ALT, MOD_MASK_GUI };
|
// Ctrl+C/V -> Cmd+C/V (not in terminal — let Ctrl+C = SIGINT through)
|
||||||
static const mod_rewrite_t SUPER_TO_SUPER = { MOD_MASK_GUI, MOD_MASK_GUI };
|
{ OS_MAC, APP_NOT(APP_TERMINAL), MOD_MASK_CTRL, KC_C, MOD_MASK_GUI, 0 },
|
||||||
static const mod_rewrite_t SUPER_TO_CTRL = { MOD_MASK_GUI, MOD_MASK_CTRL };
|
{ OS_MAC, APP_NOT(APP_TERMINAL), MOD_MASK_CTRL, KC_V, MOD_MASK_GUI, 0 },
|
||||||
static const mod_rewrite_t NONE_TO_SUPER = { 0, MOD_MASK_GUI };
|
|
||||||
static const mod_rewrite_t NONE_TO_CTRL = { 0, MOD_MASK_CTRL };
|
|
||||||
|
|
||||||
|
// --- Common Ctrl -> Cmd shortcuts (Mac) ---
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_X, MOD_MASK_GUI, 0 }, // cut
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_A, MOD_MASK_GUI, 0 }, // select all
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_S, MOD_MASK_GUI, 0 }, // save
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_F, MOD_MASK_GUI, 0 }, // find
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_F, MOD_MASK_GUI | MOD_MASK_SHIFT, 0 }, // find in files
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_W, MOD_MASK_GUI, 0 }, // close tab
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_L, MOD_MASK_GUI, 0 }, // address bar
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_R, MOD_MASK_GUI, 0 }, // reload
|
||||||
|
|
||||||
|
// --- Undo/redo family: Ctrl -> Cmd, Ctrl+Shift -> Cmd+Shift (Mac) ---
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_Z, MOD_MASK_GUI, 0 }, // undo
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_Z, MOD_MASK_GUI | MOD_MASK_SHIFT, 0 }, // redo
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_T, MOD_MASK_GUI, 0 }, // new tab
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_T, MOD_MASK_GUI | MOD_MASK_SHIFT, 0 }, // reopen tab
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_N, MOD_MASK_GUI, 0 }, // new window
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_N, MOD_MASK_GUI | MOD_MASK_SHIFT, 0 }, // incognito
|
||||||
|
|
||||||
|
// --- Arrow key modifier rewrites (Mac) ---
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_ALT, KC_LEFT, MOD_MASK_CTRL, 0 }, // switch workspace
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_LEFT, MOD_MASK_ALT, 0 }, // word left
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_ALT, KC_RGHT, MOD_MASK_CTRL, 0 }, // switch workspace
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_RGHT, MOD_MASK_ALT, 0 }, // word right
|
||||||
|
|
||||||
|
// --- Delete word (Mac) ---
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_BSPC, MOD_MASK_ALT, 0 },
|
||||||
|
|
||||||
|
// --- Home/End (Mac) ---
|
||||||
|
// Terminal: Home -> Ctrl+A, End -> Ctrl+E (must be listed before the general rules)
|
||||||
|
{ OS_MAC, APP(APP_TERMINAL), 0, KC_HOME, MOD_MASK_CTRL, KC_A },
|
||||||
|
{ OS_MAC, APP(APP_TERMINAL), 0, KC_END, MOD_MASK_CTRL, KC_E },
|
||||||
|
// General: Home -> Cmd+Left, End -> Cmd+Right
|
||||||
|
{ OS_MAC, APP_ANY, 0, KC_HOME, MOD_MASK_GUI, KC_LEFT },
|
||||||
|
{ OS_MAC, APP_ANY, 0, KC_END, MOD_MASK_GUI, KC_RGHT },
|
||||||
|
|
||||||
|
// --- Alt+F4 -> Cmd+Q (Mac) ---
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_ALT, KC_F4, MOD_MASK_GUI, KC_Q },
|
||||||
|
|
||||||
|
// --- Alt+Tab -> Cmd+Tab (Mac) ---
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_ALT, KC_TAB, MOD_MASK_GUI, 0 },
|
||||||
|
|
||||||
|
// --- Workspace overview (all OS) ---
|
||||||
|
{ OS_MAC, APP_ANY, MOD_MASK_GUI, KC_UP, MOD_MASK_CTRL, 0 }, // Mission Control
|
||||||
|
{ OS_LINUX, APP_ANY, MOD_MASK_GUI, KC_UP, MOD_MASK_GUI, KC_W }, // KDE overview
|
||||||
|
{ OS_WIN, APP_ANY, MOD_MASK_GUI, KC_UP, MOD_MASK_GUI, KC_TAB }, // Task View
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Modifier normalization ----------------------------------------------
|
||||||
// Collapse left/right mods into modifier types for comparison.
|
// Collapse left/right mods into modifier types for comparison.
|
||||||
// e.g. either LCTL (0x01) or RCTL (0x10) both become 0x01.
|
// e.g. either LCTL (0x01) or RCTL (0x10) both become 0x01.
|
||||||
static uint8_t normalize_mods(uint8_t mods) {
|
static uint8_t normalize_mods(uint8_t mods) {
|
||||||
return (mods | (mods >> 4)) & 0x0F;
|
return (mods | (mods >> 4)) & 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if current mods exactly match a rule's `from` mods.
|
// --- Active rewrite tracking (hold-to-repeat support) --------------------
|
||||||
static bool mods_match(uint8_t mods, mod_rewrite_t rule) {
|
|
||||||
return normalize_mods(mods) == normalize_mods(rule.from);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Active rewrite tracking for hold-to-repeat support.
|
|
||||||
//
|
//
|
||||||
// The old tap_code() approach sent an immediate press+release, so holding
|
// register_code() keeps the key held for auto-repeat. This struct tracks the
|
||||||
// e.g. Ctrl+Left (remapped to Alt+Left on Mac) produced a single word-jump
|
// state needed to clean up correctly on release. Only one rewrite can be
|
||||||
// instead of repeating. Now rewrite_mods()/rewrite_mods_and_key() use
|
// active at a time (only one key auto-repeats).
|
||||||
// register_code() to keep the key held, and this struct tracks the state
|
|
||||||
// needed to clean up correctly on release.
|
|
||||||
//
|
|
||||||
// Only one rewrite can be active at a time (only one key auto-repeats).
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t trigger_keycode; // physical key (e.g. KC_LEFT) — 0 when inactive
|
uint16_t trigger_keycode; // physical key (e.g. KC_LEFT) -- 0 when inactive
|
||||||
uint8_t output_keycode; // key registered with host (may differ from trigger)
|
uint8_t output_keycode; // key registered with host (may differ from trigger)
|
||||||
uint8_t from_mods; // normalized mods that were removed
|
uint8_t from_mods; // normalized mods that were removed
|
||||||
uint8_t to_mods; // normalized mods that were added
|
uint8_t to_mods; // normalized mods that were added
|
||||||
@@ -62,10 +122,6 @@ typedef struct {
|
|||||||
static active_rewrite_t active_rw = {0};
|
static active_rewrite_t active_rw = {0};
|
||||||
|
|
||||||
// Undo an active rewrite: restore saved modifiers and unregister the held key.
|
// Undo an active rewrite: restore saved modifiers and unregister the held key.
|
||||||
// saved_mods starts as the exact get_mods() at press time, but is updated as
|
|
||||||
// individual from-mods are released during the hold, so it always reflects
|
|
||||||
// what should actually be active after teardown. No phantom mods.
|
|
||||||
// Mods are restored before unregister_code so only one USB report is sent.
|
|
||||||
static void teardown_active_rewrite(void) {
|
static void teardown_active_rewrite(void) {
|
||||||
if (!active_rw.trigger_keycode) return;
|
if (!active_rw.trigger_keycode) return;
|
||||||
set_mods(active_rw.saved_mods);
|
set_mods(active_rw.saved_mods);
|
||||||
@@ -73,14 +129,9 @@ static void teardown_active_rewrite(void) {
|
|||||||
active_rw.trigger_keycode = 0;
|
active_rw.trigger_keycode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intercept release events for active rewrites. Called at the top of
|
// Intercept release events for active rewrites.
|
||||||
// process_record_user (after OS_MODE_NONE/no_remap bail-outs).
|
// 1. Rewritten key released -> clean up via teardown.
|
||||||
//
|
// 2. Original modifier released while key held -> remove from saved_mods.
|
||||||
// Handles two cases:
|
|
||||||
// 1. The rewritten key itself is released — clean up via teardown_active_rewrite().
|
|
||||||
// 2. The original modifier is released while the key is still held —
|
|
||||||
// remove it from saved_mods so teardown won't restore a phantom modifier.
|
|
||||||
//
|
|
||||||
// Returns false to consume the event, true to continue normal processing.
|
// Returns false to consume the event, true to continue normal processing.
|
||||||
static bool process_rewrite_release(uint16_t keycode, keyrecord_t *record) {
|
static bool process_rewrite_release(uint16_t keycode, keyrecord_t *record) {
|
||||||
if (!active_rw.trigger_keycode) return true;
|
if (!active_rw.trigger_keycode) return true;
|
||||||
@@ -98,59 +149,38 @@ static bool process_rewrite_release(uint16_t keycode, keyrecord_t *record) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite modifier combos: swap exact `from` mods to `to` mods and hold keycode.
|
// Apply a rewrite unconditionally (matching already done by caller).
|
||||||
// Left/right variants of the same modifier are treated as equivalent.
|
static void apply_rewrite(uint16_t trigger_keycode, uint8_t mods_from, uint8_t mods_to, uint16_t key_out) {
|
||||||
//
|
|
||||||
// Uses register_code() instead of tap_code() so the key stays held for
|
|
||||||
// auto-repeat. The key is unregistered later by process_rewrite_release()
|
|
||||||
// when the physical key is released. If another rewrite is already active,
|
|
||||||
// it is cleaned up first (only one key can auto-repeat at a time).
|
|
||||||
//
|
|
||||||
// Returns true if a rewrite was applied (caller should return false to
|
|
||||||
// suppress the original keycode).
|
|
||||||
static bool rewrite_mods(uint16_t keycode, mod_rewrite_t rule) {
|
|
||||||
uint8_t mods = get_mods();
|
uint8_t mods = get_mods();
|
||||||
if (mods_match(mods, rule)) {
|
|
||||||
if (active_rw.trigger_keycode) teardown_active_rewrite();
|
|
||||||
active_rw = (active_rewrite_t){
|
|
||||||
.trigger_keycode = keycode,
|
|
||||||
.output_keycode = keycode,
|
|
||||||
.from_mods = normalize_mods(rule.from),
|
|
||||||
.to_mods = normalize_mods(rule.to),
|
|
||||||
.saved_mods = mods,
|
|
||||||
|
|
||||||
};
|
|
||||||
set_mods(active_rw.to_mods);
|
|
||||||
register_code(keycode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like rewrite_mods(), but also changes the keycode sent to the host.
|
|
||||||
// trigger_keycode is the physical key pressed (used to match the release
|
|
||||||
// event later), while keycode_out is what the host actually receives.
|
|
||||||
// e.g. Home (trigger) -> Cmd+Left (output): trigger_keycode=KC_HOME,
|
|
||||||
// keycode_out=KC_LEFT, rule=NONE_TO_SUPER.
|
|
||||||
static bool rewrite_mods_and_key(uint16_t trigger_keycode, mod_rewrite_t rule, uint16_t keycode_out) {
|
|
||||||
uint8_t mods = get_mods();
|
|
||||||
if (mods_match(mods, rule)) {
|
|
||||||
if (active_rw.trigger_keycode) teardown_active_rewrite();
|
if (active_rw.trigger_keycode) teardown_active_rewrite();
|
||||||
active_rw = (active_rewrite_t){
|
active_rw = (active_rewrite_t){
|
||||||
.trigger_keycode = trigger_keycode,
|
.trigger_keycode = trigger_keycode,
|
||||||
.output_keycode = keycode_out,
|
.output_keycode = key_out,
|
||||||
.from_mods = normalize_mods(rule.from),
|
.from_mods = normalize_mods(mods_from),
|
||||||
.to_mods = normalize_mods(rule.to),
|
.to_mods = normalize_mods(mods_to),
|
||||||
.saved_mods = mods,
|
.saved_mods = mods,
|
||||||
|
|
||||||
};
|
};
|
||||||
set_mods(active_rw.to_mods);
|
set_mods(active_rw.to_mods);
|
||||||
register_code(keycode_out);
|
register_code(key_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk the rule table; first matching rule wins.
|
||||||
|
static bool apply_remap_rules(uint16_t keycode) {
|
||||||
|
uint8_t norm = normalize_mods(get_mods());
|
||||||
|
for (uint8_t i = 0; i < sizeof(remap_rules) / sizeof(remap_rules[0]); i++) {
|
||||||
|
const remap_rule_t *r = &remap_rules[i];
|
||||||
|
if (r->key_from != keycode) continue;
|
||||||
|
if (!((1 << os_mode) & r->os_mask)) continue;
|
||||||
|
if (!((1 << focused_app) & r->app_mask)) continue;
|
||||||
|
if (norm != normalize_mods(r->mods_from)) continue;
|
||||||
|
apply_rewrite(keycode, r->mods_from, r->mods_to, r->key_to ? r->key_to : keycode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Keymaps -------------------------------------------------------------
|
||||||
|
|
||||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
|
||||||
/* Layer 0, default layer
|
/* Layer 0, default layer
|
||||||
@@ -259,8 +289,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cycle RGB animation (FN+Backspace)
|
// Cycle RGB animation (FN+Backspace)
|
||||||
// Must update layer_rgb for all layers because system76_ec_rgb_layer()
|
|
||||||
// resets rgb_matrix_config from layer_rgb on every layer change.
|
|
||||||
if (keycode == CK_RGBMOD) {
|
if (keycode == CK_RGBMOD) {
|
||||||
if (record->event.pressed) {
|
if (record->event.pressed) {
|
||||||
uint8_t mode = layer_rgb[0].mode + 1;
|
uint8_t mode = layer_rgb[0].mode + 1;
|
||||||
@@ -290,130 +318,26 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
|||||||
super_tapped = false;
|
super_tapped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (keycode) {
|
// Mac: tap Super -> Cmd+Space (Spotlight)
|
||||||
// Mac mode: tap Super -> Cmd+Space (Spotlight)
|
if (keycode == KC_LGUI && os_mode == OS_MODE_MAC) {
|
||||||
// Linux/Windows: tap Super passes through normally (KDE app menu)
|
|
||||||
case KC_LGUI:
|
|
||||||
if (os_mode == OS_MODE_MAC) {
|
|
||||||
if (record->event.pressed) {
|
if (record->event.pressed) {
|
||||||
super_tapped = true;
|
super_tapped = true;
|
||||||
register_mods(MOD_BIT(KC_LGUI));
|
register_mods(MOD_BIT(KC_LGUI));
|
||||||
} else {
|
} else {
|
||||||
if (super_tapped) {
|
if (super_tapped) {
|
||||||
tap_code(KC_SPC); // GUI still held, sends Super+Space
|
tap_code(KC_SPC);
|
||||||
super_tapped = false;
|
super_tapped = false;
|
||||||
}
|
}
|
||||||
unregister_mods(MOD_BIT(KC_LGUI));
|
unregister_mods(MOD_BIT(KC_LGUI));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
// Apply remap rules on key press
|
||||||
// Ctrl+C/V -> Super+C/V (copy/paste)
|
|
||||||
// Ctrl+Shift+C/V -> Super+C/V (terminal copy/paste)
|
|
||||||
case KC_C:
|
|
||||||
case KC_V:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
if (rewrite_mods(keycode, CTRL_SHIFT_TO_SUPER)) return false;
|
|
||||||
// Terminal: plain Ctrl+C/V passes through (SIGINT, etc.)
|
|
||||||
if (focused_app != APP_TERMINAL) {
|
|
||||||
if (rewrite_mods(keycode, CTRL_TO_SUPER)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
|
||||||
// Ctrl+X/A/S/F -> Super+X/A/S/F (cut, select all, save, find)
|
|
||||||
// Ctrl+W/L/R -> Super+W/L/R (close tab, address bar, reload)
|
|
||||||
case KC_X:
|
|
||||||
case KC_A:
|
|
||||||
case KC_S:
|
|
||||||
case KC_F:
|
|
||||||
case KC_W:
|
|
||||||
case KC_L:
|
|
||||||
case KC_R:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
if (rewrite_mods(keycode, CTRL_TO_SUPER)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
|
||||||
// Ctrl+Z/T/N -> Super+Z/T/N (undo, new tab, new window)
|
|
||||||
// Ctrl+Shift+Z/T/N -> Super+Shift+Z/T/N (redo, reopen tab, incognito)
|
|
||||||
case KC_Z:
|
|
||||||
case KC_T:
|
|
||||||
case KC_N:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
if (rewrite_mods(keycode, CTRL_TO_SUPER)) return false;
|
|
||||||
if (rewrite_mods(keycode, CTRL_SHIFT_TO_CMD_SHIFT)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
|
||||||
// Ctrl+Alt+Left/Right -> Ctrl+Left/Right (switch workspace)
|
|
||||||
// Ctrl+Left/Right -> Alt+Left/Right (word navigation)
|
|
||||||
case KC_LEFT:
|
|
||||||
case KC_RGHT:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
if (rewrite_mods(keycode, CTRL_ALT_TO_CTRL)) return false;
|
|
||||||
if (rewrite_mods(keycode, CTRL_TO_ALT)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
|
||||||
// Ctrl+Backspace -> Alt+Backspace (delete word backward)
|
|
||||||
case KC_BSPC:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
if (rewrite_mods(keycode, CTRL_TO_ALT)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
|
||||||
// Home -> Super+Left (line start)
|
|
||||||
// End -> Super+Right (line end)
|
|
||||||
case KC_HOME:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
// Terminal: Home -> Ctrl+A (line start)
|
|
||||||
if (focused_app == APP_TERMINAL) {
|
|
||||||
if (rewrite_mods_and_key(keycode, NONE_TO_CTRL, KC_A)) return false;
|
|
||||||
}
|
|
||||||
if (rewrite_mods_and_key(keycode, NONE_TO_SUPER, KC_LEFT)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KC_END:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
// Terminal: End -> Ctrl+E (line end)
|
|
||||||
if (focused_app == APP_TERMINAL) {
|
|
||||||
if (rewrite_mods_and_key(keycode, NONE_TO_CTRL, KC_E)) return false;
|
|
||||||
}
|
|
||||||
if (rewrite_mods_and_key(keycode, NONE_TO_SUPER, KC_RGHT)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
|
||||||
// Alt+F4 -> Super+Q (quit app)
|
|
||||||
case KC_F4:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
if (rewrite_mods_and_key(keycode, ALT_TO_SUPER, KC_Q)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Mac mode rewrites:
|
|
||||||
// Alt+Tab -> Super+Tab (app switcher)
|
|
||||||
case KC_TAB:
|
|
||||||
if (os_mode == OS_MODE_MAC && record->event.pressed) {
|
|
||||||
if (rewrite_mods(keycode, ALT_TO_SUPER)) return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Workspace overview:
|
|
||||||
// Super+Up -> Super+W (KDE overview, linux)
|
|
||||||
// Super+Up -> Ctrl+Up (Mission Control, mac)
|
|
||||||
// Super+Up -> Super+Tab (Task View, windows)
|
|
||||||
case KC_UP:
|
|
||||||
if (record->event.pressed) {
|
if (record->event.pressed) {
|
||||||
if (os_mode == OS_MODE_MAC) {
|
if (apply_remap_rules(keycode)) return false;
|
||||||
if (rewrite_mods(keycode, SUPER_TO_CTRL)) return false;
|
|
||||||
} else if (os_mode == OS_MODE_LINUX) {
|
|
||||||
if (rewrite_mods_and_key(keycode, SUPER_TO_SUPER, KC_W)) return false;
|
|
||||||
} else if (os_mode == OS_MODE_WINDOWS) {
|
|
||||||
if (rewrite_mods_and_key(keycode, SUPER_TO_SUPER, KC_TAB)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,4 +345,3 @@ void matrix_init_user(void) {
|
|||||||
// Force dynamic keymap reset so PROGMEM keymaps always take effect
|
// Force dynamic keymap reset so PROGMEM keymaps always take effect
|
||||||
dynamic_keymap_reset();
|
dynamic_keymap_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user