Binds in Lua are not recognized

Hi,

I have recognized that binds seem to act weird when I tried to move my config to the new Lua format. The following example works fine using the .conf file, but not the .lua configuration:

Current hyprland.conf contains:

$mainMod = Super_L

bind = $mainMod Shift_L, C, killactive,

In my hyprland.lua configuration I use:

local mainMod = “Super_L”

hl.bind(mainMod .. " + Shift_L + C", hl.dsp.window.close())

Effectively, pressing the Mod key does not work - consequently none of the binds work. wev or xkbcli interactive-wayland both recognize the keysym Super_L properly.

Using the following on latest Arch:

hyprland -v
Hyprland 0.55.1 built from branch v0.55.1 at commit a47147bc095e5b3be3eb8bd04f0ac242b968cd4d clean ([gha] Nix: update inputs).
Date: Wed May 13 22:55:46 2026
Tag: v0.55.1, commits: 7311

Libraries:
Hyprgraphics: built against 0.5.1, system has 0.5.1
Hyprutils: built against 0.13.1, system has 0.13.1
Hyprcursor: built against 0.1.13, system has 0.1.13
Hyprlang: built against 0.6.8, system has 0.6.8
Aquamarine: built against 0.11.0, system has 0.11.0

I don’t think you need the _L for mainMod?

I have the followingin my binds.lua:

local mainMod = “SUPER”

local closeWindowBind = hl.bind(“SUPER + mouse:273”, hl.dsp.window.close())

I don’t understand why omitting the _L should be the solution when the keysym refers to Super_L.

But, for what it’s worth using local mainMod = “SUPER” works. However, then the original window.close bind does not work as it implies a Shift_L:

local mainMod = “SUPER”

hl.bind(mainMod .. " + Shift_L + C", hl.dsp.window.close())

Therefore, the bind does not work.

Instead, using

local mainMod = “SUPER”

hl.bind(mainMod .. " + SHIFT + C", hl.dsp.window.close())

does work.

I am not sure if this is the intended behavior. Because it would be awesome if you could distinguish between a Shift_L and Shift_R but still be able accept both using SHIFT.

We have modifiers and keys. A keybind has a modifier (optional) and a key.
I am not sure if you can have 2 keys. Edit: you can have multiple keys.

Modifiers: From LuaBindingsTopLevel.cpp

static std::optional modFromSv(std::string_view sv) {
if (sv == “SHIFT”)
return HL_MODIFIER_SHIFT;
if (sv == “CAPS”)
return HL_MODIFIER_CAPS;
if (sv == “CTRL” || sv == “CONTROL”)
return HL_MODIFIER_CTRL;
if (sv == “ALT” || sv == “MOD1”)
return HL_MODIFIER_ALT;
if (sv == “MOD2”)
return HL_MODIFIER_MOD2;
if (sv == “MOD3”)
return HL_MODIFIER_MOD3;
if (sv == “SUPER” || sv == “WIN” || sv == “LOGO” || sv == “MOD4” || sv == “META”)
return HL_MODIFIER_META;
if (sv == “MOD5”)
return HL_MODIFIER_MOD5;

return std::nullopt;

}

Keys: These go to xkbcommon-keysyms.h and are case insensitive i believe:

// Normal keys A, B, C

// [...]

#define XKB_KEY_Shift_L                       0xffe1  /* Left shift /
#define XKB_KEY_Shift_R                       0xffe2  / Right shift /
#define XKB_KEY_Control_L                     0xffe3  / Left control /
#define XKB_KEY_Control_R                     0xffe4  / Right control /
#define XKB_KEY_Caps_Lock                     0xffe5  / Caps lock /
#define XKB_KEY_Shift_Lock                    0xffe6  / Shift lock */

#define XKB_KEY_Meta_L                        0xffe7  /* Left meta /
#define XKB_KEY_Meta_R                        0xffe8  / Right meta /
#define XKB_KEY_Alt_L                         0xffe9  / Left alt /
#define XKB_KEY_Alt_R                         0xffea  / Right alt /
#define XKB_KEY_Super_L                       0xffeb  / Left super /
#define XKB_KEY_Super_R                       0xffec  / Right super /
#define XKB_KEY_Hyper_L                       0xffed  / Left hyper /
#define XKB_KEY_Hyper_R                       0xffee  / Right hyper */

// [...]

Also on my machine, the bind

hl.bind("SUPER + CTRL_L", hl.dsp.window.drag(), { mouse = true })

from Binds – Hyprland Wiki throws an error, as there is no XKB_KEY_Ctrl_L in xkbcommon-keysyms.h

Edit:

If a dev reads this:

  1. Please fix the wiki example to use CONTROL_L instead of non-existing CTRL_L.

  2. I think the lua bind parser accepts binds with only modifiers, which are dead. They should be rejected with an error message.

  3. I think the wiki would benefit from a list of modifiers. For example: “Valid modifiers are SUPER, SHIFT, CTRL, ALT and CAPS.”

Thank you all for your feedback. I am still slightly confused though :sweat_smile:

Are modifiers only accepted in the ‘simple’ form as in SHIFT and not being recognized and distinguished between Shift_L / Shift_R?

Because certainly there seems to be an issue with how these keysyms are being parsed when using the lua approach.

Modifiers is something different from a key, and as such handled differently.
Super_L is a key, SUPER is a modifier. Super_L and Super_R both set the SUPER flag when pressed.
And yes, it’s possible to make hyprland handle L and R, but requires some work in the keybindmanager in the source. No one have just gotten around to it yet i guess. Open a feature request and maybe someone will pick it up.