Open Bug 1299553 Opened 8 years ago Updated 6 months ago

[Cocoa] Keyup events are not fired if cmd/meta key is pressed

Categories

(Core :: DOM: UI Events & Focus Handling, defect, P5)

x86_64
macOS
defect

Tracking

()

People

(Reporter: tcsc, Unassigned)

References

Details

(Whiteboard: tpi:+)

Noticed this over the weekend while working on a hobby project: I haven't tested this on any platform other than mac. If cmd key is pressed, keydown events are still fired for other keys, but the keyup events won't be. This seems to behave as expected for modifier keys, e.g. the keyup events are still fired for alt, ctrl, shift, etc. Here's a small page you can use to verify this: https://jsfiddle.net/fLdygewL/ Make sure the bottom right pane has focus and try pressing and holding cmd, followed by pressing and releasing s, c, v, etc.
Masayuki, is this expected behaviour?
Flags: needinfo?(masayuki)
IIRC, macOS (OS X) doesn't send keyup event to us while Cmd key is pressed. How about on the other browsers?
Flags: needinfo?(masayuki)
Thom, can you confirm the behaviour of other browsers? (see comment 2)
Flags: needinfo?(tchiovoloni)
Yep, it happens in other browsers as well. That said, while I'm certainly not an expert in this area, I just wrote a small test to see if OS X really isn't sending the keyup event in these cases, and as far as I can tell it is. If you make a new Cocoa project in xcode, and replace the default applicationDidFinishLaunching with this: https://gist.github.com/thomcc/6f41cd2043130319c8dc3af4e8701ee4, and look at the log, you can clearly see both keydown and keyup getting fired even when the cmd key is depressed. Of course, it's completely possible I'm missing some nuance here (certainly our input handling is more sophisticated than my test), in which case I guess you can feel free to resolve as invalid, but it would be a shame to keep a bug like this just because it exists elsewhere, especially when it makes implementing input polling (or other types of input handling) robustly from JavaScript more-or-less impossible -- not receiving the keyup event, or *any* event when keyup occurs isn't exactly something you can work around.
Flags: needinfo?(tchiovoloni)
So, anything we'd like to do here?
Flags: needinfo?(masayuki)
Um, I'm not sure. I'm not so familiar with Cocoa's behavior. I guess that replying some messages from Cocoa or existing native menu causes not reaching keyup event to browsers. Anyway, this shouldn't be a big problem for web developers because: * keyup event shouldn't be used in most cases. keyup event indicates physical key state, so, it doesn't indicate what is expected by the user. * keyup event can be fired without keydown event. For example, while you press a key in another application and activate a browser window with a pointing device and then, release the key, in such case, keyup event is fired alone and such event shouldn't be handled by web applications. So, keyup event isn't a good way to assume as a user's operation.
Flags: needinfo?(masayuki)
Component: DOM: Events → Widget: Cocoa
(In reply to Masayuki Nakano [:masayuki] (Mozilla Japan) (Offline: 9/19, 9/22-9/25, 9/28)) from comment #6) > Um, I'm not sure. I'm not so familiar with Cocoa's behavior. I guess that > replying some messages from Cocoa or existing native menu causes not > reaching keyup event to browsers. > > Anyway, this shouldn't be a big problem for web developers because: > > * keyup event shouldn't be used in most cases. keyup event indicates > physical key state, so, it doesn't indicate what is expected by the user. It depends on what you're doing. For documents, web apps, etc. this is probably true, those applications almost always should be listening to a different event. But for browser-based games, being able to poll the current input state during each animation frame is more or less required for anything sophisticated. While games on the web are still a bit of an edge case for browser applications, I worked on them at my last job and so I do feel like their support is worthwhile. To be clear, yes, it's about the physical key state, but that's exactly what you're unable to properly model if you drop a keyup and there's no event you can listen to as a workaround. > * keyup event can be fired without keydown event. For example, while you > press a key in another application and activate a browser window with a > pointing device and then, release the key, in such case, keyup event is > fired alone and such event shouldn't be handled by web applications. A lone keyup event is very easy to handle without other issues. The inverse case (e.g. keydown event occurs, user leaves the window, releases the key) is similarly easy to handle properly by clearing what you think the current input state is in a blur event handler on the window. While it's true this isn't flawless (they may come back before releasing the key), that's a fairly rare edge case that doesn't cause many problems in practice (IME, at least). All that said, I wouldn't argue this is a particularly high priority since the applications where this can cause issues are less common, but they're certainly not all misguided cases where the developer is doing something bad.
(In reply to Thom Chiovoloni [:tcsc] from comment #7) > But for browser-based games, being able to poll the current input state > during each animation frame is more or less required for anything > sophisticated. While games on the web are still a bit of an edge case for > browser applications, I worked on them at my last job and so I do feel like > their support is worthwhile. Ah, games... But is key combination with Command key used by games? And also meta key is (will be, see bug 1232918) mapped to Windows Log keys. So, basically, key combinations with meta key shouldn't be handled on web apps except at implementing shortcut keys for Mac users...
(In reply to Masayuki Nakano [:masayuki] (Mozilla Japan) (Offline: 9/19, 9/22-9/25, 9/28)) from comment #8) > (In reply to Thom Chiovoloni [:tcsc] from comment #7) > > But for browser-based games, being able to poll the current input state > > during each animation frame is more or less required for anything > > sophisticated. While games on the web are still a bit of an edge case for > > browser applications, I worked on them at my last job and so I do feel like > > their support is worthwhile. > > Ah, games... But is key combination with Command key used by games? And also > meta key is (will be, see bug 1232918) mapped to Windows Log keys. So, > basically, key combinations with meta key shouldn't be handled on web apps > except at implementing shortcut keys for Mac users... Not typically, however it's not the command key that's dropped, so if the game has focus, and the user enters a key combination with a key that is used by the game, you end up with a stuck key in the game, which looks really, well, bad.
Whiteboard: tpi:?
Priority: -- → P2
Whiteboard: tpi:? → tpi:+
Just wanted to drop a note here and let you know that I just ran into this issue in a game I'm building right now.
Priority: P2 → P3

Moving all keyboard/IME handling bugs to DOM: UI Events & Focus Handling component.

Component: Widget: Cocoa → DOM: UI Events & Focus Handling
OS: Unspecified → macOS
Priority: P3 → P5
Hardware: Unspecified → x86_64
Summary: Keyup event dropped on mac if cmd/meta key is pressed. → [Cocoa] Keyup events are not fired if cmd/meta key is pressed
Severity: normal → S3

Any chance to solve this issue?

Is there other way to implement reliable shortcuts? Any suggestions?

For example I am building editor and I cannot use cmd+1, cmd+2 to switch between modes. I need to release key every time for shortcuts to work.

We don't have any chance to fire keyup event since macOS does not notify the timing and fact to native apps. And basically, apps should handle at keydown rather than keyup for shortcut keys. One of special cases at keyup is hiding popups which is shown at keydown, though.

I'm afraid that is incorrect. We know from TigerVNC that the OS will fire an event for this scenario just fine.

I would guess that the event gets gobbled up somewhere in Firefox' shortcut handling code, even if there is no shortcut bound to that combination.

All native key up events come here first:
https://searchfox.org/mozilla-central/rev/26790fecfcda622dab234b28859da721b80f3a35/widget/cocoa/TextInputHandler.mm#1883-1892

Therefore, you can check the OS's behavior with MOZ_LOG=KeyboardHandler:3,sync (see also about:logging). (I've not checked recent macOS's behavior, however, we don't have any filter to discard only some keyup events.)

That looks deep inside the code, and not at the start of where events enter the application. You can test TigerVNC with the arguments -Log \*:stderr:100 and you can see that it has no problem catching this key release event.

As for the technical details, it catches events early in the chain by overriding [NSApplication sendEvent:]:

https://github.com/fltk/fltk/blob/390f530abb4074e06f69bb9bc07031e6a4492f7b/src/Fl_cocoa.mm#L1823

Where the event is then passed along to the application code:

https://github.com/fltk/fltk/blob/390f530abb4074e06f69bb9bc07031e6a4492f7b/src/Fl_cocoa.mm#L1826
https://github.com/TigerVNC/tigervnc/blob/57cdcedf1bde06195f782fd2cfcf302050245da6/vncviewer/Viewport.cxx#L937
https://github.com/TigerVNC/tigervnc/blob/57cdcedf1bde06195f782fd2cfcf302050245da6/vncviewer/Viewport.cxx#L1133

You need to log in before you can comment on or make changes to this bug.