Miscellaneous VNC related fixes from Xen forwarded by Matthew Kent.
authorbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 30 Oct 2007 22:38:53 +0000 (22:38 +0000)
committerbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 30 Oct 2007 22:38:53 +0000 (22:38 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3489 c046a42c-6fe2-441c-8c8c-71466251a162

console.c
keymaps.c
vl.h
vnc.c
vnc_keysym.h

index ff725c2..9d3c2f6 100644 (file)
--- a/console.c
+++ b/console.c
@@ -509,7 +509,7 @@ static void text_console_resize(TextConsole *s)
             c++;
         }
     }
-    free(s->cells);
+    qemu_free(s->cells);
     s->cells = cells;
 }
 
@@ -1167,11 +1167,21 @@ int is_graphic_console(void)
     return active_console->console_type == GRAPHIC_CONSOLE;
 }
 
+void console_color_init(DisplayState *ds)
+{
+    int i, j;
+    for (j = 0; j < 2; j++) {
+        for (i = 0; i < 8; i++) {
+            color_table[j][i] = col_expand(ds, 
+                   vga_get_color(ds, color_table_rgb[j][i]));
+        }
+    }
+}
+
 CharDriverState *text_console_init(DisplayState *ds, const char *p)
 {
     CharDriverState *chr;
     TextConsole *s;
-    int i,j;
     unsigned width;
     unsigned height;
     static int color_inited;
@@ -1195,12 +1205,7 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p)
 
     if (!color_inited) {
         color_inited = 1;
-        for(j = 0; j < 2; j++) {
-            for(i = 0; i < 8; i++) {
-                color_table[j][i] = col_expand(s->ds,
-                        vga_get_color(s->ds, color_table_rgb[j][i]));
-            }
-        }
+        console_color_init(s->ds);
     }
     s->y_displayed = 0;
     s->y_base = 0;
index f0f8c10..15c40fa 100644 (file)
--- a/keymaps.c
+++ b/keymaps.c
@@ -32,6 +32,12 @@ static int get_keysym(const char *name)
     return 0;
 }
 
+struct key_range {
+    int start;
+    int end;
+    struct key_range *next;
+};
+
 #define MAX_NORMAL_KEYCODE 512
 #define MAX_EXTRA_COUNT 256
 typedef struct {
@@ -41,8 +47,34 @@ typedef struct {
        uint16_t keycode;
     } keysym2keycode_extra[MAX_EXTRA_COUNT];
     int extra_count;
+    struct key_range *keypad_range;
+    struct key_range *numlock_range;
 } kbd_layout_t;
 
+static void add_to_key_range(struct key_range **krp, int code) {
+    struct key_range *kr;
+    for (kr = *krp; kr; kr = kr->next) {
+       if (code >= kr->start && code <= kr->end)
+           break;
+       if (code == kr->start - 1) {
+           kr->start--;
+           break;
+       }
+       if (code == kr->end + 1) {
+           kr->end++;
+           break;
+       }
+    }
+    if (kr == NULL) {
+       kr = qemu_mallocz(sizeof(*kr));
+       if (kr) {
+           kr->start = kr->end = code;
+           kr->next = *krp;
+           *krp = kr;
+       }
+    }
+}
+
 static kbd_layout_t *parse_keyboard_layout(const char *language,
                                           kbd_layout_t * k)
 {
@@ -87,7 +119,15 @@ static kbd_layout_t *parse_keyboard_layout(const char *language,
                     //             fprintf(stderr, "Warning: unknown keysym %s\n", line);
                } else {
                    const char *rest = end_of_keysym + 1;
-                   int keycode = strtol(rest, NULL, 0);
+                   char *rest2;
+                   int keycode = strtol(rest, &rest2, 0);
+
+                   if (rest && strstr(rest, "numlock")) {
+                       add_to_key_range(&k->keypad_range, keycode);
+                       add_to_key_range(&k->numlock_range, keysym);
+                       //fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode);
+                   }
+
                    /* if(keycode&0x80)
                       keycode=(keycode<<8)^0x80e0; */
                    if (keysym < MAX_NORMAL_KEYCODE) {
@@ -143,3 +183,25 @@ static int keysym2scancode(void *kbd_layout, int keysym)
     }
     return 0;
 }
+
+static inline int keycode_is_keypad(void *kbd_layout, int keycode)
+{
+    kbd_layout_t *k = kbd_layout;
+    struct key_range *kr;
+
+    for (kr = k->keypad_range; kr; kr = kr->next)
+        if (keycode >= kr->start && keycode <= kr->end)
+            return 1;
+    return 0;
+}
+
+static inline int keysym_is_numlock(void *kbd_layout, int keysym)
+{
+    kbd_layout_t *k = kbd_layout;
+    struct key_range *kr;
+
+    for (kr = k->numlock_range; kr; kr = kr->next)
+        if (keysym >= kr->start && keysym <= kr->end)
+            return 1;
+    return 0;
+}
diff --git a/vl.h b/vl.h
index 6c98033..90fdcf9 100644 (file)
--- a/vl.h
+++ b/vl.h
@@ -374,6 +374,7 @@ void vga_hw_screen_dump(const char *filename);
 int is_graphic_console(void);
 CharDriverState *text_console_init(DisplayState *ds, const char *p);
 void console_select(unsigned int index);
+void console_color_init(DisplayState *ds);
 
 /* serial ports */
 
diff --git a/vnc.c b/vnc.c
index 72c8d1c..83d0011 100644 (file)
--- a/vnc.c
+++ b/vnc.c
@@ -284,7 +284,10 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h)
        exit(1);
     }
 
