* Better keymap support
@ 2008-08-29 7:39 Dietmar Maurer
2008-08-29 12:00 ` Avi Kivity
2008-09-02 10:12 ` Henrik Holst
0 siblings, 2 replies; 3+ messages in thread
From: Dietmar Maurer @ 2008-08-29 7:39 UTC (permalink / raw)
To: kvm
[-- Attachment #1: Type: text/plain, Size: 217 bytes --]
Hi all,
This patch add better vnc keymap support, i.e. you can now type a '|'
and '@' on german keybords.
It is based on a patch from ricardo ribalda I found on the qemu list
some months ago.
- Dietmar
[-- Attachment #2: keymap.diff --]
[-- Type: application/octet-stream, Size: 13184 bytes --]
--- kvm-60/qemu/keymaps.c.orig 2008-02-16 08:32:42.000000000 +0100
+++ kvm-60/qemu/keymaps.c 2008-02-16 12:47:50.000000000 +0100
@@ -38,13 +38,28 @@ struct key_range {
struct key_range *next;
};
+
+#define KEYMOD_SHIFT 0x01
+#define KEYMOD_CTRL 0x02
+#define KEYMOD_ALT 0x04
+#define KEYMOD_DEAD 0x08
+#define KEYMOD_ALTGR 0x10
+
#define MAX_NORMAL_KEYCODE 512
#define MAX_EXTRA_COUNT 256
-typedef struct {
+
+ typedef struct {
uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
+ uint16_t keycode;
+ uint8_t keymod;
+ int deadsym;
+} keydata_t;
+
+typedef struct {
+ keydata_t keysym2keycode[MAX_NORMAL_KEYCODE];
struct {
int keysym;
- uint16_t keycode;
+ keydata_t kdata;
} keysym2keycode_extra[MAX_EXTRA_COUNT];
int extra_count;
struct key_range *keypad_range;
@@ -82,6 +97,7 @@ static kbd_layout_t *parse_keyboard_layo
char file_name[1024];
char line[1024];
int len;
+ int upper;
snprintf(file_name, sizeof(file_name),
"%s/keymaps/%s", bios_dir, language);
@@ -114,25 +130,67 @@ static kbd_layout_t *parse_keyboard_layo
if (*end_of_keysym) {
int keysym;
*end_of_keysym = 0;
+ uint8_t keymod;
+ int deadsym;
+
+ keymod = 0;
+ deadsym = 0;
+ upper = 0;
+redo:
+ if (upper==1){
+ char *c;
+ for(c=line;*c;c++)
+ *c=toupper(*c);
+ keymod |= KEYMOD_SHIFT;
+ upper++;
+ }
+
keysym = get_keysym(line);
if (keysym == 0) {
// fprintf(stderr, "Warning: unknown keysym %s\n", line);
} else {
const char *rest = end_of_keysym + 1;
char *rest2;
+ char *modifier;
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);
+ modifier = strtok (rest2, " ");
+ while (modifier != NULL) {
+ if (!strcmp(modifier, "shift")) {
+ keymod |= KEYMOD_SHIFT;
+ } else
+ if (!strcmp(modifier, "addupper")) {
+ upper++;
+ } else
+ if (!strcmp(modifier, "ctrl")) {
+ keymod |= KEYMOD_CTRL;
+ } else
+ if (!strcmp(modifier, "alt")) {
+ keymod |= KEYMOD_ALT;
+ } else
+ if (!strcmp(modifier, "altgr")) {
+ keymod |= KEYMOD_ALTGR;
+ } else
+ if (!strncmp(modifier, "dead_",5)) {
+ keymod |= KEYMOD_DEAD;
+ deadsym = get_keysym(modifier);
+ } else
+ if (!strcmp(modifier, "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);
+ }
+ modifier = strtok (NULL," ");
}
/* if(keycode&0x80)
keycode=(keycode<<8)^0x80e0; */
if (keysym < MAX_NORMAL_KEYCODE) {
//fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode);
- k->keysym2keycode[keysym] = keycode;
+ k->keysym2keycode[keysym].keycode = keycode;
+ k->keysym2keycode[keysym].keymod = keymod;
+ k->keysym2keycode[keysym].deadsym = deadsym;
+
} else {
if (k->extra_count >= MAX_EXTRA_COUNT) {
fprintf(stderr,
@@ -145,16 +203,24 @@ static kbd_layout_t *parse_keyboard_layo
#endif
k->keysym2keycode_extra[k->extra_count].
keysym = keysym;
- k->keysym2keycode_extra[k->extra_count].
- keycode = keycode;
+ k->keysym2keycode_extra[k->extra_count].kdata.
+ keycode = keycode;
+ k->keysym2keycode_extra[k->extra_count].kdata.
+ keymod = keymod;
+ k->keysym2keycode_extra[k->extra_count].kdata.
+ deadsym = deadsym;
+
k->extra_count++;
}
}
+ if (upper==1)
+ goto redo;
}
}
}
}
fclose(f);
+
return k;
}
@@ -163,14 +229,11 @@ static void *init_keyboard_layout(const
return parse_keyboard_layout(language, 0);
}
-static int keysym2scancode(void *kbd_layout, int keysym)
+static keydata_t *find_keysym(void *kbd_layout, int keysym)
{
kbd_layout_t *k = kbd_layout;
if (keysym < MAX_NORMAL_KEYCODE) {
- if (k->keysym2keycode[keysym] == 0)
- fprintf(stderr, "Warning: no scancode found for keysym %d\n",
- keysym);
- return k->keysym2keycode[keysym];
+ return &k->keysym2keycode[keysym];
} else {
int i;
#ifdef XK_ISO_Left_Tab
@@ -178,10 +241,10 @@ static int keysym2scancode(void *kbd_lay
keysym = XK_Tab;
#endif
for (i = 0; i < k->extra_count; i++)
- if (k->keysym2keycode_extra[i].keysym == keysym)
- return k->keysym2keycode_extra[i].keycode;
+ if (k->keysym2keycode_extra[i].keysym == keysym)
+ return &k->keysym2keycode_extra[i].kdata;
}
- return 0;
+ return NULL;
}
static inline int keycode_is_keypad(void *kbd_layout, int keycode)
--- kvm-60/qemu/vnc.c.orig 2008-02-16 10:32:11.000000000 +0100
+++ kvm-60/qemu/vnc.c 2008-02-16 13:24:05.000000000 +0100
@@ -55,6 +55,20 @@ static void vnc_debug_gnutls_log(int lev
#define VNC_DEBUG(fmt, ...) do { } while (0)
#endif
+typedef struct {
+ int keycode;
+ int bit;
+} modifier_t;
+
+static modifier_t test_modifier[]={
+ {0x2a, KEYMOD_SHIFT},
+ {0x36, KEYMOD_SHIFT},
+ {0x1d, KEYMOD_CTRL},
+ {0x9d, KEYMOD_CTRL},
+ {0x38, KEYMOD_ALT},
+ {0xb8, KEYMOD_ALTGR},
+ {0,0},
+};
typedef struct Buffer
{
@@ -173,7 +187,7 @@ struct VncState
VncReadEvent *read_handler;
size_t read_handler_expect;
/* input */
- uint8_t modifiers_state[256];
+ uint8_t modifiers_state[2][256];
};
static VncState *vnc_state; /* needed for info vnc */
@@ -908,30 +922,86 @@ static void pointer_event(VncState *vs,
check_pointer_type_change(vs, kbd_mouse_is_absolute());
}
+static void do_keycode(int keycode, int down)
+{
+ // fprintf (stderr, "KEY: %04x %d\n", keycode, down);
+ if (keycode & 0x80)
+ kbd_put_keycode(0xe0);
+ if (down)
+ kbd_put_keycode(keycode & 0x7f);
+ else
+ kbd_put_keycode(keycode | 0x80);
+}
+
+static void do_modifier(VncState *vs, int keycode, int down, int level)
+{
+ do_keycode(keycode, down);
+ vs->modifiers_state[level][keycode] = down;
+ if (level==0) {
+ vs->modifiers_state[1][keycode] = down;
+ }
+}
+
static void reset_keys(VncState *vs)
{
int i;
for(i = 0; i < 256; i++) {
- if (vs->modifiers_state[i]) {
- if (i & 0x80)
- kbd_put_keycode(0xe0);
- kbd_put_keycode(i | 0x80);
- vs->modifiers_state[i] = 0;
+ if (vs->modifiers_state[0][i]) {
+ do_modifier (vs, i, 0, 0);
}
}
}
+static void set_modifiers(VncState *vs, uint8_t reqstate, int down, int full)
+{
+ modifier_t *m;
+ for(m=test_modifier; m->bit; m++) {
+ int requested = reqstate & m->bit;
+ /* Release unwanted modifiers */
+ if (!down || full) {
+ if (vs->modifiers_state[1][m->keycode] && !requested)
+ do_modifier(vs, m->keycode, 0, 1);
+ }
+ /* Press desired modifiers */
+ if (down || full) {
+ int already_set = vs->modifiers_state[1][m->keycode];
+ if (!already_set && requested)
+ do_modifier(vs, m->keycode, 1, 1);
+ }
+ }
+}
+
+static void restore_modifiers(VncState *vs)
+{
+ /* Restore modifiers from reference */
+ modifier_t *m;
+ for(m=test_modifier; m->bit; m++) {
+ if (vs->modifiers_state[0][m->keycode] !=
+ vs->modifiers_state[1][m->keycode])
+ do_modifier(vs, m->keycode, vs->modifiers_state[0][m->keycode], 0);
+ }
+}
+
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);
+ keydata_t *eventdata = find_keysym(vs->kbd_layout, keysym & 0xFFFF);
+ if (eventdata==NULL)
+ return;
+
+ kbd_put_keycode(eventdata->keycode & 0x7f);
+ kbd_put_keycode(eventdata->keycode | 0x80);
}
-static void do_key_event(VncState *vs, int down, uint32_t sym)
+static void key_event(VncState *vs, int down, uint32_t sym)
{
- int keycode;
+ keydata_t *eventdata = find_keysym(vs->kbd_layout, sym & 0xFFFF);
+ if (eventdata==NULL)
+ return;
+
+ int keycode = eventdata->keycode;
- keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
+ //fprintf (stderr, "SYM: %04x SCANCODE: %04x MOD %04x\n",
+ // sym, keycode, eventdata->keymod);
/* QEMU console switch */
switch(keycode) {
@@ -941,13 +1011,10 @@ static void do_key_event(VncState *vs, i
case 0x9d: /* Right CTRL */
case 0x38: /* Left ALT */
case 0xb8: /* Right ALT */
- if (down)
- vs->modifiers_state[keycode] = 1;
- else
- vs->modifiers_state[keycode] = 0;
- break;
+ do_modifier(vs, keycode, down, 0);
+ return;
case 0x02 ... 0x0a: /* '1' to '9' keys */
- if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
+ if (down && vs->modifiers_state[0][0x1d] && vs->modifiers_state[0][0x38]) {
/* Reset the modifiers sent to the current console */
reset_keys(vs);
console_select(keycode - 0x02);
@@ -955,8 +1022,12 @@ static void do_key_event(VncState *vs, i
}
break;
case 0x45: /* NumLock */
- if (!down)
- vs->modifiers_state[keycode] ^= 1;
+ if (!down) {
+ if (vs->modifiers_state[0][0x45])
+ do_modifier(vs, keycode, 0, 0);
+ else
+ do_modifier(vs, keycode, 1, 0);
+ }
break;
}
@@ -966,25 +1037,42 @@ static void do_key_event(VncState *vs, i
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;
+ if (!vs->modifiers_state[0][0x45]) {
+ do_modifier(vs, 0x45, 1, 0);
press_key(vs, 0xff7f);
}
} else {
- if (vs->modifiers_state[0x45]) {
- vs->modifiers_state[0x45] = 0;
- press_key(vs, 0xff7f);
+ if (vs->modifiers_state[0][0x45]) {
+ do_modifier(vs, 0x45, 0, 0);
+ press_key(vs, 0xff7f);
}
}
}
if (is_graphic_console()) {
- if (keycode & 0x80)
- kbd_put_keycode(0xe0);
- if (down)
- kbd_put_keycode(keycode & 0x7f);
- else
- kbd_put_keycode(keycode | 0x80);
+ if (down) {
+ /* Send deadkey */
+ if (eventdata->keymod & KEYMOD_DEAD) {
+ keydata_t *deaddata;
+ deaddata = find_keysym(vs->kbd_layout, eventdata->deadsym);
+ if (deaddata != NULL) {
+ set_modifiers(vs, deaddata->keymod, 0, 1);
+ do_keycode(deaddata->keycode, 1);
+ do_keycode(deaddata->keycode, 0);
+ restore_modifiers(vs);
+ }
+ }
+ set_modifiers(vs, eventdata->keymod, 1, 0);
+ } else
+ restore_modifiers(vs);
+
+ do_keycode (keycode, down);
+
+ /* vnc never sends ALTGR, so we create an artificial up event */
+ if (down && (eventdata->keymod & KEYMOD_ALTGR)) {
+ set_modifiers(vs, eventdata->keymod, 0, 0);
+ }
+
} else {
/* QEMU console emulation */
if (down) {
@@ -1031,13 +1119,6 @@ static void do_key_event(VncState *vs, i
}
}
-static void key_event(VncState *vs, int down, uint32_t sym)
-{
- if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
- sym = sym - 'A' + 'a';
- do_key_event(vs, down, sym);
-}
-
static void framebuffer_update_request(VncState *vs, int incremental,
int x_position, int y_position,
int w, int h)
--- kvm-60/qemu/sdl.c.orig 2008-02-16 09:21:09.000000000 +0100
+++ kvm-60/qemu/sdl.c 2008-02-16 09:24:38.000000000 +0100
@@ -116,7 +116,11 @@ static uint8_t sdl_keyevent_to_keycode_g
if (keysym == 92 && ev->keysym.scancode == 133) {
keysym = 0xa5;
}
- return keysym2scancode(kbd_layout, keysym);
+ keydata_t *eventdata = find_keysym(kbd_layout, keysym);
+ if (eventdata==NULL)
+ return 0;
+ else
+ return eventdata->keycode;
}
/* specific keyboard conversions from scan codes */
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Better keymap support
2008-08-29 7:39 Better keymap support Dietmar Maurer
@ 2008-08-29 12:00 ` Avi Kivity
2008-09-02 10:12 ` Henrik Holst
1 sibling, 0 replies; 3+ messages in thread
From: Avi Kivity @ 2008-08-29 12:00 UTC (permalink / raw)
To: Dietmar Maurer; +Cc: kvm
Dietmar Maurer wrote:
> Hi all,
>
> This patch add better vnc keymap support, i.e. you can now type a '|'
> and '@' on german keybords.
>
> It is based on a patch from ricardo ribalda I found on the qemu list
> some months ago.
>
Please post it on the qemu list, so that qemu upstream can benefit from
it as well. Once the patched is applied to qemu I will merge it into kvm.
--
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Better keymap support
2008-08-29 7:39 Better keymap support Dietmar Maurer
2008-08-29 12:00 ` Avi Kivity
@ 2008-09-02 10:12 ` Henrik Holst
1 sibling, 0 replies; 3+ messages in thread
From: Henrik Holst @ 2008-09-02 10:12 UTC (permalink / raw)
To: Dietmar Maurer; +Cc: kvm
fre 2008-08-29 klockan 09:39 +0200 skrev Dietmar Maurer:
> Hi all,
>
> This patch add better vnc keymap support, i.e. you can now type a '|'
> and '@' on german keybords.
>
> It is based on a patch from ricardo ribalda I found on the qemu list
> some months ago.
>
> - Dietmar
>
Is it really necesary with such a big patch? I found this small one on
an old qemu list which made AltGr work for atleast swedish keyboards,
perhaps it will work for German keyboards as well (our keyboards should
be very similar since the main addition is the AltGr key compared with
the US keyboard).
--- ../kvm-70-old/qemu/vnc_keysym.h 2008-06-17 14:09:05.000000000
+0200
+++ qemu/vnc_keysym.h 2008-06-17 14:09:07.000000000 +0200
@@ -204,6 +204,7 @@
{"EuroSign", 0x20ac}, /* XK_EuroSign */
/* modifiers */
+{"ISO_Level3_Shift", 0xfe03}, /* ISO_Level3 */
{"Control_L", 0xffe3}, /* XK_Control_L */
{"Control_R", 0xffe4}, /* XK_Control_R */
{"Alt_L", 0xffe9}, /* XK_Alt_L */
--- ../kvm-70-old/qemu/keymaps/modifiers 2008-06-17
14:09:04.000000000 +0200
+++ qemu/keymaps/modifiers 2008-06-17 14:09:07.000000000 +0200
@@ -15,3 +15,6 @@
# Translate Menu to the Windows Application key.
Menu 0xdd
+
+# AltGR
+ISO_Level3_Shift 0xb8
regards, Henrik Holst
Witsbits AB
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-09-02 10:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-29 7:39 Better keymap support Dietmar Maurer
2008-08-29 12:00 ` Avi Kivity
2008-09-02 10:12 ` Henrik Holst
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox