Improve Cocoa modifier key handling
I had two problems with QEMU on macOS: 1) Sometimes when alt-tabbing to QEMU it would act as if the 'a' key was pressed so I'd get 'aaaaaaaaa....'. 2) Using Sikuli to programatically send keys to the QEMU window text like "foo_bar" would come out as "fooa-bar". They looked similar and after much digging the problem turned out to be the same. When QEMU's ui/cocoa.m received an NSFlagsChanged NSEvent it looked at the keyCode to determine what modifier key changed. This usually works fine but sometimes the keyCode is 0 and the app should instead be looking at the modifierFlags bitmask. Key code 0 is the 'a' key. I added code that handles keyCode == 0 differently. It checks the modifierFlags and if they differ from QEMU's idea of which modifier keys are currently pressed it toggles those changed keys. This fixes my problems and seems work fine. Signed-off-by: Ian McKellar <ianloic@google.com> Message-id: 20170526233816.47627-1-ianloic@google.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
3f0602927b
commit
af8862b2a2
60
ui/cocoa.m
60
ui/cocoa.m
@ -52,6 +52,8 @@
|
|||||||
/* macOS 10.12 deprecated many constants, #define the new names for older SDKs */
|
/* macOS 10.12 deprecated many constants, #define the new names for older SDKs */
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
|
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
|
||||||
#define NSEventMaskAny NSAnyEventMask
|
#define NSEventMaskAny NSAnyEventMask
|
||||||
|
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
|
||||||
|
#define NSEventModifierFlagShift NSShiftKeyMask
|
||||||
#define NSEventModifierFlagCommand NSCommandKeyMask
|
#define NSEventModifierFlagCommand NSCommandKeyMask
|
||||||
#define NSEventModifierFlagControl NSControlKeyMask
|
#define NSEventModifierFlagControl NSControlKeyMask
|
||||||
#define NSEventModifierFlagOption NSAlternateKeyMask
|
#define NSEventModifierFlagOption NSAlternateKeyMask
|
||||||
@ -268,7 +270,7 @@ static void handleAnyDeviceErrors(Error * err)
|
|||||||
NSWindow *fullScreenWindow;
|
NSWindow *fullScreenWindow;
|
||||||
float cx,cy,cw,ch,cdx,cdy;
|
float cx,cy,cw,ch,cdx,cdy;
|
||||||
CGDataProviderRef dataProviderRef;
|
CGDataProviderRef dataProviderRef;
|
||||||
int modifiers_state[256];
|
BOOL modifiers_state[256];
|
||||||
BOOL isMouseGrabbed;
|
BOOL isMouseGrabbed;
|
||||||
BOOL isFullscreen;
|
BOOL isFullscreen;
|
||||||
BOOL isAbsoluteEnabled;
|
BOOL isAbsoluteEnabled;
|
||||||
@ -536,18 +538,59 @@ QemuCocoaView *cocoaView;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) toggleModifier: (int)keycode {
|
||||||
|
// Toggle the stored state.
|
||||||
|
modifiers_state[keycode] = !modifiers_state[keycode];
|
||||||
|
// Send a keyup or keydown depending on the state.
|
||||||
|
qemu_input_event_send_key_qcode(dcl->con, keycode, modifiers_state[keycode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) toggleStatefulModifier: (int)keycode {
|
||||||
|
// Toggle the stored state.
|
||||||
|
modifiers_state[keycode] = !modifiers_state[keycode];
|
||||||
|
// Generate keydown and keyup.
|
||||||
|
qemu_input_event_send_key_qcode(dcl->con, keycode, true);
|
||||||
|
qemu_input_event_send_key_qcode(dcl->con, keycode, false);
|
||||||
|
}
|
||||||
|
|
||||||
- (void) handleEvent:(NSEvent *)event
|
- (void) handleEvent:(NSEvent *)event
|
||||||
{
|
{
|
||||||
COCOA_DEBUG("QemuCocoaView: handleEvent\n");
|
COCOA_DEBUG("QemuCocoaView: handleEvent\n");
|
||||||
|
|
||||||
int buttons = 0;
|
int buttons = 0;
|
||||||
int keycode;
|
int keycode = 0;
|
||||||
bool mouse_event = false;
|
bool mouse_event = false;
|
||||||
NSPoint p = [event locationInWindow];
|
NSPoint p = [event locationInWindow];
|
||||||
|
|
||||||
switch ([event type]) {
|
switch ([event type]) {
|
||||||
case NSEventTypeFlagsChanged:
|
case NSEventTypeFlagsChanged:
|
||||||
keycode = cocoa_keycode_to_qemu([event keyCode]);
|
if ([event keyCode] == 0) {
|
||||||
|
// When the Cocoa keyCode is zero that means keys should be
|
||||||
|
// synthesized based on the values in in the eventModifiers
|
||||||
|
// bitmask.
|
||||||
|
|
||||||
|
if (qemu_console_is_graphic(NULL)) {
|
||||||
|
NSEventModifierFlags modifiers = [event modifierFlags];
|
||||||
|
|
||||||
|
if (!!(modifiers & NSEventModifierFlagCapsLock) != !!modifiers_state[Q_KEY_CODE_CAPS_LOCK]) {
|
||||||
|
[self toggleStatefulModifier:Q_KEY_CODE_CAPS_LOCK];
|
||||||
|
}
|
||||||
|
if (!!(modifiers & NSEventModifierFlagShift) != !!modifiers_state[Q_KEY_CODE_SHIFT]) {
|
||||||
|
[self toggleModifier:Q_KEY_CODE_SHIFT];
|
||||||
|
}
|
||||||
|
if (!!(modifiers & NSEventModifierFlagControl) != !!modifiers_state[Q_KEY_CODE_CTRL]) {
|
||||||
|
[self toggleModifier:Q_KEY_CODE_CTRL];
|
||||||
|
}
|
||||||
|
if (!!(modifiers & NSEventModifierFlagOption) != !!modifiers_state[Q_KEY_CODE_ALT]) {
|
||||||
|
[self toggleModifier:Q_KEY_CODE_ALT];
|
||||||
|
}
|
||||||
|
if (!!(modifiers & NSEventModifierFlagCommand) != !!modifiers_state[Q_KEY_CODE_META_L]) {
|
||||||
|
[self toggleModifier:Q_KEY_CODE_META_L];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keycode = cocoa_keycode_to_qemu([event keyCode]);
|
||||||
|
}
|
||||||
|
|
||||||
if ((keycode == Q_KEY_CODE_META_L || keycode == Q_KEY_CODE_META_R)
|
if ((keycode == Q_KEY_CODE_META_L || keycode == Q_KEY_CODE_META_R)
|
||||||
&& !isMouseGrabbed) {
|
&& !isMouseGrabbed) {
|
||||||
@ -559,16 +602,9 @@ QemuCocoaView *cocoaView;
|
|||||||
// emulate caps lock and num lock keydown and keyup
|
// emulate caps lock and num lock keydown and keyup
|
||||||
if (keycode == Q_KEY_CODE_CAPS_LOCK ||
|
if (keycode == Q_KEY_CODE_CAPS_LOCK ||
|
||||||
keycode == Q_KEY_CODE_NUM_LOCK) {
|
keycode == Q_KEY_CODE_NUM_LOCK) {
|
||||||
qemu_input_event_send_key_qcode(dcl->con, keycode, true);
|
[self toggleStatefulModifier:keycode];
|
||||||
qemu_input_event_send_key_qcode(dcl->con, keycode, false);
|
|
||||||
} else if (qemu_console_is_graphic(NULL)) {
|
} else if (qemu_console_is_graphic(NULL)) {
|
||||||
if (modifiers_state[keycode] == 0) { // keydown
|
[self toggleModifier:keycode];
|
||||||
qemu_input_event_send_key_qcode(dcl->con, keycode, true);
|
|
||||||
modifiers_state[keycode] = 1;
|
|
||||||
} else { // keyup
|
|
||||||
qemu_input_event_send_key_qcode(dcl->con, keycode, false);
|
|
||||||
modifiers_state[keycode] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user