Over half a year ago there was talk about making the command key work on QEMU. I have finally made a patch that allows users of QEMU on Mac OS X be able to do this. Just apply the patch to QEMU to make the command key work.
You set the command key by using this option: -command-key 55. This will make the command key work in QEMU. To quit QEMU, type ALT - Q.
Let me know if you like it.
--- 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 <host keyboard key value>\n"); + printf("This page will help: http://boredzo.org/blog/wp-content/uploads/2007/05/imtx-virtual-keycodes.png..."); + 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); } + +