-    ds->depth = vs->depth * 8;
+    if (ds->depth != vs->depth * 8) {
+        ds->depth = vs->depth * 8;
+        console_color_init(ds);
+    }
     size_changed = ds->width != w || ds->height != h;
     ds->width = w;
     ds->height = h;
@@ -907,6 +910,12 @@ static void reset_keys(VncState *vs)
     }
 }
 
+static void press_key(VncState *vs, int keysym)
+{
+    kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f);
+    kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80);
+}
+
 static void do_key_event(VncState *vs, int down, uint32_t sym)
 {
     int keycode;
@@ -934,6 +943,28 @@ static void do_key_event(VncState *vs, int down, uint32_t sym)
             return;
         }
         break;
+    case 0x45:                 /* NumLock */
+        if (!down)
+            vs->modifiers_state[keycode] ^= 1;
+        break;
+    }
+
+    if (keycode_is_keypad(vs->kbd_layout, keycode)) {
+        /* If the numlock state needs to change then simulate an additional
+           keypress before sending this one.  This will happen if the user
+           toggles numlock away from the VNC window.
+        */
+        if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) {
+            if (!vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 1;
+                press_key(vs, 0xff7f);
+            }
+        } else {
+            if (vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 0;
+                press_key(vs, 0xff7f);
+            }
+        }
     }
 
     if (is_graphic_console()) {
@@ -991,7 +1022,7 @@ static void do_key_event(VncState *vs, int down, uint32_t sym)
 
 static void key_event(VncState *vs, int down, uint32_t sym)
 {
-    if (sym >= 'A' && sym <= 'Z')
+    if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
        sym = sym - 'A' + 'a';
     do_key_event(vs, down, sym);
 }
index 14fe47f..5c47104 100644 (file)
@@ -231,6 +231,19 @@ static name2keysym_t name2keysym[]={
 {"Home", 0xff50},      /* XK_Home */
 {"End", 0xff57},       /* XK_End */
 {"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */
+{"KP_Home", 0xff95},
+{"KP_Left", 0xff96},
+{"KP_Up", 0xff97},
+{"KP_Right", 0xff98},
+{"KP_Down", 0xff99},
+{"KP_Prior", 0xff9a},
+{"KP_Page_Up", 0xff9a},
+{"KP_Next", 0xff9b},
+{"KP_Page_Down", 0xff9b},
+{"KP_End", 0xff9c},
+{"KP_Begin", 0xff9d},
+{"KP_Insert", 0xff9e},
+{"KP_Delete", 0xff9f},
 {"F1", 0xffbe},        /* XK_F1 */
 {"F2", 0xffbf},        /* XK_F2 */
 {"F3", 0xffc0},        /* XK_F3 */
@@ -258,6 +271,7 @@ static name2keysym_t name2keysym[]={
 {"KP_8", 0xffb8},      /* XK_KP_8 */
 {"KP_9", 0xffb9},      /* XK_KP_9 */
 {"KP_Add", 0xffab},    /* XK_KP_Add */
+{"KP_Separator", 0xffac},/* XK_KP_Separator */
 {"KP_Decimal", 0xffae},  /* XK_KP_Decimal */
 {"KP_Divide", 0xffaf},   /* XK_KP_Divide */
 {"KP_Enter", 0xff8d},    /* XK_KP_Enter */