diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 419cdf45a..25a117560 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -73,6 +73,18 @@ get_abstract_code (grub_term_input_t term, int in) if (((in & 0xff) == 0) && keyboard_map[(in & 0xff00) >> 8] >= 'a' && keyboard_map[(in & 0xff00) >> 8] <= 'z') return keyboard_map[(in & 0xff00) >> 8] | flags | GRUB_TERM_ALT_GR; + if ((in & 0xff) == 0 && (in & 0xff00) >= 0x7800 + && (in & 0xff00) <= 0x8000) + return (((in & 0xff00) >> 8) - 0x78 + '1') | flags | GRUB_TERM_ALT_GR; + + if ((in & 0xff00) == 0x8100) + return '0' | flags | GRUB_TERM_ALT_GR; + + if ((in & 0xffff) == 0x8200) + return '-' | flags | GRUB_TERM_ALT_GR; + + if ((in & 0xffff) == 0x8300) + return '+' | flags | GRUB_TERM_ALT_GR; if ((in & 0xff) == 0) return keyboard_map[(in & 0xff00) >> 8] | flags; @@ -83,34 +95,25 @@ get_abstract_code (grub_term_input_t term, int in) } static grub_uint32_t mapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - -static unsigned -clear_internal_flags (unsigned in) -{ - if (in & GRUB_TERM_ALT_GR) - in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT; - return in & ~GRUB_TERM_CAPS & ~GRUB_TERM_KEYPAD; -} +static grub_uint32_t mapping_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; static unsigned map (grub_term_input_t term __attribute__ ((unused)), unsigned in) { if (in & GRUB_TERM_KEYPAD) - return clear_internal_flags (in); - - /* AltGr isn't supported yet. */ - if (in & GRUB_TERM_ALT_GR) - in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT; + return in; if ((in & GRUB_TERM_EXTENDED) || (in & GRUB_TERM_KEY_MASK) == '\b' || (in & GRUB_TERM_KEY_MASK) == '\n' || (in & GRUB_TERM_KEY_MASK) == ' ' || (in & GRUB_TERM_KEY_MASK) == '\t' || (in & GRUB_TERM_KEY_MASK) == '\e' || (in & GRUB_TERM_KEY_MASK) == '\r' || (in & GRUB_TERM_KEY_MASK) >= ARRAY_SIZE (mapping)) - return clear_internal_flags (in); + return in; - return mapping[in & GRUB_TERM_KEY_MASK] - | clear_internal_flags (in & ~GRUB_TERM_KEY_MASK); + if ((in & GRUB_TERM_ALT_GR) && mapping_alt[in & GRUB_TERM_KEY_MASK]) + return mapping_alt[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK & ~GRUB_TERM_ALT_GR); + + return mapping[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK); } static int @@ -118,6 +121,9 @@ translate (grub_term_input_t term, int in) { int code, flags; code = get_abstract_code (term, in); + + flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD | GRUB_TERM_CAPS); + if ((code & GRUB_TERM_CAPS) && (code & GRUB_TERM_KEY_MASK) >= 'a' && (code & GRUB_TERM_KEY_MASK) <= 'z') code = (code & GRUB_TERM_KEY_MASK) + 'A' - 'a'; @@ -125,7 +131,6 @@ translate (grub_term_input_t term, int in) && (code & GRUB_TERM_KEY_MASK) <= 'Z') code = (code & GRUB_TERM_KEY_MASK) + 'a' - 'A'; - flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD); code &= (GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD); code = map (term, code); /* Transform unconsumed AltGr into Alt. */ @@ -134,6 +139,8 @@ translate (grub_term_input_t term, int in) flags |= GRUB_TERM_ALT; code &= ~GRUB_TERM_ALT_GR; } + code &= ~GRUB_TERM_KEYPAD; + if ((flags & GRUB_TERM_CAPS) && code >= 'a' && code <= 'z') code += 'A' - 'a'; else if ((flags & GRUB_TERM_CAPS) && code >= 'A' @@ -186,6 +193,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), grub_uint32_t version; grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE]; grub_uint32_t newmapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t newmapping_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; unsigned i; if (argc < 1) @@ -241,9 +249,20 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), goto fail; } + if (grub_file_read (file, newmapping_alt, sizeof (newmapping_alt)) + != sizeof (newmapping_alt)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + for (i = 0; i < ARRAY_SIZE (mapping); i++) mapping[i] = grub_le_to_cpu32(newmapping[i]); + for (i = 0; i < ARRAY_SIZE (mapping_alt); i++) + mapping_alt[i] = grub_le_to_cpu32(newmapping_alt[i]); + return GRUB_ERR_NONE; fail: @@ -263,6 +282,7 @@ GRUB_MOD_INIT(keylayouts) unsigned i; for (i = 0; i < ARRAY_SIZE (mapping); i++) mapping[i] = i; + grub_memset (mapping_alt, 0, sizeof (mapping_alt)); mapping[GRUB_TERM_KEY_102] = '\\'; mapping[GRUB_TERM_KEY_SHIFT_102] = '|'; diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index 1d263e268..081e9ca98 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -21,7 +21,7 @@ #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) -#define GRUB_KEYBOARD_LAYOUTS_VERSION 2 +#define GRUB_KEYBOARD_LAYOUTS_VERSION 3 #define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 256 diff --git a/term/at_keyboard.c b/term/at_keyboard.c index cc0c69e22..5adc8b4da 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -34,6 +34,7 @@ static int pending_key = -1; #define KEYBOARD_STATUS_CTRL_R (1 << 5) #define KEYBOARD_STATUS_CAPS_LOCK (1 << 6) #define KEYBOARD_STATUS_NUM_LOCK (1 << 7) +#define KEYBOARD_STATUS_EXTENDED (1 << 8) static grub_uint8_t led_status; @@ -80,12 +81,10 @@ keyboard_controller_led (grub_uint8_t leds) /* FIXME: This should become an interrupt service routine. For now it's just used to catch events from control keys. */ static void -grub_keyboard_isr (char key) +grub_keyboard_isr (grub_uint8_t key) { - char is_make = KEYBOARD_ISMAKE (key); - key = KEYBOARD_SCANCODE (key); - if (is_make) - switch (key) + if (KEYBOARD_ISMAKE (key)) + switch (KEYBOARD_SCANCODE (key)) { case SHIFT_L: at_keyboard_status |= KEYBOARD_STATUS_SHIFT_L; @@ -97,14 +96,14 @@ grub_keyboard_isr (char key) at_keyboard_status |= KEYBOARD_STATUS_CTRL_L; break; case ALT: - at_keyboard_status |= KEYBOARD_STATUS_ALT_L; + if (at_keyboard_status & KEYBOARD_STATUS_EXTENDED) + at_keyboard_status |= KEYBOARD_STATUS_ALT_R; + else + at_keyboard_status |= KEYBOARD_STATUS_ALT_L; break; - default: - /* Skip grub_dprintf. */ - return; } else - switch (key) + switch (KEYBOARD_SCANCODE (key)) { case SHIFT_L: at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_L; @@ -116,15 +115,17 @@ grub_keyboard_isr (char key) at_keyboard_status &= ~KEYBOARD_STATUS_CTRL_L; break; case ALT: - at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L; + if (at_keyboard_status & KEYBOARD_STATUS_EXTENDED) + at_keyboard_status &= ~KEYBOARD_STATUS_ALT_R; + else + at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L; break; - default: - /* Skip grub_dprintf. */ - return; } -#ifdef DEBUG_AT_KEYBOARD - grub_dprintf ("atkeyb", "Control key 0x%0x was %s\n", key, is_make ? "pressed" : "unpressed"); -#endif + if (key == 0xe0) + at_keyboard_status |= KEYBOARD_STATUS_EXTENDED; + else + at_keyboard_status &= ~KEYBOARD_STATUS_EXTENDED; + } /* If there is a raw key pending, return it; otherwise return -1. */ @@ -210,9 +211,15 @@ grub_at_keyboard_getkey_noblock (void) } if (at_keyboard_status & KEYBOARD_STATUS_ALT_L) - key |= GRUB_TERM_ALT; + { + key |= GRUB_TERM_ALT; + grub_printf ("AltL"); + } if (at_keyboard_status & KEYBOARD_STATUS_ALT_R) - key |= GRUB_TERM_ALT_GR; + { + key |= GRUB_TERM_ALT_GR; + grub_printf ("AltGr"); + } if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R)) key |= GRUB_TERM_CTRL; diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index 48b17e798..434f9f4f8 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -115,7 +115,8 @@ get_grub_code (char *layout_code) } void -write_file (char* filename, grub_uint32_t *keyboard_map) +write_file (char* filename, grub_uint32_t *keyboard_map, + grub_uint32_t *keyboard_map_alt) { FILE *fp_output; grub_uint32_t version; @@ -126,6 +127,9 @@ write_file (char* filename, grub_uint32_t *keyboard_map) for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) keyboard_map[i] = grub_cpu_to_le32 (keyboard_map[i]); + for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) + keyboard_map_alt[i] = grub_cpu_to_le32 (keyboard_map_alt[i]); + fp_output = fopen (filename, "w"); if (!fp_output) @@ -139,6 +143,8 @@ write_file (char* filename, grub_uint32_t *keyboard_map) fwrite (&version, sizeof (version), 1, fp_output); fwrite (keyboard_map, sizeof (keyboard_map[0]), GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE, fp_output); + fwrite (keyboard_map_alt, sizeof (keyboard_map_alt[0]), + GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE, fp_output); fclose (fp_output); } @@ -146,6 +152,7 @@ void write_keymaps (char *keymap, char *file_basename) { grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; char line[2048]; pid_t pid; @@ -189,11 +196,17 @@ write_keymaps (char *keymap, char *file_basename) unsigned keycode; char normal[64]; char shift[64]; - sscanf (line, "keycode %u = %60s %60s", &keycode, normal, shift); + char normalalt[64]; + char shiftalt[64]; + + sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode, + normal, shift, normalalt, shiftalt); if (keycode < ARRAY_SIZE (us_keyboard_map) && us_keyboard_map[keycode] < ARRAY_SIZE (keyboard_map)) { keyboard_map[us_keyboard_map[keycode]] = get_grub_code (normal); + keyboard_map_alt[us_keyboard_map[keycode]] + = get_grub_code (normalalt); ok = 1; } if (keycode < ARRAY_SIZE (us_keyboard_map_shifted) @@ -201,6 +214,8 @@ write_keymaps (char *keymap, char *file_basename) { keyboard_map[us_keyboard_map_shifted[keycode]] = get_grub_code (shift); + keyboard_map_alt[us_keyboard_map_shifted[keycode]] + = get_grub_code (shiftalt); ok = 1; } } @@ -213,7 +228,7 @@ write_keymaps (char *keymap, char *file_basename) exit (1); } - write_file (file_basename, keyboard_map); + write_file (file_basename, keyboard_map, keyboard_map_alt); } int