From patchwork Fri May 26 23:38:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Denis V. Lunev\" via" X-Patchwork-Id: 9751249 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4AF7860249 for ; Fri, 26 May 2017 23:39:22 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2DD03280CF for ; Fri, 26 May 2017 23:39:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2044128459; Fri, 26 May 2017 23:39:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id DE905280CF for ; Fri, 26 May 2017 23:39:20 +0000 (UTC) Received: from localhost ([::1]:38895 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dEOpD-0006G8-Js for patchwork-qemu-devel@patchwork.kernel.org; Fri, 26 May 2017 19:39:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60971) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dEOoc-0006Fs-3Q for qemu-devel@nongnu.org; Fri, 26 May 2017 19:38:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dEOoZ-00013q-0B for qemu-devel@nongnu.org; Fri, 26 May 2017 19:38:42 -0400 Received: from mail-pg0-x22b.google.com ([2607:f8b0:400e:c05::22b]:36090) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dEOoY-00013j-Nv for qemu-devel@nongnu.org; Fri, 26 May 2017 19:38:38 -0400 Received: by mail-pg0-x22b.google.com with SMTP id x64so144015pgd.3 for ; Fri, 26 May 2017 16:38:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=/0Xb6FJkB3cDyZp/tLzldjbJIbPytOB3zl7YcCuDJF4=; b=lHAATvpmSqJ0zsPB/GP4sXIaLV+T56amyQMmx1P6a1fgAUmhj82MRKyIEIB+1jsdRx dQbzrQnMheGE4rns1gczoMcVZ1/QCG37sz0U6jci7r0J1dprwks6kYJ6EerNFZsv2R1u +QA/o+jvp1wr2CJ4p80nD4xNGkCJyVTnL4MYpPmeosMeJ5IeLy9n69eL0ApEKqsD4w9Z pVKFVaIcsErFxkT9THy/pAk7In/j9jUTdls4N3wBUMh6nY54n6cu912WsTXazqA24Hp3 2YW2Hr38xVwJzSGEBThGwjqLgNkMfJN7rsfCOkGQ/61Ik+jcxCTjoE0dSI8ydQ4ZXoY0 5ByA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=/0Xb6FJkB3cDyZp/tLzldjbJIbPytOB3zl7YcCuDJF4=; b=LBrc51Wpo/I89AZea7chrho0wE5SxdPpJFkip4IfNhW9qk2DI4bsEeyU5KhTA/6iF/ 0/jukpZAhGWJhCrc/12S/03kkM968ZKgIBgRpSQkVaTJPnukbbXGy6KefC+NyaG0mafA UPBhFW2oeV12dv5nu8IFzWklmKwSbDigI5lkY9EzdBdpWDkEE1CVi89wvzmmYpLs+oLy qJMmZsXSsYCKvDRJCbW6dx9ZTvJ63sU1P2aI2Yf/PQdgWKC5Pojabf/0mI1d+EPJyCwT rqG1trh9iKcyuqAB2mMgDIZZ51TNG7MtSKz07GrJ9MUZJ3YgGz35phGwJna3lciM9n/R Xq5Q== X-Gm-Message-State: AODbwcBqgfNjBXQAF4HuM3WVPuCjySE9VRtwKl9bb/ka+xxtJDabT2V5 p7yTJm6s+ghhSRt56cQwVw== X-Received: by 10.99.165.9 with SMTP id n9mr5446790pgf.233.1495841916772; Fri, 26 May 2017 16:38:36 -0700 (PDT) Received: from ianloic-macbookpro2.roam.corp.google.com.com ([100.118.184.234]) by smtp.gmail.com with ESMTPSA id p4sm3901573pfj.104.2017.05.26.16.38.35 (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 26 May 2017 16:38:35 -0700 (PDT) To: qemu-devel@nongnu.org Date: Fri, 26 May 2017 16:38:16 -0700 Message-Id: <20170526233816.47627-1-ianloic@google.com> X-Mailer: git-send-email 2.13.0.rc1.294.g07d810a77f-goog X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::22b Subject: [Qemu-devel] [PATCH] Improve Cocoa modifier key handling X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Ian McKellar via Qemu-devel From: "Denis V. Lunev\" via" Reply-To: Ian McKellar Cc: kraxel@redhat.com, Ian McKellar Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 NSEventModifierFlagShift NSShiftKeyMask #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 toggleStatefulModifier:keycode]; } 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]; } }