Skip to main content
Version: 2.0 (dev)

Keyboard Layout Switching

This guide covers setting up multiple keyboard layouts and switching between them in SomeWM.

Setting Your Layout

Configure your keyboard layout in rc.lua using awful.input:

local awful = require("awful")

-- Single layout
awful.input.xkb_layout = "us"

-- Multiple layouts (comma-separated)
awful.input.xkb_layout = "us,de,ru"

-- With variants
awful.input.xkb_variant = ",nodeadkeys," -- variant for each layout

Switching Layouts

Why Toggle Options Don't Work

In X11, XKB toggle options like grp:alt_shift_toggle work because the X server executes the layout switch when you press the key combination. On Wayland, there's no X server to do this - the toggle key is just a key press that never triggers a switch.

Sway, Hyprland, and other Wayland compositors have the same limitation.

The Solution: Keybindings

Create an explicit keybinding to cycle through your layouts:

awful.key({ "Mod1", "Shift" }, "space", function()
local layouts = awful.widget.keyboardlayout.get_groups_from_group_names(
awesome.xkb_get_group_names())
local current = awesome.xkb_get_layout_group()
awesome.xkb_set_layout_group((current + 1) % #layouts)
end, {description = "switch keyboard layout", group = "awesome"})

Or a simpler version if you know you have exactly 2 layouts:

awful.key({ "Mod1", "Shift" }, "space", function()
local current = awesome.xkb_get_layout_group()
awesome.xkb_set_layout_group((current + 1) % 2)
end, {description = "switch keyboard layout", group = "awesome"})

Displaying Current Layout

Add a keyboard layout indicator to your wibar:

local awful = require("awful")

-- Create the widget
local keyboard_layout = awful.widget.keyboardlayout()

-- Add to your wibar
s.mywibox = awful.wibar({
position = "top",
screen = s,
widget = {
-- ... other widgets ...
keyboard_layout,
-- ... other widgets ...
}
})

The widget automatically updates when you switch layouts.

XKB Options That Work

Static XKB options still work fine on Wayland. Only toggle options (grp:*) are affected:

-- These work
awful.input.xkb_options = "ctrl:nocaps" -- Caps Lock as Ctrl
awful.input.xkb_options = "ctrl:swapcaps" -- Swap Caps Lock and Ctrl
awful.input.xkb_options = "compose:ralt" -- Right Alt as Compose
awful.input.xkb_options = "caps:escape" -- Caps Lock as Escape

-- These do NOT trigger automatic switching
awful.input.xkb_options = "grp:alt_shift_toggle"
awful.input.xkb_options = "grp:win_space_toggle"

You can combine working options:

awful.input.xkb_options = "ctrl:nocaps,compose:ralt"

Complete Example

local awful = require("awful")

-- Set up layouts
awful.input.xkb_layout = "us,de"
awful.input.xkb_options = "ctrl:nocaps,compose:ralt"

-- Keybinding to switch
awful.keyboard.append_global_keybindings({
awful.key({ "Mod1", "Shift" }, "space", function()
local layouts = awful.widget.keyboardlayout.get_groups_from_group_names(
awesome.xkb_get_group_names())
local current = awesome.xkb_get_layout_group()
awesome.xkb_set_layout_group((current + 1) % #layouts)
end, {description = "switch keyboard layout", group = "awesome"})
})

See Also