--- qemu-old/keymaps/es	Sun Dec 12 18:56:30 2004
+++ qemu-new/keymaps/es	Tue Aug 08 23:41:55 2006
@@ -103,3 +103,58 @@
 underscore 0x35 shift
 dead_belowdot 0x35 altgr
 dead_abovedot 0x35 shift altgr
+
+
+# Dead keys
+aacute 0x1e dead_acute
+Aacute 0x1e dead_acute shift
+eacute 0x12 dead_acute
+Eacute 0x12 dead_acute shift
+iacute 0x17 dead_acute
+Iacute 0x17 dead_acute shift
+oacute 0x18 dead_acute
+Oacute 0x18 dead_acute shift
+uacute 0x16 dead_acute
+Uacute 0x16 dead_acute shift
+yacute 0x15 dead_acute
+Yacute 0x15 dead_acute shift
+
+agrave 0x1e dead_grave
+Agrave 0x1e dead_grave shift
+egrave 0x12 dead_grave
+Egrave 0x12 dead_grave shift
+igrave 0x17 dead_grave
+Igrave 0x17 dead_grave shift
+ograve 0x18 dead_grave
+Ograve 0x18 dead_grave shift
+ugrave 0x16 dead_grave
+Ugrave 0x16 dead_grave shift
+
+adiaeresis 0x1e dead_diaeresis
+Adiaeresis 0x1e dead_diaeresis shift
+ediaeresis 0x12 dead_diaeresis
+Ediaeresis 0x12 dead_diaeresis shift
+idiaeresis 0x17 dead_diaeresis
+Idiaeresis 0x17 dead_diaeresis shift
+odiaeresis 0x18 dead_diaeresis
+Odiaeresis 0x18 dead_diaeresis shift
+udiaeresis 0x16 dead_diaeresis
+Udiaeresis 0x16 dead_diaeresis shift
+ydiaeresis 0x15 dead_diaeresis
+
+acircumflex 0x1e dead_circumflex
+Acircumflex 0x1e dead_circumflex shift
+ecircumflex 0x12 dead_circumflex
+Ecircumflex 0x12 dead_circumflex shift
+icircumflex 0x17 dead_circumflex
+Icircumflex 0x17 dead_circumflex shift
+ocircumflex 0x18 dead_circumflex
+Ocircumflex 0x18 dead_circumflex shift
+ucircumflex 0x16 dead_circumflex
+Ucircumflex 0x16 dead_circumflex shift
+
+acute 0x39 dead_acute
+grave 0x39 dead_grave
+diaeresis 0x39 dead_diaeresis
+asciicircum 0x39 dead_circumflex
+
--- qemu-old/keymaps.c	Sun Apr 30 23:28:35 2006
+++ qemu-new/keymaps.c	Tue Aug 08 23:39:58 2006
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 
+
 static int get_keysym(const char *name)
 {
     name2keysym_t *p;
@@ -32,13 +33,26 @@
     return 0;
 }
 
+
+#define KEYMOD_SHIFT 0x01
+#define KEYMOD_CTRL  0x02
+#define KEYMOD_ALT   0x04
+#define KEYMOD_DEAD  0x08
+
 #define MAX_NORMAL_KEYCODE 512
 #define MAX_EXTRA_COUNT 256
+
 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;
 } kbd_layout_t;
@@ -50,6 +64,7 @@
     char file_name[1024];
     char line[1024];
     int len;
+    int upper;
 
     snprintf(file_name, sizeof(file_name),
              "%s/keymaps/%s", bios_dir, language);
@@ -82,17 +97,61 @@
 	    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;
 		    int keycode = strtol(rest, NULL, 0);
+                    char *modifier;
+                    modifier = strtok (rest," ");
+                    modifier = strtok (NULL," ");
+                    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_CTRL | KEYMOD_ALT;
+                        } else
+                        if (!strncmp(modifier, "dead_",5)) {
+                            keymod |= KEYMOD_DEAD;
+                            deadsym = get_keysym(modifier);
+                        } 
+                        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,
@@ -105,11 +164,18 @@
 #endif
 			    k->keysym2keycode_extra[k->extra_count].
 				keysym = keysym;
-			    k->keysym2keycode_extra[k->extra_count].
+                            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;
 		}
 	    }
 	}
@@ -123,14 +189,11 @@
     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
@@ -138,8 +201,9 @@
 	    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;
 }
--- qemu-old/sdl.c	Tue Jun 13 14:03:53 2006
+++ qemu-new/sdl.c	Tue Aug 08 23:40:08 2006
@@ -104,7 +104,11 @@
     keysym = ev->keysym.sym;
     if (keysym == 0 && ev->keysym.scancode == 113)
         keysym = SDLK_MODE;
