qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] keyboard shift-state problem


From: Mark Jonckheere
Subject: [Qemu-devel] keyboard shift-state problem
Date: Tue, 18 May 2004 02:21:39 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020408

When the operator switches from qemu to another window while keeping one
of the shift-keys (Shift, Ctrl, Alt) depressed (for example using Alt-TAB),
qemu doesn't receive a Key-UP event for this shift-key. The result is that
when the operator returns back to qemu, the guest OS accepts new keystrokes
as if that shift-key is still depressed.

A solution to this problem is storing the shift-state as every shift-key
is depressed and released, and sending extra key-events when control is
transferred to another window.

I detected that in this case SDL sends a keyboard event with a zero
scancode, so it is easy to detect when the shift-state should be adjusted.

This has been tested on a RedHat 7.3 host (x86) with SDL version
1.2.3-7, it should be verified for other host environments.

A second problem is the CapsLock and Numlock state. I detected that
SDL handles these keys as shift-keys and not as toggles. Depressing
and releasing one of those keys generates only a single event with
alternating key down and key up codes. To turn CapsLock on and again
off, you had to depress that key 4 times. I made a modification to
translate this single event into a key-down, key-up sequence.

This works well for CapsLock, but it can put NumLock into the opposite
state between the host OS and the guest OS. This results in depressing
the NumLock key by the operator at every switch between windows.

There is no simple solution for this problem. One possible solution is
to keep track of the commands from the guest OS to change the state of
the keyboard LEDs and change the state of the host according to these.

Or keeping track of the guest Numlock LED and sending back a Numlock
down-up sequence before each key if the state is different from the host
state.

Another solution is to add a command to change the NumLock state
from the monitor.

Or simply leaving it as it was and documenting to the end-user
that "To change the Numlock or CapsLock state, you should depress
those keys twice".


Greetings,
Mark.


---8<----------------------------------------------------->8---
--- qemu/sdl.c  Fri Apr 30 00:15:15 2004
+++ qemu.patched/sdl.c  Tue May 18 00:34:19 2004
@@ -130,6 +130,7 @@
 static void sdl_process_key(SDL_KeyboardEvent *ev)
 {
     int keycode, v;
+    static int modif;

     /* XXX: not portable, but avoids complicated mappings */
     keycode = ev->keysym.scancode;
@@ -151,6 +152,78 @@
         keycode = 0;
     }

+    /* Adjust shift-key states when leaving window */
+
+    if (ev->keysym.scancode == 0) {
+        if ((modif ^ ev->keysym.mod) & KMOD_LSHIFT)
+            kbd_put_keycode(0x2a | (modif & KMOD_LSHIFT ? 0x80 : 0));
+        if ((modif ^ ev->keysym.mod) & KMOD_RSHIFT)
+            kbd_put_keycode(0x36 | (modif & KMOD_RSHIFT ? 0x80 : 0));
+        if ((modif ^ ev->keysym.mod) & KMOD_LCTRL)
+            kbd_put_keycode(0x1d | (modif & KMOD_LCTRL ? 0x80 : 0));
+        if ((modif ^ ev->keysym.mod) & KMOD_RCTRL) {
+            kbd_put_keycode(0xe0 );
+            kbd_put_keycode(0x1d | (modif & KMOD_RCTRL ? 0x80 : 0));
+        }
+        if ((modif ^ ev->keysym.mod) & KMOD_LALT)
+            kbd_put_keycode(0x38 | (modif & KMOD_LALT ? 0x80 : 0));
+        if ((modif ^ ev->keysym.mod) & KMOD_RALT) {
+            kbd_put_keycode(0xe0 );
+            kbd_put_keycode(0x38 | (modif & KMOD_RALT ? 0x80 : 0));
+        }
+        modif = ev->keysym.mod;
+    }
+
+    /* remember shift-key state */
+
+    switch (keycode) {
+    case 0x2a:                          /* Left Shift */
+        if (ev->type == SDL_KEYUP)
+            modif &= ~KMOD_LSHIFT;
+        else
+            modif |= KMOD_LSHIFT;
+        break;
+    case 0x36:                          /* Right Shift */
+        if (ev->type == SDL_KEYUP)
+            modif &= ~KMOD_RSHIFT;
+        else
+            modif |= KMOD_RSHIFT;
+        break;
+    case 0x1d:                          /* Left CTRL */
+        if (ev->type == SDL_KEYUP)
+            modif &= ~KMOD_LCTRL;
+        else
+            modif |= KMOD_LCTRL;
+        break;
+    case 0x1de0:                        /* Right CTRL */
+        if (ev->type == SDL_KEYUP)
+            modif &= ~KMOD_RCTRL;
+        else
+            modif |= KMOD_RCTRL;
+        break;
+    case 0x38:                          /* Left ALT */
+        if (ev->type == SDL_KEYUP)
+            modif &= ~KMOD_LALT;
+        else
+            modif |= KMOD_LALT;
+        break;
+    case 0x38e0:                        /* Right ALT */
+        if (ev->type == SDL_KEYUP)
+            modif &= ~KMOD_RALT;
+        else
+            modif |= KMOD_RALT;
+        break;
+    case 0x45:                          /* Num Lock */
+        kbd_put_keycode(0x45);
+        kbd_put_keycode(0xc5);
+        return;
+    case 0x3a:                          /* Caps Lock */
+        kbd_put_keycode(0x3a);
+        kbd_put_keycode(0xba);
+        return;
+
+    }
+
     /* now send the key code */
     while (keycode != 0) {
         v = keycode & 0xff;
---8<----------------------------------------------------->8---





reply via email to

[Prev in Thread] Current Thread [Next in Thread]