Add new remap rules: Ctrl+D, Ctrl(+Shift)+P with Xcode-specific

bindings, Ctrl+Shift word selection, and Ctrl-as-Cmd for mouse
clicks in Xcode/VSCode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 19:00:32 -07:00
parent 0e370b1abd
commit 061baa1cf0

View File

@@ -33,6 +33,9 @@ enum custom_keycodes {
#define APP(a) (1 << (a))
#define APP_NOT(a) (APP_ANY & ~APP(a))
// Rule flags
#define RULE_CANCEL_ON_KEYPRESS (1 << 0) // teardown rewrite if any other key is pressed
typedef struct {
uint8_t os_mask; // bitmask of OS modes that match
uint8_t app_mask; // bitmask of focused apps that match
@@ -40,28 +43,50 @@ typedef struct {
uint16_t key_from; // trigger keycode
uint8_t mods_to; // replacement modifiers
uint16_t key_to; // output keycode (0 = same as trigger key)
uint8_t flags; // RULE_* flags (0 for most rules via partial init)
} remap_rule_t;
static const remap_rule_t remap_rules[] = {
// --- Copy/paste (Mac) ---
// Ctrl+Shift+C/V -> Cmd+C/V (terminal copy/paste — Ctrl+Shift is the trigger in terminals)
// --- Ctrl -> Cmd for mouse clicks (Xcode/VSCode on Mac) ---
// Registers Cmd while Ctrl is held alone; any keyboard key cancels it.
// Enables Cmd+click (jump to symbol) via the Ctrl key.
{ OS_MAC, APP(APP_XCODE) | APP(APP_VSCODE), 0, KC_LCTL, 0, KC_LGUI, RULE_CANCEL_ON_KEYPRESS },
{ OS_MAC, APP(APP_XCODE) | APP(APP_VSCODE), 0, KC_RCTL, 0, KC_LGUI, RULE_CANCEL_ON_KEYPRESS },
// --- Text editing (Mac) ---
// Ctrl+Shift+C/V -> copy/paste (Cmd on Mac, Ctrl on Linux/Windows)
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_C, MOD_MASK_GUI, 0 },
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_V, MOD_MASK_GUI, 0 },
// Ctrl+C/V -> Cmd+C/V (not in terminal — let Ctrl+C = SIGINT through)
{ OS_MAC, APP_NOT(APP_TERMINAL), MOD_MASK_CTRL, KC_C, MOD_MASK_GUI, 0 },
{ OS_MAC, APP_NOT(APP_TERMINAL), MOD_MASK_CTRL, KC_V, MOD_MASK_GUI, 0 },
// --- 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_NOT(APP_TERMINAL), MOD_MASK_CTRL, KC_D, MOD_MASK_GUI, 0 }, // bookmark / select next occurrence
{ 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
// Word navigation: Ctrl(+Shift)+Left/Right -> Alt(+Shift)+Left/Right
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_LEFT, MOD_MASK_ALT | MOD_MASK_SHIFT, 0 }, // select word left
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_RGHT, MOD_MASK_ALT | MOD_MASK_SHIFT, 0 }, // select word right
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_LEFT, MOD_MASK_ALT, 0 }, // word left
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_RGHT, MOD_MASK_ALT, 0 }, // word right
// Delete word: Ctrl+Backspace -> Alt+Backspace
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_BSPC, MOD_MASK_ALT, 0 },
// Home/End: terminal -> Ctrl+A/E, general -> Cmd+Left/Right
{ 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 },
{ OS_MAC, APP_ANY, 0, KC_HOME, MOD_MASK_GUI, KC_LEFT },
{ OS_MAC, APP_ANY, 0, KC_END, MOD_MASK_GUI, KC_RGHT },
// --- Common Ctrl -> Cmd shortcuts (Mac) ---
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_S, MOD_MASK_GUI, 0 }, // save
{ 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(APP_XCODE), MOD_MASK_CTRL, KC_P, MOD_MASK_GUI | MOD_MASK_SHIFT, KC_O }, // Xcode: Open Quickly
{ OS_MAC, APP_ANY, MOD_MASK_CTRL, KC_P, MOD_MASK_GUI, 0 }, // print / quick open
{ OS_MAC, APP(APP_XCODE), MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_P, MOD_MASK_GUI | MOD_MASK_SHIFT, KC_A }, // Xcode: Quick Actions
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_SHIFT, KC_P, MOD_MASK_GUI | MOD_MASK_SHIFT, 0 }, // command palette
{ 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
@@ -69,22 +94,9 @@ static const remap_rule_t remap_rules[] = {
{ 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 },
// --- Workspace switching (Mac) ---
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_ALT, KC_LEFT, MOD_MASK_CTRL, 0 }, // switch workspace left
{ OS_MAC, APP_ANY, MOD_MASK_CTRL | MOD_MASK_ALT, KC_RGHT, MOD_MASK_CTRL, 0 }, // switch workspace right
// --- Alt+F4 -> Cmd+Q (Mac) ---
{ OS_MAC, APP_ANY, MOD_MASK_ALT, KC_F4, MOD_MASK_GUI, KC_Q },
@@ -117,6 +129,7 @@ typedef struct {
uint8_t to_mods; // normalized mods that were added
uint8_t saved_mods; // exact get_mods() at press time, for restoration
// updated as from-mods are released during hold
uint8_t flags; // propagated from remap_rule_t
} active_rewrite_t;
static active_rewrite_t active_rw = {0};
@@ -150,7 +163,7 @@ static bool process_rewrite_release(uint16_t keycode, keyrecord_t *record) {
}
// Apply a rewrite unconditionally (matching already done by caller).
static void apply_rewrite(uint16_t trigger_keycode, uint8_t mods_from, uint8_t mods_to, uint16_t key_out) {
static void apply_rewrite(uint16_t trigger_keycode, uint8_t mods_from, uint8_t mods_to, uint16_t key_out, uint8_t flags) {
uint8_t mods = get_mods();
if (active_rw.trigger_keycode) teardown_active_rewrite();
active_rw = (active_rewrite_t){
@@ -159,6 +172,7 @@ static void apply_rewrite(uint16_t trigger_keycode, uint8_t mods_from, uint8_t m
.from_mods = normalize_mods(mods_from),
.to_mods = normalize_mods(mods_to),
.saved_mods = mods,
.flags = flags,
};
set_mods(active_rw.to_mods);
register_code(key_out);
@@ -173,7 +187,7 @@ static bool apply_remap_rules(uint16_t keycode) {
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);
apply_rewrite(keycode, r->mods_from, r->mods_to, r->key_to ? r->key_to : keycode, r->flags);
return true;
}
return false;
@@ -232,7 +246,7 @@ ________________________________________________________________________________
| x | | | | | | | | | | | | PGUP |
|________________|________|________|________|________|________|________|________|________|________|________|____________|________|_________
| | | | | | | | | | | | | |
| x | | x | x | | | x | x | x | | HOME | PGDN | END |
| x | | x | x | | | x | x | NOREMAP | | HOME | PGDN | END |
|____________|________|_______|________|_________________|_________________|________|________|_____________| |________|________|________|
*/
@@ -242,7 +256,7 @@ ________________________________________________________________________________
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_PGUP,
KC_NO, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_HOME, KC_PGDN, KC_END
KC_NO, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, CK_NOREMAP, KC_HOME, KC_PGDN, KC_END
),
[2] = LAYOUT(
@@ -313,6 +327,13 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// Handle release events for active modifier rewrites (key repeat support)
if (!process_rewrite_release(keycode, record)) return false;
// Cancel modifier-only rewrites (e.g. Ctrl->Cmd) when any other key is pressed
if (record->event.pressed && active_rw.trigger_keycode &&
(active_rw.flags & RULE_CANCEL_ON_KEYPRESS) &&
keycode != active_rw.trigger_keycode) {
teardown_active_rewrite();
}
// Any other key pressed while GUI held means it's being used as a modifier
if (record->event.pressed && keycode != KC_LGUI) {
super_tapped = false;