-    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 */
--- qemu-old/vnc.c	Tue Jun 13 18:35:24 2006
+++ qemu-new/vnc.c	Tue Aug 08 23:41:37 2006
@@ -31,6 +31,23 @@
 #include "vnc_keysym.h"
 #include "keymaps.c"
 
+
+static uint8_t modifiers_state[2][256];
+
+typedef struct {
+    int left;
+    int right;
+    int bit;
+} modifier_t;
+
+static modifier_t test_modifier[]={
+    {0x2a,  0x36,   KEYMOD_SHIFT},
+    {0x1d,  0x9d,   KEYMOD_CTRL},
+    {0x38,  0xb8,   KEYMOD_ALT},
+    {0,0,0},
+};
+
+
 typedef struct Buffer
 {
     size_t capacity;
@@ -699,12 +716,9 @@
     }
 }
 
-static void do_key_event(VncState *vs, int down, uint32_t sym)
-{
-    int keycode;
-
-    keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
 
+static void do_keycode(int keycode, int down)
+{
     if (keycode & 0x80)
 	kbd_put_keycode(0xe0);
     if (down)
@@ -713,11 +727,88 @@
 	kbd_put_keycode(keycode | 0x80);
 }
 
+static void do_modifier(int keycode, int down, int level)
+{
+    do_keycode(keycode,down);
+    modifiers_state[level][keycode] = down;
+    if (level==0) {
+        modifiers_state[1][keycode] = down;
+    }
+}
+
+static void set_modifiers(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 (modifiers_state[1][m->left] && !requested)
+                do_modifier(m->left,0,1);
+            if (modifiers_state[1][m->right] && !requested)
+                do_modifier(m->right,0,1);
+        }
+        /* Press desired modifiers */
+        if (down || full) {
+            int already_set = modifiers_state[1][m->left] | modifiers_state[1][m->right];
+            if (!already_set && requested)
+                do_modifier(m->left,1,1);
+        }
+    }
+}
+
+static void restore_modifiers()
+{
+    /* Restore modifiers from reference */
+    modifier_t *m;
+    for(m=test_modifier; m->bit; m++) {
+        if (modifiers_state[0][m->left] != modifiers_state[1][m->left])
+            do_modifier(m->left,modifiers_state[0][m->left],0);
+        if (modifiers_state[0][m->right] != modifiers_state[1][m->right])
+            do_modifier(m->right,modifiers_state[0][m->right],0);
+    }    
+}
+
 static void key_event(VncState *vs, int down, uint32_t sym)
 {
-    if (sym >= 'A' && sym <= 'Z')
-	sym = sym - 'A' + 'a';
-    do_key_event(vs, down, sym);
+    keydata_t *eventdata;
+    eventdata = find_keysym(vs->kbd_layout, sym & 0xFFFF);
+    if (eventdata==NULL)
+        return;
+    switch(eventdata->keycode) {
+    case 0x2a:                          /* Left Shift */
+    case 0x36:                          /* Right Shift */
+    case 0x1d:                          /* Left CTRL */
+    case 0x9d:                          /* Right CTRL */
+    case 0x38:                          /* Left ALT */
+    case 0xb8:                          /* Right ALT */
+        do_modifier(eventdata->keycode, down, 0);
+        return;
+    case 0x3a: /* caps lock */
+        /* TODO: handle properly caps lock + shift combinations */
+        return;
+        break;
+    }
+
+    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(deaddata->keymod,0,1);
+                do_keycode(deaddata->keycode,1);
+                do_keycode(deaddata->keycode,0);
+                restore_modifiers();
+            }
+        }
+        set_modifiers(eventdata->keymod,1,0);
+    }
+
+    do_keycode(eventdata->keycode,down);
+        
+    if (!down)
+        restore_modifiers();
 }
 
 static void framebuffer_update_request(VncState *vs, int incremental,
--- qemu-old/vnc_keysym.h	Sun Apr 30 23:28:36 2006
+++ qemu-new/vnc_keysym.h	Tue Aug 08 23:39:35 2006
@@ -247,6 +247,33 @@
 {"F14", 0xffcb},       /* XK_F14 */
 {"F15", 0xffcc},       /* XK_F15 */
 {"Sys_Req", 0xff15},   /* XK_Sys_Req */
+{"KP_Space", 0xff80},      /* XK_KP_Space */
+{"KP_Tab", 0xff89},        /* XK_KP_Tab */
+{"KP_Enter", 0xff8d},      /* XK_KP_Enter */
+{"KP_F1", 0xff91},         /* XK_KP_F1 */
+{"KP_F2", 0xff92},         /* XK_KP_F2 */
+{"KP_F3", 0xff93},         /* XK_KP_F3 */
+{"KP_F4", 0xff94},         /* XK_KP_F4 */
+{"KP_Home", 0xff95},       /* XK_KP_Home */
+{"KP_Left", 0xff96},       /* XK_KP_Left */
+{"KP_Up", 0xff97},         /* XK_KP_Up */
+{"KP_Right", 0xff98},      /* XK_KP_Right */
+{"KP_Down", 0xff99},       /* XK_KP_Down */
+{"KP_Prior", 0xff9a},      /* XK_KP_Prior */
+{"KP_Page_Up", 0xff9a},    /* XK_KP_Page_Up */
+{"KP_Next", 0xff9b},       /* XK_KP_Next */
+{"KP_Page_Down", 0xff9b},  /* XK_KP_Page_Down */
+{"KP_End", 0xff9c},        /* XK_KP_End */
+{"KP_Begin", 0xff9d},      /* XK_KP_Begin */
+{"KP_Insert", 0xff9e},     /* XK_KP_Insert */
+{"KP_Delete", 0xff9f},     /* XK_KP_Delete */
+{"KP_Equal", 0xffbd},      /* XK_KP_Equal */
+{"KP_Multiply", 0xffaa},   /* XK_KP_Multiply */
+{"KP_Add", 0xffab},        /* XK_KP_Add */
+{"KP_Separator", 0xffac},  /* XK_KP_Separator */
+{"KP_Subtract", 0xffad},   /* XK_KP_Subtract */
+{"KP_Decimal", 0xffae},    /* XK_KP_Decimal */
+{"KP_Divide", 0xffaf},     /* XK_KP_Divide */
 {"KP_0", 0xffb0},      /* XK_KP_0 */
 {"KP_1", 0xffb1},      /* XK_KP_1 */
 {"KP_2", 0xffb2},      /* XK_KP_2 */
@@ -257,13 +284,6 @@
 {"KP_7", 0xffb7},      /* XK_KP_7 */
 {"KP_8", 0xffb8},      /* XK_KP_8 */
 {"KP_9", 0xffb9},      /* XK_KP_9 */
-{"KP_Add", 0xffab},    /* XK_KP_Add */
-{"KP_Decimal", 0xffae},  /* XK_KP_Decimal */
-{"KP_Divide", 0xffaf},   /* XK_KP_Divide */
-{"KP_Enter", 0xff8d},    /* XK_KP_Enter */
-{"KP_Equal", 0xffbd},    /* XK_KP_Equal */
-{"KP_Multiply", 0xffaa}, /* XK_KP_Multiply */
-{"KP_Subtract", 0xffad}, /* XK_KP_Subtract */
 {"help", 0xff6a},        /* XK_Help */
 {"Menu", 0xff67},        /* XK_Menu */
 {"Print", 0xff61},       /* XK_Print */
@@ -271,5 +291,27 @@
 {"Num_Lock", 0xff7f},    /* XK_Num_Lock */
 {"Pause", 0xff13},       /* XK_Pause */
 {"Escape", 0xff1b},      /* XK_Escape */
+
+/* dead keys */
+{"dead_grave", 0xfe50},               /* XK_dead_grave */
+{"dead_acute", 0xfe51},               /* XK_dead_acute */
+{"dead_circumflex", 0xfe52},          /* XK_dead_circumflex */
+{"dead_tilde", 0xfe53},               /* XK_dead_tilde */
+{"dead_macron", 0xfe54},              /* XK_dead_macron */
+{"dead_breve", 0xfe55},               /* XK_dead_breve */
+{"dead_abovedot", 0xfe56},            /* XK_dead_abovedot */
+{"dead_diaeresis", 0xfe57},           /* XK_dead_diaeresis */
+{"dead_abovering", 0xfe58},           /* XK_dead_abovering */
+{"dead_doubleacute", 0xfe59},         /* XK_dead_doubleacute */
+{"dead_caron", 0xfe5a},               /* XK_dead_caron */
+{"dead_cedilla", 0xfe5b},             /* XK_dead_cedilla */
+{"dead_ogonek", 0xfe5c},              /* XK_dead_ogonek */
+{"dead_iota", 0xfe5d},                /* XK_dead_iota */
+{"dead_voiced_sound", 0xfe5e},        /* XK_dead_voiced_sound */
+{"dead_semivoiced_sound", 0xfe5f},    /* XK_dead_semivoiced_sound */
+{"dead_belowdot", 0xfe60},            /* XK_dead_belowdot */
+{"dead_hook", 0xfe61},                /* XK_dead_hook */
+{"dead_horn", 0xfe62},                /* XK_dead_horn */
+
 {0,0},
 };
