[Qemu-devel] [PATCH 1/1] Improve Cocoa modifier key handling

2017-05-13 Thread Ian McKellar via Qemu-devel
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 'a'.
 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.

The patch itself is an attachment.

Ian


0001-Improve-Cocoa-modifier-key-handling.patch
Description: Binary data


[Qemu-devel] [PATCH 1/1] Improve Cocoa modifier key handling

2017-05-22 Thread Ian McKellar via Qemu-devel
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 'a'.
 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 
---
 ui/cocoa.m | 48 
 1 file changed, 40 insertions(+), 8 deletions(-)

diff --git a/ui/cocoa.m b/ui/cocoa.m
index 207555edf7..e645befa13 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -52,6 +52,8 @@
 /* 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
 #define NSEventMaskAny  NSAnyEventMask
+#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
+#define NSEventModifierFlagShiftNSShiftKeyMask
 #define NSEventModifierFlagCommand  NSCommandKeyMask
 #define NSEventModifierFlagControl  NSControlKeyMask
 #define NSEventModifierFlagOption   NSAlternateKeyMask
@@ -536,6 +538,16 @@ QemuCocoaView *cocoaView;
 }
 }
 
+- (void) toggleModifier: (int)keycode {
+if (modifiers_state[keycode] == 0) { // keydown
+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;
+}
+}
+
 - (void) handleEvent:(NSEvent *)event
 {
 COCOA_DEBUG("QemuCocoaView: handleEvent\n");
@@ -547,7 +559,33 @@ QemuCocoaView *cocoaView;
 
 switch ([event type]) {
 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 toggleModifier: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)
&& !isMouseGrabbed) {
@@ -562,13 +600,7 @@ QemuCocoaView *cocoaView;
 qemu_input_event_send_key_qcode(dcl->con, keycode, true);
 qemu_input_event_send_key_qcode(dcl->con, keycode, false);
 } else if (qemu_console_is_graphic(NULL)) {
-if (modifiers_state[keycode] == 0) { // keydown
-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;
-}
+  [self toggleModifier:keycode];
 }
 }
 
-- 
2.11.0.390.gc69c2f50cf-goog




Re: [Qemu-devel] [PATCH 1/1] Improve Cocoa modifier key handling

2017-05-23 Thread Ian McKellar via Qemu-devel
On Tue, May 23, 2017 at 3:03 AM Gerd Hoffmann  wrote:

> Sounds like this happens in case there is a modifier state change
> without linked key event, such as state change while qemu did not have
> the keyboard focus.  Nice that macos sends notifications in that case.
>

Yeah, I guess it makes sense to send an event to update modifier state when
keyboard focus returns.

>
> I'm wondering whenever we should just use modifierFlags all the time.
>

Probably. My initial patch tried to be minimally intrusive but I can try
reworking the NSEventTypeFlagsChanged handling to compare the new
modifierFlags to the last we've seen and synthesize the appropriate key
down/up events.

Ian


Re: [Qemu-devel] [PATCH 1/1] Improve Cocoa modifier key handling

2017-05-23 Thread Ian McKellar via Qemu-devel
On Tue, May 23, 2017 at 8:52 AM Ian McKellar  wrote:

> On Tue, May 23, 2017 at 3:03 AM Gerd Hoffmann  wrote:
>
>>
>> I'm wondering whenever we should just use modifierFlags all the time.
>>
>
> Probably. My initial patch tried to be minimally intrusive but I can try
> reworking the NSEventTypeFlagsChanged handling to compare the new
> modifierFlags to the last we've seen and synthesize the appropriate key
> down/up events.
>
> After a little more experimentation I think that the approach in this
patch is the right one. modifierFlags doesn't[1] indicate which instance of
a modifier (ie: left or right) is being held. Except for
the NSEventTypeFlagsChanged that's synthesized when a window takes focus
the event's keyCode indicates which physical key is affected. That first
event after focus has keyCode==0 which we can detect because 0 is the
keyCode of the 'A' key which isn't a modifier.

Ian

[1] actually there are undocumented flags outside the
NSEventModifierFlagDeviceIndependentFlagsMask mask that indicate left/right
keys but I don't think we should use them.


[Qemu-devel] [PATCH] Improve Cocoa modifier key handling

2017-05-26 Thread Ian McKellar via Qemu-devel
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 'a'.
 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 
---
 ui/cocoa.m | 60 
 1 file changed, 48 insertions(+), 12 deletions(-)

diff --git a/ui/cocoa.m b/ui/cocoa.m
index 207555edf7..e89020929b 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -52,6 +52,8 @@
 /* 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
 #define NSEventMaskAny  NSAnyEventMask
+#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
+#define NSEventModifierFlagShiftNSShiftKeyMask
 #define NSEventModifierFlagCommand  NSCommandKeyMask
 #define NSEventModifierFlagControl  NSControlKeyMask
 #define NSEventModifierFlagOption   NSAlternateKeyMask
@@ -268,7 +270,7 @@ static void handleAnyDeviceErrors(Error * err)
 NSWindow *fullScreenWindow;
 float cx,cy,cw,ch,cdx,cdy;
 CGDataProviderRef dataProviderRef;
-int modifiers_state[256];
+BOOL modifiers_state[256];
 BOOL isMouseGrabbed;
 BOOL isFullscreen;
 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
 {
 COCOA_DEBUG("QemuCocoaView: handleEvent\n");
 
 int buttons = 0;
-int keycode;
+int keycode = 0;
 bool mouse_event = false;
 NSPoint p = [event locationInWindow];
 
 switch ([event type]) {
 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)
&& !isMouseGrabbed) {
@@ -559,16 +602,9 @@ QemuCocoaView *cocoaView;
 // emulate caps lock and num lock keydown and keyup
 if (keycode == Q_KEY_CODE_CAPS_LOCK ||
 keycode == Q_KEY_CODE_NUM_LOCK) {
-qemu_input_event_send_key_qcode(dcl->con, keycode, true);
-qemu_input_event_send_key_qcode(dcl->con, keycode, false);
+[self toggleSt

Re: [Qemu-devel] [PATCH 1/1] Improve Cocoa modifier key handling

2017-05-26 Thread Ian McKellar via Qemu-devel
Sent another patch that does a better job of toggling caps-lock. I couldn't
make it fail with the old patch but I think the new patch is somewhat
better.

Ian

On Tue, May 23, 2017 at 11:17 PM Gerd Hoffmann  wrote:

>   Hi,
>
> > After a little more experimentation I think that the approach in this
> > patch is the right one. modifierFlags doesn't[1] indicate which
> > instance of a modifier (ie: left or right) is being held.
>
> Ok, makes sense.  One more thing:  I think capslock must be handled
> differently as keydown + keyup toggle state.
>
> cheers,
>   Gerd
>
>