This patch adds the ability to use the command key in the guest
operating system. Just add -command-key 55 to the command line
options sent to QEMU to use this feature.
I have checked the patch by sending it thru
checkpatch.pl this time. I also made a bunch of style changes to more closely match QEMU's suggested coding style.
---
ui/cocoa.m | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 104 insertions(+), 10 deletions(-)
diff --git a/ui/cocoa.m b/ui/cocoa.m
index be49179..99d65bf 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -70,6 +70,7 @@ static DisplayChangeListener *dcl;
int gArgc;
char **gArgv;
+bool substituting_for_command_key = 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
+ 219, // 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 new_command_key_button_value, i;
+
+ #define BUFFER_SIZE 10
+ #define LEFT_COMMAND_KEY 0x37
+ #define RIGHT_COMMAND_KEY 0x36
+ #define GUEST_COMMAND_KEY 219
+
+ char key_value_string[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(key_value_string, BUFFER_SIZE, "%s", argv[i+1]);
+ if(strlen(key_value_string) == 0) {
+ printf("Usage: -command-key <host keyboard key value>\n");
+ exit(-1000);
+ }
+
+ // if using hexadecimal notation (e.g. 0x37)
+ if(key_value_string[0] == '0' && toupper(key_value_string[1]) == 'X') {
+ sscanf(key_value_string, "%x", &new_command_key_button_value);
+ }
+
+ // for decimal notation
+ else {
+ new_command_key_button_value = atoi(key_value_string);
+ }
+
+ //in case the key specified is a negative value
+ if(new_command_key_button_value < 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(new_command_key_button_value == LEFT_COMMAND_KEY || new_command_key_button_value == RIGHT_COMMAND_KEY) {
+ substituting_for_command_key = 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[new_command_key_button_value] = 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,6 +558,11 @@ 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 substitute_key_mask = NSAlternateKeyMask;
+
switch ([event type]) {
case NSFlagsChanged:
keycode = cocoa_keycode_to_qemu([event keyCode]);
@@ -499,12 +571,13 @@ QemuCocoaView *cocoaView;
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;
}
@@ -517,13 +590,33 @@ QemuCocoaView *cocoaView;
}
break;
case NSKeyDown:
+ // if substituting for the host command key and the substitute key is being held down - have QEMU handle it
+ if((substituting_for_command_key == true) && ([event modifierFlags] & substitute_key_mask)) {
+ // recreate the event with the command key as the modifier
+ int modifiers = [event modifierFlags];
+ modifiers = modifiers | NSCommandKeyMask; // set the command key
+ modifiers = modifiers ^ substitute_key_mask; // 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 && substituting_for_command_key == 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) && (substituting_for_command_key == 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]);
@@ -584,7 +677,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:
@@ -812,6 +905,7 @@ QemuCocoaView *cocoaView;
COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
int status;
+ handleCommandKeyOption(&argc, argv);
status = qemu_main(argc, argv, *_NSGetEnviron());
exit(status);
}
@@ -1046,4 +1140,4 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
// register cleanup function
atexit(cocoa_cleanup);
-}
+}
\ No newline at end of file
--
1.7.5.4