From patchwork Fri Jul 12 20:41:48 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Programmingkid X-Patchwork-Id: 258798 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C1C1A2C0349 for ; Sat, 13 Jul 2013 06:42:14 +1000 (EST) Received: from localhost ([::1]:60797 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UxkAO-0008FS-8P for incoming@patchwork.ozlabs.org; Fri, 12 Jul 2013 16:42:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34685) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UxkA6-0008F2-Bw for qemu-devel@nongnu.org; Fri, 12 Jul 2013 16:41:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UxkA4-000231-QH for qemu-devel@nongnu.org; Fri, 12 Jul 2013 16:41:54 -0400 Received: from mail-qe0-x233.google.com ([2607:f8b0:400d:c02::233]:62791) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UxkA4-00022s-KE for qemu-devel@nongnu.org; Fri, 12 Jul 2013 16:41:52 -0400 Received: by mail-qe0-f51.google.com with SMTP id a11so5438267qen.10 for ; Fri, 12 Jul 2013 13:41:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:content-type:content-transfer-encoding:subject:date:message-id :to:mime-version:x-mailer; bh=biB6n0zuxhn/xB/Uo6WAc6xHvffVeqvVbXIFJszI7rQ=; b=YLqPKG99pQo9LQeKl/UXySsvq3Ui/sIDFnvHvAIAWGMOuTorNUzpX6oTN2GzfoOvPS OoFMFad9cnnVZpOYKW9va5FxU9fNb1fJ8wUyfImfg0SFR4xYpgRL4gkWC6euqfoft0Wc Xlgzsc6rLk8AlNiEhKZugu8RiZ57vPn8nlwXXKHHLnKvBgnF0PgLrDTwrqD5C/AOOGJ1 82qQyO4Gd62cbutDs6EWibOc3swLXm03Jl6zTpMBgaIMRbZuNeb8raLIRDVknBorEZth trhHgogKuTg/+izoS7tcaIjoUT0df2OJG8m3ge4yiRYuyz/1tLJfZBfncqZUM9wJkWt1 FLGQ== X-Received: by 10.49.6.6 with SMTP id w6mr35961394qew.44.1373661711464; Fri, 12 Jul 2013 13:41:51 -0700 (PDT) Received: from [192.168.0.3] (d14-69-153-26.try.wideopenwest.com. [69.14.26.153]) by mx.google.com with ESMTPSA id a8sm37108375qae.11.2013.07.12.13.41.49 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 12 Jul 2013 13:41:50 -0700 (PDT) From: Programmingkid Date: Fri, 12 Jul 2013 16:41:48 -0400 Message-Id: To: qemu-devel qemu-devel Mime-Version: 1.0 (Apple Message framework v1084) X-Mailer: Apple Mail (2.1084) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400d:c02::233 Subject: [Qemu-devel] [PATCH] Adds the ability to use the command key in the guest OS. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds the ability to use the command key in the guest OS. This patch will allow you to send keyboard shortcuts to Macintosh applications running in QEMU. signed-off-by: John Arbuckle --- ui/cocoa.m | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 110 insertions(+), 13 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index be49179..4884ccf 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -70,6 +70,7 @@ static DisplayChangeListener *dcl; int gArgc; char **gArgv; +bool substitutingForCommandKey = false; // keymap conversion int keymap[] = @@ -129,8 +130,8 @@ int keymap[] = 14, // 51 0x33 0x0e BKSP QZ_BACKSPACE 0, // 52 0x34 Undefined 1, // 53 0x35 0x01 ESC QZ_ESCAPE - 0, // 54 0x36 QZ_RMETA - 0, // 55 0x37 QZ_LMETA + 220, // 54 0x36 QZ_RMETA + 219, // 55 0x37 QZ_LMETA 42, // 56 0x38 0x2a L SHFT QZ_LSHIFT 58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK 56, // 58 0x3A 0x38 L ALT QZ_LALT @@ -249,6 +250,72 @@ static int cocoa_keycode_to_qemu(int keycode) } +// Used to map the guest OS's command key to a key on the host keyboard. +// Uses the -command-key option. +static void handleCommandKeyOption(int * argc, char * argv[]) +{ + bool foundOption = false; + int newCommandKeyButtonValue, i; + + #define BUFFER_SIZE 10 + #define LEFT_COMMAND_KEY 0x37 + #define RIGHT_COMMAND_KEY 0x36 + #define GUEST_COMMAND_KEY 219 + + char keyValueString[BUFFER_SIZE]; + + for(i = 0; i < *argc; i++) { + if(strcmp(argv[i], "-command-key") == 0) { + foundOption = true; + break; + } + } + + // if the -command-key option is found + if(foundOption == true) + { + snprintf(keyValueString, BUFFER_SIZE, "%s", argv[i+1]); + if(strlen(keyValueString) == 0) { + printf("Usage: -command-key \n"); + printf("This page will help: http://boredzo.org/blog/wp-content/uploads/2007/05/imtx-virtual-keycodes.png\n"); + exit(-1000); + } + + // if using hexadecimal notation (e.g. 0x37) + if(keyValueString[0] == '0' && toupper(keyValueString[1]) == 'X') { + sscanf(keyValueString, "%x", &newCommandKeyButtonValue); + } + + // for decimal notation + else { + newCommandKeyButtonValue = atoi(keyValueString); + } + + //in case the key specified is a negative value + if(newCommandKeyButtonValue < 0) { + printf("\aCan't use a negative value for the command key!\n"); + exit(-1001); + } + + // if the guest OS command key is set to the host keyboard's left or right command key + if(newCommandKeyButtonValue == LEFT_COMMAND_KEY || newCommandKeyButtonValue == RIGHT_COMMAND_KEY) { + substitutingForCommandKey = true; + printf("\nNote: since you are using the host command key, the ALT key can be used to send QEMU commands.\n"); + printf("Example: use ALT-q to quit QEMU.\n\n"); + } + + // do the mapping + keymap[newCommandKeyButtonValue] = GUEST_COMMAND_KEY; + + // Remove -command-key from the argument list. + // QEMU will complain if we don't. + for(int x = i; x < *argc - 2; x=x+2) { + argv[x] = argv[x+2]; + argv[x+1] = argv[x+3]; + } + *argc = *argc - 2; + } +} /* ------------------------------------------------------ @@ -491,20 +558,27 @@ QemuCocoaView *cocoaView; int keycode; NSPoint p = [event locationInWindow]; + // The key used to send QEMU commands (e.g. Quit, Full Screen). + // Change this if you don't like using the ALT key. + // Possible values: NSShiftKeyMask, NSControlKeyMask, NSFunctionKeyMask, NSAlternateKeyMask + const int substituteKeyMask = NSAlternateKeyMask; + switch ([event type]) { case NSFlagsChanged: - keycode = cocoa_keycode_to_qemu([event keyCode]); + keycode = cocoa_keycode_to_qemu([event keyCode]); if (keycode) { if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup kbd_put_keycode(keycode); kbd_put_keycode(keycode | 0x80); } else if (qemu_console_is_graphic(NULL)) { - if (keycode & 0x80) - kbd_put_keycode(0xe0); - if (modifiers_state[keycode] == 0) { // keydown + if (keycode & 0x80) // if keycode >= 0x80, for those keycodes that need a 0xe0 sent first + { + kbd_put_keycode(0xe0); + } + if (modifiers_state[keycode] == 0) { // keydown kbd_put_keycode(keycode & 0x7f); modifiers_state[keycode] = 1; - } else { // keyup + } else { // keyup kbd_put_keycode(keycode | 0x80); modifiers_state[keycode] = 0; } @@ -516,17 +590,37 @@ QemuCocoaView *cocoaView; [self ungrabMouse]; } break; - case NSKeyDown: + case NSKeyDown: + // if substituting for the host command key and the substitute key is being held down - have QEMU handle it + if((substitutingForCommandKey == true) && ([event modifierFlags] & substituteKeyMask)) { + // recreate the event with the command key as the modifier + int modifiers = [event modifierFlags]; + modifiers = modifiers | NSCommandKeyMask; // set the command key + modifiers = modifiers ^ substituteKeyMask; // unset the substitute key + + event = [NSEvent keyEventWithType: [event type] location: [event locationInWindow] modifierFlags: modifiers + timestamp: [event timestamp] windowNumber: [event windowNumber] context: [event context] characters: [event characters] + charactersIgnoringModifiers: [event charactersIgnoringModifiers] isARepeat: [event isARepeat] keyCode: [event keyCode] ]; + [NSApp sendEvent:event]; + return; + } - // forward command Key Combos - if ([event modifierFlags] & NSCommandKeyMask) { + // if the command key is held down and we want QEMU to handle the event - not the guest OS + else if([event modifierFlags] & NSCommandKeyMask && substitutingForCommandKey == false) { [NSApp sendEvent:event]; return; } + // if the command key is held down and we want the guest OS to handle it + if(([event modifierFlags] & NSCommandKeyMask) && (substitutingForCommandKey == true)) { + kbd_put_keycode(219); // command key + kbd_put_keycode(cocoa_keycode_to_qemu([event keyCode])); // any other keys + return; + } + // default keycode = cocoa_keycode_to_qemu([event keyCode]); - + // handle control + alt Key Combos (ctrl+alt is reserved for QEMU) if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { switch (keycode) { @@ -584,7 +678,7 @@ QemuCocoaView *cocoaView; if (qemu_console_is_graphic(NULL)) { if (keycode & 0x80) kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key + kbd_put_keycode(keycode | 0x80); //add 128 (0x80) to signal release of key } break; case NSMouseMoved: @@ -810,8 +904,9 @@ QemuCocoaView *cocoaView; - (void)startEmulationWithArgc:(int)argc argv:(char**)argv { COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n"); - + int status; + handleCommandKeyOption(&argc, argv); status = qemu_main(argc, argv, *_NSGetEnviron()); exit(status); } @@ -1047,3 +1142,5 @@ void cocoa_display_init(DisplayState *ds, int full_screen) // register cleanup function atexit(cocoa_cleanup); } + +