[ English / 日本語 ]
This module provides a mechanism to dynamically shift keyboard layouts at runtime, primarily intended to solve discrepancies when an OS is configured for a non-US layout (e.g., JIS).
Specifically, this module provides a behavior &kpls that maps keycodes according to the current layout shift state. You can override the &kp behavior with &kpls, which lets it work without modifying your existing keymap, while preserving Keymap Editor compatibility. If you prefer not to override &kp, you can also use &kpls in your keymap instead.
Multiple layouts can be enabled simultaneously, each with independent on/off state.
This module defines the following behaviors:
&kpls: A layout-aware version of&kp; maps keycodes according to active layout shift maps. For example,&kpls EQUALnormally outputs=, but outputs_(which is=in JIS layout) when US -> JIS layout is enabled.&tog_ls: Toggles layout shift maps on/off&tog_ls_on: Turns on layout shift maps&tog_ls_off: Turns off layout shift maps
These toggle behaviors require the layout-maps property to specify which layout(s) to control (see Usage). Multiple layout maps can be specified.
- US -> JIS: Converts US keyboard keycodes for use on an OS configured with the JIS layout
- Dvorak: Dvorak keyboard layout
- Swap Ctrl and Cmd: Swap Ctrl / Cmd for Windows / Mac
You can also define your own custom layout maps. See Adding New Layouts for details.
manifest:
remotes:
- name: zmkfirmware
url-base: https://github.com/zmkfirmware
- name: kot149
url-base: https://github.com/kot149
projects:
- name: zmk
remote: zmkfirmware
revision: main
import: app/west.yml
- name: zmk-layout-shift
remote: kot149
revision: v2
self:
path: configConfigure the toggle behaviors to point to the desired layout map(s). Layout maps are automatically enabled when referenced. If layout-maps is omitted, the toggle controls all available layout maps at once:
&tog_ls { layout-maps = <&layout_shift_map_us_to_jis>; };
&tog_ls_on { layout-maps = <&layout_shift_map_us_to_jis>; };
&tog_ls_off { layout-maps = <&layout_shift_map_us_to_jis>; };
Available layout map nodes:
| Node Label | Layout |
|---|---|
layout_shift_map_us_to_jis |
US -> JIS |
layout_shift_map_dvorak |
Dvorak |
layout_shift_map_swap_ctrl_cmd |
Swap Ctrl / Cmd |
You can also define your own custom layout maps. See Adding New Layouts for details.
You can control multiple layouts with a single toggle by specifying multiple phandles:
&tog_ls { layout-maps = <&layout_shift_map_us_to_jis &layout_shift_map_swap_ctrl_cmd>; };
&tog_ls_on { layout-maps = <&layout_shift_map_us_to_jis &layout_shift_map_swap_ctrl_cmd>; };
&tog_ls_off { layout-maps = <&layout_shift_map_us_to_jis &layout_shift_map_swap_ctrl_cmd>; };
Note: When multiple layout maps are active simultaneously, maps are applied sequentially. By default, they are applied in devicetree declaration order (
layout_shift_maps.dtsi). The output of one map becomes the input to the next, so if map 1 mapsA -> Band map 2 mapsB -> C, the final output isC.To control the application order explicitly, set the
priorityproperty on each layout map node — smaller values are applied first.&layout_shift_map_us_to_jis { priority = <1>; }; &layout_shift_map_swap_ctrl_cmd { priority = <2>; }; // applied after JIS
#include layout_shift_kp_override.dtsi to override &kp with custom implementation which is layout-aware. This allows to use layout shift without modifying your existing keymap, while preserving Keymap Editor compatibility.
#include <layout_shift_kp_override.dtsi>Important
You need to add this include **below** the #include <behaviors.dtsi> or other includes to make it work.
However, Keymap Editor automatically reorders the includes. To avoid this, you can copy-paste the definition of &kp from layout_shift_kp_override.dtsi directly to your keymap file.
Use &tog_ls, &tog_ls_on, &tog_ls_off in your keymap to control layout shift state. Then &kp will output the keycode according to the active layout shift maps.
#include <layout_shift_kp_override.dtsi>
&tog_ls { layout-maps = <&layout_shift_map_us_to_jis>; };
&tog_ls_on { layout-maps = <&layout_shift_map_us_to_jis>; };
&tog_ls_off { layout-maps = <&layout_shift_map_us_to_jis>; };
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&kp EQUAL // Will output = normally, but _ (which is = on JIS layout OS) when the US -> JIS layout shift is active
&tog_ls // Toggle US -> JIS keycode conversion on/off
&tog_ls_on // Turn on US -> JIS layout shift
&tog_ls_off // Turn off US -> JIS layout shift
>;
};
};
};
Note
If you prefer not to override &kp, #include layout_shift.dtsi instead of layout_shift_kp_override.dtsi and use &kpls in your keymap instead:
#include <layout_shift.dtsi>
&tog_ls { layout-maps = <&layout_shift_map_us_to_jis>; };
&tog_ls_on { layout-maps = <&layout_shift_map_us_to_jis>; };
&tog_ls_off { layout-maps = <&layout_shift_map_us_to_jis>; };
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&kpls EQUAL // Will output = normally, but _ (which is = on JIS layout) when JIS layout is active
&tog_ls // Toggle US -> JIS layout shift on/off
&tog_ls_on // Turn on US -> JIS layout shift
&tog_ls_off // Turn off US -> JIS layout shift
>;
};
};
};
If you need separate toggle keys for different layouts (e.g., one key for JIS, another for Swap Ctrl/Cmd), you can define per-layout toggle behaviors in your keymap:
#include <layout_shift_kp_override.dtsi>
/ {
behaviors {
tog_ls_us_to_jis: toggle_layout_shift_us_to_jis {
compatible = "zmk,behavior-layout-shift-toggle";
#binding-cells = <0>;
toggle-mode = "flip";
layout-maps = <&layout_shift_map_us_to_jis>;
};
tog_ls_swap: toggle_layout_shift_swap {
compatible = "zmk,behavior-layout-shift-toggle";
#binding-cells = <0>;
toggle-mode = "flip";
layout-maps = <&layout_shift_map_swap_ctrl_cmd>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&tog_ls_us_to_jis // Toggle US -> JIS conversion
&tog_ls_swap // Toggle Swap Ctrl/Cmd layout
>;
};
};
};
You can also define on / off variants by setting toggle-mode to "on" or "off".
You can define custom layout maps in your own keymap or .dtsi files.
Add a layout map node with compatible = "zmk,layout-shift-map":
/ {
layout_shift_map_colemak: layout_shift_map_colemak {
compatible = "zmk,layout-shift-map";
mappings = <
E F LAYOUT_SHIFT_OPTIONAL_ALL
R P LAYOUT_SHIFT_OPTIONAL_ALL
T G LAYOUT_SHIFT_OPTIONAL_ALL
// ... add more mappings as needed
>;
};
};
Then reference it from a toggle behavior:
&tog_ls { layout-maps = <&layout_shift_map_colemak>; };
Or define a dedicated toggle behavior for it (see Per-Layout Toggle Behaviors).
Each mapping consists of three values: from_keycode, to_keycode, optional_modifiers.
Optional Modifier Control Options:
LAYOUT_SHIFT_OPTIONAL_NONE(0): All modifiers required (exact match)LAYOUT_SHIFT_OPTIONAL_SHIFT: Shift keys are optional during matchingLAYOUT_SHIFT_OPTIONAL_CTRL: Ctrl keys are optional during matchingLAYOUT_SHIFT_OPTIONAL_ALT: Alt keys are optional during matchingLAYOUT_SHIFT_OPTIONAL_GUI: GUI (Windows/Cmd) keys are optional during matchingLAYOUT_SHIFT_OPTIONAL_ALL(0xFF): All modifiers optional during matching- Custom combinations:
LAYOUT_SHIFT_OPTIONAL_CTRL | LAYOUT_SHIFT_OPTIONAL_ALT(Ctrl/Alt optional, Shift/GUI required)
References: