awesome icon indicating copy to clipboard operation
awesome copied to clipboard

Key release signals not emitted for modifier keys

Open keidax opened this issue 9 years ago • 27 comments

Signals for the modifier keys (Alt_L, Ctrl_L, Super_L, etc.) are emitted only on key press events, not on key release events.

I added

awful.key({ modkey }, "Alt_R", nil)

to globalkeys, then added the lines

for i,v in pairs(globalkeys) do
    if v.key == "Alt_R" then
        v:connect_signal("press", function(...)
            print("press signal received")
        end)
        v:connect_signal("release", function(...)
            print("release signal received")
        end)
    end
end

Running awesome inside Xephyr, I see the press signals but not the releases.

Other keys such as alphanumerics work as expected.

keidax avatar Mar 18 '15 22:03 keidax

Running awesome inside Zephyr, I see the press signals but not the releases.

It is not specific to Xephyr, is it?

blueyed avatar Mar 18 '15 23:03 blueyed

No, I can run xev within Xephyr and see all the correct key presses.

keidax avatar Mar 18 '15 23:03 keidax

I've meant if it also happens when running awesome directly. And I assume that you mean Xephyr instead of "Zephyr"?

blueyed avatar Mar 19 '15 00:03 blueyed

I just tested and it happens when running awesome directly as well.

You're right about Xephyr, I fixed it.

keidax avatar Mar 19 '15 02:03 keidax

Can confirm. I'm running awesome directly, key release events don't get called. This is the key binding I'm creating in rc.lua inside globalkeys:

awful.key({ "Shift" }, "Control_L",
    function() naughty.notify{ title="ctrl+shift down" } end,
    function() naughty.notify{ title="ctrl+shift up"} end
)

Like @keidax, I see the notification for "ctrl+shift down", but not up, regardless of the order of releasing the keys.

EngiN33R avatar Mar 26 '15 10:03 EngiN33R

same thing for mouse buttons.

tested with:

awful.button({ modkey }, 1 , print("press") , print("release"))

radi-ka avatar Mar 29 '15 20:03 radi-ka

See also this report in the old bugtracker, which has some additional information from when I've tried to debug this: https://awesome.naquadah.org/bugs/index.php?do=details&task_id=1129

blueyed avatar Mar 29 '15 21:03 blueyed

The problem appears to be that for the "release" event the released modifier is probably in ev->state, but not in k->modifiers.

https://github.com/awesomeWM/awesome/blob/68b0fa243ff828abd0a766a18c87755730676f9d/event.c#L87-L95

blueyed avatar Aug 10 '15 22:08 blueyed

Add the following to your globalkeys and then think about the results:

awful.key({ }, "Alt_L", function() print("alt pressed") end, function() print("does not happen") end),
awful.key({ "Mod1" }, "Alt_L", function() print("does not happen") end, function() print("alt released") end),

Result:

alt pressed
alt released

(Spoiler: The above asks for "Alt_L" without any modifiers and then for "Alt_L" together with modifier 1 and pressing Alt_L activates modifier 1. So the problem is that Alt_L itself is a modifier and thus the release event no longer matches the keybinding asking for no modifiers at all. No idea how to sanely fix this, but I guess we'd have to ask libxkbcommon "Alt_L was released, which modifier does this deactivate which I should thus ignore?".)

(However, it's not really that easy, because, for example, there is a left and a right shift key. When you press both, the press and release for the second one should have the Shift modifier activated and only the very first press and the very last one should ignore the modifier. And handling this correctly becomes tricky.)

Oh and the issue about mouse buttons is unrelated to this one. So this has nothing to do with FS#1129.

Sorry for only noticing this now. At least you know have a work-around for this.

psychon avatar Aug 11 '15 07:08 psychon

I guess we'd have to ask libxkbcommon "Alt_L was released, which modifier does this deactivate which I should thus ignore?"

That does not seem to be too simple. I have found XGetModifierMapping which could be used to get the modifier that a key belongs to. It is used by xmodmap (from x11-xserver-utils).

We have xutil_key_mask_fromstr already, and could add xutil_mod_mask_fromkey in the same vain.

My first attempt has been the following, but it will match too many (if there is the same hotkey with multiple modifier combinations):

&& (k->modifiers == XCB_BUTTON_MASK_ANY
    || (XCB_EVENT_RESPONSE_TYPE(ev) == XCB_KEY_PRESS
        && k->modifiers == ev->state)
    || (XCB_EVENT_RESPONSE_TYPE(ev) == XCB_KEY_RELEASE
        && (ev->state & k->modifiers) == globalconf.modifier_mask)));

I wonder if the same method from event_handle_button could be applied here (https://github.com/awesomeWM/awesome/blob/68b0fa243ff828abd0a766a18c87755730676f9d/event.c#L201-212)?

    /* ev->state contains the state before the event. Compute the state
     * after the event for the mousegrabber.
     */
    uint16_t state = ev->state, change = 1 << (ev->detail - 1 + 8);
    if (XCB_EVENT_RESPONSE_TYPE(ev) == XCB_BUTTON_PRESS)
        state |= change;
    else
        state &= ~change;
    if(event_handle_mousegrabber(ev->root_x, ev->root_y, state))
        return;

Another idea might be to handle it via XCB_XKB_STATE_NOTIFY in event_handle_xkb_notify and keep track of the modifier mask in globalconf somehow?!

blueyed avatar Aug 11 '15 12:08 blueyed

Is the discussion around this issue still alive? Stumbled across this, while trying to get the release event for Super_L.

Also is there with the current open issue any known workaround to get a function triggered on the release of a modifier key (especially one that is also used in several other keybindings)? I tried registering a keyhandler in the pressed callback, but as long as this is running no other registered shortcut for this modifier key works. Is there a possibility to pass a key event from my keyhandler to the "global" one of awesome, so that I could use this as a workaround? Using awful.key.execute from within the keygrabber (or this special key combinations with Super in it) doesn't seem to execute any of the other registered listeners.

timroes avatar Apr 15 '17 20:04 timroes

Okay I found a workaround for my case (and perhaps it helps someone else too):

awful.key({}, 'Super_L', function() 
  -- press event will be called
end)
awful.key({'Mod4'}, 'Super_L', function() end, function()
  -- release event will be triggered with the key itself as a modifier
end)

timroes avatar Apr 15 '17 20:04 timroes

And I stand corrected again. The above basically works and other global hotkeys containing Super_L will still be triggered, but key bindings on clients containing that meta key won't be triggered at all anymore (which might be some kind of new bug?)

timroes avatar Apr 18 '17 09:04 timroes

Is there any news? I've faced the same issue on awesome v4.3 and Shift+Control_L/Control+Shift_L hotkeys.

mbagdasarov avatar Apr 02 '20 01:04 mbagdasarov

Since I am running into that right now again, can also confirm this is still an issue on v4.3 and also want to elaborate my comment from 3 years ago.

It seems as soon as you have a root key listener on a meta key: (awful.key({}, 'Super_L', function() ... end)) at that point no further keys registered directly on clients (e.g. via awful rules) will be called anymore (the workaround function above is irrelevant for that behavior). At the same time all other root key bindings that contain Mod4 as a modifier will still work perfectly.

This behavior is slightly annoying, since it prevents to build any global shortcut on the primary modifier key alone e.g. I wanted to trigger something when double clicking the Super key, but that breaks all client key bindings.

I am curious if anyone has found a recent workaround for that?

timroes avatar May 01 '20 17:05 timroes

I've just run into this same issue. I've come from i3 where I had the toolbar hide until I was holding the modkey (Super_L) as I like a clean minimal display. I had hoped that a WM with a full language based config would give me complete control. I guess I should have known better, lol.

RJSzynal avatar May 22 '20 22:05 RJSzynal

@RJSzynal you mean solution provided 5 years ago stopped working? https://github.com/awesomeWM/awesome/issues/169#issuecomment-129749339 https://github.com/awesomeWM/awesome/issues/169#issuecomment-294317264

actionless avatar May 23 '20 15:05 actionless

@actionless It sounds like that solution never worked in the first place. https://github.com/awesomeWM/awesome/issues/169#issuecomment-294752983 https://github.com/awesomeWM/awesome/issues/169#issuecomment-622482864

It seems as soon as you have a root key listener on a meta key: (awful.key({}, 'Super_L', function() ... end)) at that point no further keys registered directly on clients (e.g. via awful rules) will be called anymore (the workaround function above is irrelevant for that behavior)

RJSzynal avatar May 24 '20 00:05 RJSzynal

then it's a different issue from the OP

actionless avatar May 24 '20 14:05 actionless

To clarify, I'm saying the solution to the original issue, provided before, creates this second issue and is therefore not viable. So the original issue stands unresolved.

RJSzynal avatar May 24 '20 14:05 RJSzynal

the OP is about binding release handlers, your issue is about inability to bind press event handler if modifier is already engaged

actionless avatar May 24 '20 19:05 actionless

My problem is that it does not register release event handlers! Literally the same as the first line of the first post.

Signals for the modifier keys (Alt_L, Ctrl_L, Super_L, etc.) are emitted only on key press events, not on key release events.

I tried the "solution" you referenced but it only creates a second issue whereby the press event is not handled for clients and is therefore not a solution This leaves my issue back to being the same as the OP.

RJSzynal avatar May 25 '20 09:05 RJSzynal

Hi I'm facing the same issue, but as tried follow the example @psychon in https://github.com/awesomeWM/awesome/issues/169#issuecomment-129749339 and I came to this piece of code:

local awful = require("awful")
local gears = require("gears")
local debug = gears.debug.dump_return

local function notify(options)
	require("naughty").notify(options)
end

local function dump(variable)
	return gears.debug.dump_return(variable)
end

local key_press = {
	last_press = nil,
	current_press = os.time()
}

local globalkeys = gears.table.join(
	awful.key({ }, "Super_R",function()
	local now=os.time()
	local last_press=key_press.last_press
	notify({
		title="last_press "  .. last_press,
		text="current " .. now,
		timeout=5
	})
        --- here I define a timeout between super key and others bindings
        -- to act like windows
	if now - last_press > 2 and last_press ~= nil then
		notify({title="Super_R Finished"})
	end
	end),
awful.key({ "Mod4" }, "Super_R", _ , function()
		notify({title="Super_R released"});
	end),

awful.key({ "Mod4" }, "p", function()
	notify({title="Super_R + p pressed"})
end)
)

-- I save the last timestamp the key was pressed
key.connect_signal("press",function()
	local now = os.time()
	local last_press
	local msg

	if key_press.last_press == nil then
		last_press=now
		key_press.last_press = last_press
	else
		last_press=key_press.last_press
		key_press.last_press = now
	end

	notify({
		title="last_press "  .. last_press,
		text="current " .. now,
		timeout=5
	})

end)
root.keys(globalkeys)

this way I can use my super key to open my launcher for example and keep the super key + j to focus another client. Lua is not my first programming language but a tried, pretty sure that this code could be refactory to something more readble.

Sorry for the english. :(

Edit:

Hi I made another tests and using the method suggested by @psychon some keybinds stopping working like modkey + o.

Rodrigo-Barros avatar Nov 13 '21 22:11 Rodrigo-Barros

I am running into a similar issue but mine is having an effect on the XF86AudioRaiseVolume and XF86AudioLowerVolume key events. I run xev and it is picking up the key strokes. xmodmap shows all of the XF86Audio* keys, too. The setup I've been using is:

awful.key({}, "XF86AudioRaiseVolume", get_current_volume(volumesliderwidget), {description="Raise volume", group="control"})

Putting a naughty.notify() function call in the callback doesn't even run so the event isn't being registered. Am I missing something? I am running:

awesome v4.3 (Too long) • Compiled against Lua 5.3.3 (running with Lua 5.3) • D-Bus support: ✔ • execinfo support: ✔ • xcb-randr version: 1.6 • LGI version: 0.9.2

willholl4nd avatar Jan 16 '22 01:01 willholl4nd

@willholl4nd This is unrelated to the issue you posted in. XF86* keys are not modifier keys, and in the snippet you posted, you're not using the key release event.

Either way, it looks like you're not actually providing a callback function, unless get_current_volume returns a function.

These two snippets are equivalent:

awful.key({}, "XF86AudioRaiseVolume", naughty.notify({ text = "XF86AudioRaiseVolume" }))
naughty.notify({ text = "XF86AudioRaiseVolume" })
awful.key({}, "XF86AudioRaiseVolume", nil)

The notification is created only one time, when the key definition is created. You need to provide a function that may be called at a later time (when the key is pressed).

awful.key({}, "XF86AudioRaiseVolume", function()
	naughty.notify({ text = "XF86AudioRaiseVolume" })
end)

sclu1034 avatar Jan 16 '22 09:01 sclu1034

And I stand corrected again. The above basically works and other global hotkeys containing Super_L will still be triggered, but key bindings on clients containing that meta key won't be triggered at all anymore (which might be some kind of new bug?)

I ran into this today, too. Seem to still be a bug. Is there anything we can do about it?

ptrxyz avatar Sep 04 '22 18:09 ptrxyz

https://github.com/awesomeWM/awesome/issues/169#issuecomment-294317264

This does not work for me, but if you replace Mod4 with Any, it does seem to work for me

awful.key({ 'Any' }, 'Super_L', nil, function()
  -- release event will be triggered
end)

JasonTheKitten avatar Aug 05 '23 04:08 JasonTheKitten