Patchwork Adds the ability to use the command key in the guest OS.

login
register
mail settings
Submitter G 3
Date July 12, 2013, 8:41 p.m.
Message ID <F51CACE0-E635-4DF5-920C-C470CBD7D599@gmail.com>
Download mbox | patch
Permalink /patch/258798/
State New
Headers show

Comments

G 3 - July 12, 2013, 8:41 p.m.
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 <programmingkidx@gmail.com>

---
 ui/cocoa.m |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 110 insertions(+), 13 deletions(-)

Patch

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