[ 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 EQUALnormally 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-
#includelayout_shift.dtsiat the top of your keymap:#include <layout_shift.dtsi>
-
Select the target layout by selecting one from
LAYOUT_SHIFT_TARGET_LAYOUTchoice 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_offto your keymap and use&kplsinstead of&kpto 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)
};
#endifOptional 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."
#endifUpdate this README.md to list the new layout in the "List of Supported Layouts" section.