[Interest] Qt/Mac low-level hacking: key mapping and NSMenuFunctionKey
René J.V. Bertin
rjvbertin at gmail.com
Sun Jan 29 15:28:29 CET 2017
Hello,
Not long ago I asked about support (on Mac) for opening context menus via the keyboard. I was told there is none, so I dug around in the Qt sources for a bit myself. I discovered quite quickly that there is a NSMenuFunctionKey (defined in the system SDKs) that is taken into account in the Cocoa platform plugin, and mapped to Qt::Key_Menu .
I have now tinkered with the idea of intercepting keyboard events with a local NSEvent monitor (set in a style plugin for now), which catches events corresponding to a press of the right Option (Alt) key and replaces them with a synthetic event emulating a press of the Menu key:
const unichar menuKeyCode = static_cast<unichar>(NSMenuFunctionKey);
NSString *menuKeyString = [NSString stringWithCharacters:&menuKeyCode length:1];
NSEvent *menuKeyEvent = [NSEvent keyEventWithType:NSKeyDown
location:[event locationInWindow] modifierFlags:([event modifierFlags] & ~NSAlternateKeyMask)
timestamp:[event timestamp] windowNumber:[event windowNumber]
context:nil characters:menuKeyString charactersIgnoringModifiers:menuKeyString isARepeat:NO
// the keyCode must be an 8-bit value so not to be confounded with the Unicode value.
// Judging from Carbon/Events.h 0x7f is unused.
keyCode:0x7f];
qWarning() << "new event:" << QString::fromNSString([menuKeyEvent description]);
return menuKeyEvent;
The principle seems to work when I emulate a common function key like Home, but it doesn't work for NSMenuFunctionKey. Part of the problem is probably that I have no way of knowing what keycode to insert, but there's something else which appears to go wrong in qcocoakeymapper.mm
With the event created as shown above, QCocoaKeyMapper::updateKeyMap() is called as follows:
qWarning("updateKeyMap for virtual key = 0x%02x unicodeKey=0x%04x!", (uint)macVirtualKey, unicodeKey);
> updateKeyMap for virtual key = 0x7f unicodeKey=0x1000055!
That corresponds to my event (enum Key in qnamespace.h). Evidently (?), UCKeyTranslate() fails for this combination, so qt_mac_get_key() is called with the input unicodeKey and macVirtualKey parameters. However, that function returns the letter 'U' for this input, and with DEBUG_KEY_BINDINGS set we can see why:
> **Mapping key: 85 (0x0055) - 61 (0x003d)
> 287: got key: 20
But why would qWarning("%04x", unicodeKey) print 0x1000055 and qWarning("%04x", unicodeKey.unicode()) print 0x0055 if a QChar's actual value is stored as `ushort ucs`??
By contrast, this is the output for a real event when pressing F1:
> updateKeyMap for virtual key = 0x7a unicodeKey=0x1000030!
> **Mapping key: 16 (0x0010) - 122 (0x007a)
> 319: got key: Qt::Key_F1
In short, I must manage to get qt_mac_get_key() to fall through to its final loop where it checks "if they belong to key codes in private unicode range". Any suggestions how I can get there without patching qcocoakeymapper.mm ? Has anyone ever been able to test this particular case/configuration with a keyboard that does have a Menu key, or with a system keymap that generates actual NSMenuFunctionKey strokes (or a properly configured ~/Library/KeyBindings/DefaultKeyBinding.dict)?
Thanks,
René
More information about the Interest
mailing list