[ 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. By overriding the &kp
behavior with &kpls
, it works without modifying your keymap, while preserving Keymap Editor compatibility.
This module defines the following behaviors:
&kpls
: A layout-aware version of&kp
; maps keycodes according to the current layout shift state. For example,&kpls EQUAL
normally outputs=
, but outputs_
(which is=
in JIS layout) when JIS layout is enabled.&tog_ls
: Toggles the layout shift state&tog_ls_on
: Turns on the layout shift state&tog_ls_off
: Turns off the layout shift state
Optionally, you can #include
layout_shift_kp_override.dtsi
to override the &kp
behavior with &kpls
, so that you can use layout shift without modifying your keymap, while preserving Keymap Editor compatibility.
- JIS: Japanese keyboard layout
- Dvorak: Dvorak keyboard layout
- Swap Ctrl and Cmd: Swap Ctrl / Cmd for Windows / Mac (Note: Currently, this only works with pure modifier key presses (like
&kp LEFT_CONTROL
) or mod-taps (like&mt LEFT_CONTROL A
). It doesn't work for modifiers applied to non-modifier key presses (like&kp LCTL(C)
)).
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: v1
self:
path: config
-
#include
layout_shift.dtsi
at the top of your keymap:#include <layout_shift.dtsi>
-
Select the target layout by selecting one from
LAYOUT_SHIFT_TARGET_LAYOUT
choice and add it to your .conf file (e.g.,your_keyboard.conf
):CONFIG_LAYOUT_SHIFT_TARGET_JIS=y # Japanese (JIS) layout # or CONFIG_LAYOUT_SHIFT_TARGET_DVORAK=y # Dvorak layout # etc.
-
Add
&tog_ls
/&tog_ls_on
/&tog_ls_off
to your keymap and use&kpls
instead of&kp
to allow toggling the layout:#include <layout_shift.dtsi> / { keymap { compatible = "zmk,keymap"; default_layer { bindings = < &kpls EQUAL // Will output = normally, but _ (which is = on JIS layout) for JIS layout &tog_ls // Toggle layout shift on/off &tog_ls_on // Turn layout shift on &tog_ls_off // Turn layout shift off >; }; }; };
You can #include
layout_shift_kp_override.dtsi
to override the &kp
behavior with &kpls
, so that you can use layout shift without modifying your keymap, while preserving Keymap Editor compatibility.
#include <layout_shift_kp_override.dtsi>
Note: You can omit layout_shift.dtsi
as it's also included in 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.
Now you can use &kp
as usual:
#include <layout_shift_kp_override.dtsi>
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&kp EQUAL // Will output = normally, but _ (which is = on JIS layout) for JIS layout
&tog_ls // Toggle layout shift on/off
&tog_ls_on // Turn layout shift on
&tog_ls_off // Turn layout shift off
>;
};
};
};
Add a new option to the choice
block in Kconfig
:
choice LAYOUT_SHIFT_TARGET_LAYOUT
prompt "Target keyboard layout"
default LAYOUT_SHIFT_TARGET_JIS
config LAYOUT_SHIFT_TARGET_JIS
bool "Japanese (JIS)"
config LAYOUT_SHIFT_TARGET_DVORAK
bool "Dvorak"
...
config LAYOUT_SHIFT_TARGET_COLEMAK # Add this line
bool "Colemak" # Add this line
endchoice
Create a new layout file in src/layouts/
(e.g., layout_colemak.h
):
#ifdef CONFIG_LAYOUT_SHIFT_TARGET_COLEMAK
#define LAYOUT_DEFINED
// Colemak keyboard layout mappings
// Maps US QWERTY keycodes to their Colemak equivalents
static const struct keycode_mapping layout_map[] = {
/* from -> to, optional_modifiers */
{E, F, OPTIONAL_ALL}, // E -> F (all modifiers optional for letters)
{R, P, OPTIONAL_ALL}, // R -> P (all modifiers optional for letters)
{T, G, OPTIONAL_ALL}, // T -> G (all modifiers optional for letters)
// ... add more mappings as needed
// For symbols, you might want to require certain modifiers:
// {COMMA, W, OPTIONAL_CTRL | OPTIONAL_ALT}, // , -> W (Shift required, Ctrl/Alt optional)
};
#endif
Optional Modifier Control Options:
OPTIONAL_NONE
(0): All modifiers required (exact match)OPTIONAL_SHIFT
: Shift keys are optional during matchingOPTIONAL_CTRL
: Ctrl keys are optional during matchingOPTIONAL_ALT
: Alt keys are optional during matchingOPTIONAL_GUI
: GUI (Windows/Cmd) keys are optional during matchingOPTIONAL_ALL
(0xFF): All modifiers optional during matching- Custom combinations:
OPTIONAL_CTRL | OPTIONAL_ALT
(Ctrl/Alt optional, Shift/GUI required)
References:
Add the include statement to src/layouts/index.h
:
// Layout index - includes all available layout definitions
// Each layout file contains its own conditional compilation directives
#include "layout_jis.h"
#include "layout_dvorak.h"
...
#include "layout_colemak.h" // Add this line
// Ensure at least one layout is defined
#ifndef LAYOUT_DEFINED
#error "No target layout selected. Please select a layout in Kconfig."
#endif
Update this README.md to list the new layout in the "List of Supported Layouts" section.