diff options
Diffstat (limited to 'console-client/pc-kbd.c')
-rw-r--r-- | console-client/pc-kbd.c | 282 |
1 files changed, 275 insertions, 7 deletions
diff --git a/console-client/pc-kbd.c b/console-client/pc-kbd.c index d66e94b3..95109e52 100644 --- a/console-client/pc-kbd.c +++ b/console-client/pc-kbd.c @@ -34,6 +34,10 @@ #include "driver.h" #include "mach-inputdev.h" +#ifdef XKB_SUPPORT +#include "xkb/xkb.h" +#endif + /* The default name of the node of the repeater. */ #define DEFAULT_REPEATER_NODE "kbd" @@ -41,8 +45,11 @@ /* The keyboard device in the kernel. */ static device_t kbd_dev; -/* The converter. */ -static iconv_t cd; +/* The converter. + XXX: Here it is used by the fixed US layout code. It's not static because + xkb.c also needs a converter. This variable and it's initialization should + be moved there once XKB is supported in OSKit. */ +iconv_t cd; /* The status of various LEDs. */ struct { @@ -62,6 +69,18 @@ static char *repeater_node; /* The repeater node. */ static consnode_t cnode; + +#ifdef XKB_SUPPORT +/* CTRL + Alt + Backspace will terminate the console client by + default, this hardcoded behaviour can be disabled. */ +static int ctrlaltbs; + +/* The number of jiffies until repetition starts. */ +static int xkb_repeat_delay; + +/* The number of jiffies until the next repetition is generated. */ +static int xkb_repeat_interval; +#endif /* A list of scan codes generated by the keyboard, in the set 2 encoding. */ enum scancode @@ -597,6 +616,10 @@ gnumach_v1_input_next () } while (data_buf.type != KEYBD_EVENT); +#ifdef XKB_SUPPORT + /* XKB code work with set1 scancodes. */ + return data_buf.value.sc; +#else /* not XKB_SUPPORT */ /* Some fixed codes which are the same in set 1 and set 2, and have the UP flag set. */ if (data_buf.value.sc == SC_EXTENDED1 @@ -609,6 +632,7 @@ gnumach_v1_input_next () sc = sc_set1_to_set2[data_buf.value.sc &~ SC_SET1_FLAG_UP]; return sc | (up ? SC_FLAG_UP : 0); +#endif /* not XKB_SUPPORT */ } @@ -676,11 +700,139 @@ input_next () return sc; } +#ifdef XKB_SUPPORT +/* Read a keycode using the input_next routine. The translation from + scancodes is hardcoded. A configuration file should be used in the + near future because this is an UGLY HACK. */ +keycode_t +read_keycode (void) +{ + scancode_t sc = input_next (); + int release = 0; + + /* The keypress generated two keycodes. */ + if (sc == 0xE0) + { + sc = input_next (); + + release = sc & 0x80; + sc &= ~0x80; + + switch (sc) + { + case 0x1D: /* RCTRL. */ + sc = 101; + break; + case 0x38: /* RALT. */ + sc = 105; + break; + /* LRGUI MENU. */ + case 0x5B: /* LGUI. */ + sc = 107; + break; + case 0x5C: /* RGUI. */ + sc = 108; + break; + case 0x5D: /* MENU. */ + sc = 109; + break; + case 0x52: /* Insert. */ + sc = 98; + break; + case 0x47: /* Home. */ + sc = 89; + break; + case 0x49: /* Pg Up. */ + sc = 91; + break; + case 0x53: /* Delete. */ + sc = 99; + break; + case 0x4F: /* End. */ + sc = 95; + break; + case 0x51: /* Pg Down. */ + sc = 97; + break; + case 0x48: /* Arrow up. */ + sc = 90; + break; + case 0x50: /* Arrow down. */ + sc = 96; + break; + case 0x4b: /* Arrow left. */ + sc = 92; + break; + case 0x4d: /* Arrow right. */ + sc = 94; + break; + case 0x35: /* '/' */ + sc = 104; + break; + case 0x1C: /* KP_Enter. */ + sc = 100; + break; + default: + sc += 0x78; + } + + sc |= release; + } + else + release = sc & 0x80; + + return sc; +} +#endif /* XKB_SUPPORT */ /* The input loop. */ static any_t input_loop (any_t unused) { +#ifdef XKB_SUPPORT + /* XXX: until conversion from scancode to keycode is properly implemented + XKB won't work on anything but scancode set 1. + In the meanwhile, a fixed US layout implementation is used for OSKit + Mach. **/ + if (gnumach_v1_compat) + { + /* The previous keypress. */ + keycode_t prevkey = 0; + + while (1) + { + keypress_t key; + + key.keycode = read_keycode () + min_keys; + key.rel = key.keycode & 0x80; + key.redir = 0; + + if (!key.rel && key.keycode == prevkey) + key.repeat = 1; + else + key.repeat = 0; + + if (key.repeat) + continue; + + /* The keycombination CTRL+Alt+Backspace terminates the console + client. Keycodes instead of modifiers+symbols are used to + make it able to exit the client, even when the keymaps are + faulty. */ + if ((keystate[64].keypressed || keystate[113].keypressed) /* Alt */ + && (keystate[37].keypressed || keystate[109].keypressed) /* CTRL*/ + && keystate[22].keypressed && ctrlaltbs) /* Backspace. */ + console_exit (); + + if (!key.repeat) + xkb_input_key (key.keycode); + prevkey = key.keycode; + } + + return 0; + } +#endif /* XKB_SUPPORT */ + while (1) { enum scancode fsc = input_next (); @@ -1029,8 +1181,43 @@ input_loop (any_t unused) static const char doc[] = "PC Keyboard Driver"; +struct arguments +{ + int pos; +#ifdef XKB_SUPPORT + char *xkbdir; + char *keymapfile; + char *keymap; + char *composefile; + int ctrlaltbs; + int repeat_delay; + int repeat_interval; +#endif +}; + static const struct argp_option options[] = { +#ifdef XKB_SUPPORT +/* Some random ids for options available only in long form. */ +#define REPEAT_DELAY_ID 25425 +#define REPEAT_INTERVAL_ID 5322 + {"xkbdir", 'x', "DIR", 0, + "Directory containing the XKB configuration files" }, + {"keymapfile", 'f', "FILE", 0, + "File containing the keymap" }, + {"keymap", 'k', "SECTIONNAME" , 0, + "Choose keymap"}, + {"compose", 'o', "COMPOSEFILE", 0, + "Compose file to load (default none)"}, + {"ctrlaltbs", 'c', 0 , 0, + "CTRL + Alt + Backspace will exit the console client (default)."}, + {"no-ctrlaltbs", 'n', 0 , 0, + "CTRL + Alt + Backspace will not exit the console client."}, + {"repeat-delay", REPEAT_DELAY_ID, "DELAY", 0, + "Delay before pressed key starts repeating (measured in jiffies)"}, + {"repeat-interval", REPEAT_INTERVAL_ID, "INTERVAL", 0, + "Time elapsed between repeated keys (measured in jiffies)"}, +#endif /* XKB_SUPPORT */ {"repeat", 'r', "NODE", OPTION_ARG_OPTIONAL, "Set a repeater translator on NODE (default: " DEFAULT_REPEATER_NODE ")"}, { 0 } @@ -1039,10 +1226,43 @@ static const struct argp_option options[] = static error_t parse_opt (int key, char *arg, struct argp_state *state) { - int *pos = (int *) state->input; + struct arguments *arguments = state->input; switch (key) { +#ifdef XKB_SUPPORT + case 'x': + arguments->xkbdir = arg; + break; + + case 'f': + arguments->keymapfile = arg; + break; + + case 'k': + arguments->keymap = arg; + break; + + case 'o': + arguments->composefile = arg; + break; + + case 'c': + arguments->ctrlaltbs = 1; + break; + + case 'n': + arguments->ctrlaltbs = 0; + break; + + case REPEAT_DELAY_ID: + arguments->repeat_delay = atoi(arg); + break; + + case REPEAT_INTERVAL_ID: + arguments->repeat_interval = atoi(arg); + break; +#endif /* XKB_SUPPORT */ case 'r': repeater_node = arg ? arg: DEFAULT_REPEATER_NODE; break; @@ -1054,7 +1274,7 @@ parse_opt (int key, char *arg, struct argp_state *state) return ARGP_ERR_UNKNOWN; } - *pos = state->next; + arguments->pos = state->next; return 0; } @@ -1065,16 +1285,61 @@ static error_t pc_kbd_init (void **handle, int no_exit, int argc, char *argv[], int *next) { error_t err; - int pos = 1; + struct arguments arguments = + { + pos: 1 +#ifdef XKB_SUPPORT + , xkbdir: 0 + , keymapfile: 0 + , keymap: 0 + , composefile: 0 + , ctrlaltbs: 1 + , repeat_delay: -1 + , repeat_interval: -1 +#endif + }; /* Parse the arguments. */ err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_EXIT - | ARGP_SILENT, 0 , &pos); - *next += pos - 1; + | ARGP_SILENT, 0 , &arguments); + *next += arguments.pos - 1; if (err && err != EINVAL) return err; +#ifdef XKB_SUPPORT + if (!arguments.xkbdir) + { + arguments.xkbdir = XKB_DATA_DIR; + } + if (!arguments.keymapfile) + { + arguments.keymapfile = "keymap/hurd"; + } + if (arguments.repeat_delay <= 0) + { + arguments.repeat_delay = 50; + } + if (arguments.repeat_interval <= 0) + { + arguments.repeat_interval = 10; + } + + ctrlaltbs = arguments.ctrlaltbs; + xkb_repeat_delay = arguments.repeat_delay; + xkb_repeat_interval = arguments.repeat_interval; + + err = read_composefile (arguments.composefile); + if (err) + return err; + + xkb_data_init (); + err = xkb_load_layout (arguments.xkbdir, arguments.keymapfile, + arguments.keymap); + + if (err) + return err; +#endif /* XKB_SUPPORT */ return 0; } @@ -1124,6 +1389,9 @@ pc_kbd_start (void *handle) iconv_close (cd); return err; } +#ifdef XKB_SUPPORT + xkb_init_repeat (xkb_repeat_delay, xkb_repeat_interval); +#endif } update_leds (); |