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 <programmingk...@gmail.com>

---
 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\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);
 }
+
+
-- 
1.7.5.4


Reply via email to