aboutsummaryrefslogtreecommitdiff
path: root/console-client/pc-kbd.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
committerMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
commit09e69605b16070de8ce317d86ad736d665a58906 (patch)
tree7c0dc29f4fc660a44d2f7d6ec9d099cc4f8301a6 /console-client/pc-kbd.c
parentdbe4c7712b652b7ad3126e94c47b00fa2bbb0a05 (diff)
downloadhurd-09e69605b16070de8ce317d86ad736d665a58906.tar.gz
hurd-09e69605b16070de8ce317d86ad736d665a58906.tar.bz2
hurd-09e69605b16070de8ce317d86ad736d665a58906.zip
2002-09-17 Marcus Brinkmann <marcus@gnu.org>
* Makefile (prog-subdirs): Add console-client. sutils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * MAKEDEV.sh (mkdev: vcs): New console device. (mkdev: tty[0-9a-f]|tty[0-9][0-9a-f]): Replaced with new rules for tty[1-9][0-9]. utils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * console-ncurses.c: File removed (the ncursesw console client is now a driver in the console-client). * Makefile: Revert 2002-08-22 change: Do not include`../config.make'. (targets) [LIBNCURSES]: Removed. (SRCS) [LIBNCURSES]: Likewise. (HURDLIBS) [LIBNCURSES]: Likewise. (console-ncurses): Target removed. (console-ncurses-CPPFLAGS): Removed. (console-ncurses-LDLIBS): Likewise. console-client/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * Makefile, bdf.c, bdf.h, bell.h, console.c, display.h, driver.c, driver.h, generic-speaker.c, input.h, pc-kbd.c, timer.c, timer.h, unicode.h, vga.c, vga-dynacolor.c, vga-dynacolor.h, vga-dynafont.c, vga-dynafont.h, vga-hw.h, vga-support.c, vga-support.h: New file.
Diffstat (limited to 'console-client/pc-kbd.c')
-rw-r--r--console-client/pc-kbd.c824
1 files changed, 824 insertions, 0 deletions
diff --git a/console-client/pc-kbd.c b/console-client/pc-kbd.c
new file mode 100644
index 00000000..3ec6404e
--- /dev/null
+++ b/console-client/pc-kbd.c
@@ -0,0 +1,824 @@
+/* pc-kbd.c - The PC Keyboard input driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <iconv.h>
+#include <sys/mman.h>
+
+#include <device/device.h>
+#include <cthreads.h>
+
+#include <hurd/console.h>
+#include <hurd/cons.h>
+
+#include "driver.h"
+
+
+/* The keyboard device in the kernel. */
+static device_t kbd_dev;
+
+/* The converter. */
+static iconv_t cd;
+
+/* Forward declaration. */
+static struct input_ops pc_kbd_ops;
+
+
+/* A list of scan codes generated by the keyboard. */
+enum scancode
+ {
+ SC_ESC = 0x01,
+ SC_1 = 0x02,
+ SC_2 = 0x03,
+ SC_3 = 0x04,
+ SC_4 = 0x05,
+ SC_5 = 0x06,
+ SC_6 = 0x07,
+ SC_7 = 0x08,
+ SC_8 = 0x09,
+ SC_9 = 0x0A,
+ SC_0 = 0x0B,
+ SC_MINUS = 0x0C, /* - */
+ SC_EQUAL = 0x0D, /* = */
+ SC_BACKSPACE = 0x0E,
+ SC_TAB = 0x0F,
+ SC_Q = 0x10,
+ SC_W = 0x11,
+ SC_E = 0x12,
+ SC_R = 0x13,
+ SC_T = 0x14,
+ SC_Y = 0x15,
+ SC_U = 0x16,
+ SC_I = 0x17,
+ SC_O = 0x18,
+ SC_P = 0x19,
+ SC_LEFT_BRACKET = 0x1A, /* [ */
+ SC_RIGHT_BRACKET = 0x1B, /* ] */
+ SC_ENTER = 0x1C,
+ SC_LEFT_CTRL = 0x1D,
+ SC_A = 0x1E,
+ SC_S = 0x1F,
+ SC_D = 0x20,
+ SC_F = 0x21,
+ SC_G = 0x22,
+ SC_H = 0x23,
+ SC_J = 0x24,
+ SC_K = 0x25,
+ SC_L = 0x26,
+ SC_SEMICOLON = 0x27, /* ; */
+ SC_APOSTROPHE = 0x28, /* ' */
+ SC_BACKQUOTE = 0x29, /* ` */
+ SC_LEFT_SHIFT = 0x2A,
+ SC_BACKSLASH = 0x2B, /* \ */
+ SC_Z = 0x2C,
+ SC_X = 0x2D,
+ SC_C = 0x2E,
+ SC_V = 0x2F,
+ SC_B = 0x30,
+ SC_N = 0x31,
+ SC_M = 0x32,
+ SC_COMMA = 0x33, /* , */
+ SC_PERIOD = 0x34, /* . */
+ SC_SLASH = 0x35, /* / */
+ SC_RIGHT_SHIFT = 0x36,
+ SC_PAD_ASTERISK = 0x37,
+ SC_LEFT_ALT = 0x38,
+ SC_SPACE = 0x39,
+ SC_CAPSLOCK = 0x3A,
+ SC_F1 = 0x3B,
+ SC_F2 = 0x3C,
+ SC_F3 = 0x3D,
+ SC_F4 = 0x3E,
+ SC_F5 = 0x3F,
+ SC_F6 = 0x40,
+ SC_F7 = 0x41,
+ SC_F8 = 0x42,
+ SC_F9 = 0x43,
+ SC_F10 = 0x44,
+ SC_NUMLOCK = 0x45,
+ SC_SCROLLLOCK = 0x46,
+ SC_PAD_7 = 0x47,
+ SC_PAD_8 = 0x48,
+ SC_PAD_9 = 0x49,
+ SC_PAD_MINUS = 0x4A,
+ SC_PAD_4 = 0x4B,
+ SC_PAD_5 = 0x4C,
+ SC_PAD_6 = 0x4D,
+ SC_PAD_PLUS = 0x4E,
+ SC_PAD_1 = 0x4F,
+ SC_PAD_2 = 0x50,
+ SC_PAD_3 = 0x51,
+ SC_PAD_0 = 0x52,
+ SC_PAD_DECIMAL = 0x53,
+ SC_SYSREQ = 0x54,
+ SC_F11 = 0x57,
+ SC_F12 = 0x58,
+ SC_FLAG_UP = 0x80, /* ORed to basic scancode. */
+ SC_EXTENDED1 = 0xE0, /* One code follows. */
+ SC_EXTENDED2 = 0xE1, /* Two codes follow (only used for Pause). */
+ SC_ERROR = 0xFF /* Too many keys held down. */
+ };
+
+/* Codes which can follow SC_EXTENDED1. */
+enum scancode_x1
+ {
+ SC_X1_PAD_ENTER = 0x1C,
+ SC_X1_RIGHT_CTRL = 0x1D,
+ SC_X1_PAD_SLASH = 0x35,
+ SC_X1_PRTSC = 0x37,
+ SC_X1_RIGHT_ALT = 0x38,
+ SC_X1_BREAK = 0x46,
+ SC_X1_HOME = 0x47,
+ SC_X1_UP = 0x48,
+ SC_X1_PGUP = 0x49,
+ SC_X1_LEFT = 0x4B,
+ SC_X1_RIGHT = 0x4D,
+ SC_X1_END = 0x4F,
+ SC_X1_DOWN = 0x50,
+ SC_X1_PGDN = 0x51,
+ SC_X1_INS = 0x52,
+ SC_X1_DEL = 0x53
+ };
+
+
+/* Scancode to Unicode mapping. The empty string stands for the NULL
+ character. */
+char *sc_to_kc[][7] =
+ {
+ /*None, Shift, Ctrl, LAlt, S+LAlt, C+LAlt, RAlt */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "\e", "\e", "\e", "\e\e", "\e\e", "\e\e", "\e" }, /* SC_ESC. */
+ { "1", "!", 0, "\e1", "\e!", 0, "1" }, /* SC_1. */
+ { "2", "@", "", "\e2", "\e@", 0, "2" }, /* SC_2. */
+ { "3", "#", "\e", "\e3", "\e#", 0, "3" }, /* SC_3. */
+ { "4", "$", "\x1c", "\e4", "\e$", "\e\x1c", "4" }, /* SC_4. */
+ { "5", "%", "\x1d", "\e5", "\e%", 0, "5" }, /* SC_5. */
+ { "6", "^", "\x1e", "\e6", "\e^", 0, "6" }, /* SC_6. */
+ { "7", "&", "\x1f", "\e7", "\e&", "\e\x1f", "7" }, /* SC_7. */
+ { "8", "*", "\x7f", "\e8", "\e*", 0, "8" }, /* SC_8. */
+ { "9", "(", 0, "\e9", "\e(", 0, "9" }, /* SC_9. */
+ { "0", ")", 0, "\e0", "\e)", 0, "0" }, /* SC_0. */
+ { "-", "_", "\x1f", "\e-", "\e_", "\e\x1f", "-" }, /* SC_MINUS. */
+ { "=", "+", 0, "\e=", "\e+", 0, "=" }, /* SC_EQUAL. */
+ { CONS_KEY_BACKSPACE, CONS_KEY_BACKSPACE, CONS_KEY_BACKSPACE, /* XXX */ 0,
+ CONS_KEY_BACKSPACE, /*XXX*/ 0, CONS_KEY_BACKSPACE }, /* SC_BACKSPACE. */
+ /* XXX back tab? */
+ { "\t", "\t", "\t", "\e\t", "\e\t", "\e\t", "\t" }, /* SC_TAB. */
+ { "q", "Q", "\x11", "\eq", "\eQ", "\e\x11", "q" }, /* SC_Q. */
+ { "w", "W", "\x17", "\ew", "\eW", "\e\x17", "w" }, /* SC_W. */
+ { "e", "E", "\x05", "\ee", "\eE", "\e\x05","\xe2\x82\xac" }, /* SC_E. */
+ { "r", "R", "\x12", "\er", "\eR", "\e\x12", "r" }, /* SC_R. */
+ { "t", "T", "\x14", "\et", "\eT", "\e\x14", "t" }, /* SC_T. */
+ { "y", "Y", "\x19", "\ey", "\eY", "\e\x19", "y" }, /* SC_Y. */
+ { "u", "U", "\x15", "\eu", "\eU", "\e\x15", "u" }, /* SC_U. */
+ { "i", "I", "\x09", "\ei", "\eI", "\e\x09", "i" }, /* SC_I. */
+ { "o", "O", "\x0f", "\eo", "\eO", "\e\x0f", "o" }, /* SC_O. */
+ { "p", "P", "\x10", "\ep", "\eP", "\e\x10", "p" }, /* SC_P. */
+ { "[", "{", "\e", "\e[", "\e{", 0, 0 }, /* SC_LEFT_BRACKET. */
+ { "]", "}", "\x1d", "\e]", "\e}", "\e\x1d", "~" }, /* SC_RIGHT_BRACKET. */
+ {"\x0d","\x0d", "\x0d","\e\x0d","\e\x0d","\e\x0d","\x0d" }, /* SC_ENTER. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_CTRL. XXX */
+ { "a", "A", "\x01", "\ea", "\eA", "\e\x01", "a" }, /* SC_A. */
+ { "s", "S", "\x13", "\es", "\eS", "\e\x13", "s" }, /* SC_S. */
+ { "d", "D", "\x04", "\ed", "\eD", "\e\x04", "d" }, /* SC_D. */
+ { "f", "F", "\x06", "\ef", "\eF", "\e\x06", "f" }, /* SC_F. */
+ { "g", "G", "\x07", "\eg", "\eG", "\e\x07", "g" }, /* SC_G. */
+ { "h", "H", "\x08", "\eh", "\eH", "\e\x08", "h" }, /* SC_H. */
+ { "j", "J", "\x0a", "\ej", "\eJ", "\e\x0a", "j" }, /* SC_J. */
+ { "k", "K", "\x0b", "\ek", "\eK", "\e\x0b", "k" }, /* SC_K. */
+ { "l", "L", "\x0c", "\el", "\eL", "\e\x0c", "l" }, /* SC_L. */
+ { ";", ":", 0, "\e;", "\e:", 0, 0 }, /* SC_SEMICOLON. */
+ { "'", "\"", "\x07", "\e'", "\e\"", 0, 0 }, /* SC_APOSTROPHE. */
+ { "`", "~", 0, "\e`", "\e~", 0, 0 }, /* SC_BACKQUOTE. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_SHIFT. */
+ { "\\", "|", "\x1c", "\e\\", "\e|", 0, 0 }, /* SC_BACKSLASH. */
+ { "z", "Z", "\x1a", "\ez", "\eZ", "\e\x1a", "z" }, /* SC_Z. */
+ { "x", "X", "\x18", "\ex", "\eX", "\e\x18", "x" }, /* SC_X. */
+ { "c", "C", "\x03", "\ec", "\eC", "\e\x03", "\xc2\xa2" }, /* SC_C. */
+ { "v", "V", "\x16", "\ev", "\eV", "\e\x16", "v" }, /* SC_V. */
+ { "b", "B", "\x02", "\eb", "\eB", "\e\x02", "b" }, /* SC_B. */
+ { "n", "N", "\x0e", "\en", "\eN", "\e\x0e", "n" }, /* SC_N. */
+ { "m", "M", "\x0d", "\em", "\eM", "\e\x0d", "m" }, /* SC_M. */
+ { ",", "<", 0, "\e,", "\e<", 0, 0 }, /* SC_COMMA. */
+ { ".", ">", 0, "\e.", "\e>", 0, 0 }, /* SC_PERIOD. */
+ { "/", "?", "\x7f", "\e/", "\e?", 0, 0 }, /* SC_SLASH. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_RIGHT_SHIFT. */
+ { "*", "*", "*", "*", "*", "*", "*" }, /* SC_PAD_ASTERISK. XXX */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_ALT. XXX */
+ { " ", " ", "", "\e ", "\e ", /*XXX*/0, " " }, /* SC_SPACE. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_CAPSLOCK. */
+ { CONS_KEY_F1, CONS_KEY_F13, 0, 0, 0, 0, 0 }, /* SC_F1. */
+ { CONS_KEY_F2, CONS_KEY_F14, 0, 0, 0, 0, 0 }, /* SC_F2. */
+ { CONS_KEY_F3, CONS_KEY_F15, 0, 0, 0, 0, 0 }, /* SC_F3. */
+ { CONS_KEY_F4, CONS_KEY_F16, 0, 0, 0, 0, 0 }, /* SC_F4. */
+ { CONS_KEY_F5, CONS_KEY_F17, 0, 0, 0, 0, 0 }, /* SC_F5. */
+ { CONS_KEY_F6, CONS_KEY_F18, 0, 0, 0, 0, 0 }, /* SC_F6. */
+ { CONS_KEY_F7, CONS_KEY_F19, 0, 0, 0, 0, 0 }, /* SC_F7. */
+ { CONS_KEY_F8, CONS_KEY_F20, 0, 0, 0, 0, 0 }, /* SC_F8. */
+ { CONS_KEY_F9, 0, 0, 0, 0, 0, 0 }, /* SC_F9. */
+ { CONS_KEY_F10, 0, 0, 0, 0, 0, 0 }, /* SC_F10. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_NUMLOCK. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_SCROLLLOCK. */
+ { CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME, 0, 0, 0, 0 }, /* SC_PAD_7. */
+ { CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP, 0, 0, 0, 0 }, /* SC_PAD_8. */
+ { CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE,0, 0, 0, 0 }, /* SC_PAD_9. */
+ { "-", "-", "-", "-", "-", "-", "-" }, /* SC_PAD_MINUS. */
+ { CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT, 0, 0, 0, 0 }, /* SC_PAD_4. */
+ {/* XXX */ "\e[G", "\e[G", "\e[G", 0, 0, 0, 0 }, /* SC_PAD_5. */
+ { CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT,0, 0, 0, 0 }, /* SC_PAD_6. */
+ { "+", "+", "+", "+", "+", "+", "+" }, /* SC_PAD_MINUS. */
+ { CONS_KEY_END, CONS_KEY_END, CONS_KEY_END, 0, 0, 0, 0 }, /* SC_PAD_1. */
+ { CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN, 0, 0, 0, 0 }, /* SC_PAD_2. */
+ { CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE,0, 0, 0, 0 }, /* SC_PAD_3. */
+ { CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC, 0, 0, 0, 0 }, /* SC_PAD_0. */
+ { CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC, 0, 0, 0, 0 }, /* SC_PAD_DECIMAL. */
+ { 0, 0, /*XX*/0, 0, 0, 0, 0 }, /* SC_SYSREQ. */
+ { CONS_KEY_F11, 0, 0, 0, 0, 0, 0 }, /* SC_F11. */
+ { CONS_KEY_F12, 0, 0, 0, 0, 0, 0 } /* SC_F12. */
+ };
+
+char *sc_x1_to_kc[][7] =
+ {
+ /* None, Shift, Ctrl, LAlt, S+LAlt, C+LAlt, RAlt */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { "\n", "\n", "\n", "\n", "\n", "\n", 0 }, /* SC_X1_PAD_ENTER. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_RIGHT_CTRL. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "/", "/", "/", "/", "/", "/", 0 }, /* SC_X1_PAD_SLASH. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_PRTSC. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_RIGHT_ALT. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { "\e[P", "\e[P", "\e[P", "\e[P", "\e[P", "\e[P","\e[P" }, /* SC_X1_BREAK. */
+ { CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME,
+ CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME }, /* SC_X1_HOME. */
+ { CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP,
+ CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP }, /* SC_X1_UP. */
+ { CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE,
+ CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE }, /* SC_X1_PGUP. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT,
+ CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT }, /* SC_X1_LEFT. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT,
+ CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT }, /* SC_X1_RIGHT. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_END, CONS_KEY_END, CONS_KEY_END, CONS_KEY_END,
+ CONS_KEY_END, CONS_KEY_END, CONS_KEY_END }, /* SC_X1_END. */
+ { CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN,
+ CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN }, /* SC_X1_DOWN. */
+ { CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE,
+ CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE }, /* SC_X1_PGDN. */
+ { CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC,
+ CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC }, /* SC_X1_INS. */
+ { CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC,
+ CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC } /* SC_X1_DEL. */
+ };
+
+
+/* This gross stuff is cut & pasted from Mach sources, as Mach doesn't
+ export the interface we are using here. */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+typedef u_short kev_type; /* kd event type */
+
+/* (used for event records) */
+struct mouse_motion {
+ short mm_deltaX; /* units? */
+ short mm_deltaY;
+};
+typedef u_char Scancode;
+
+typedef struct {
+ kev_type type; /* see below */
+ struct timeval time; /* timestamp */
+ union { /* value associated with event */
+ boolean_t up; /* MOUSE_LEFT .. MOUSE_RIGHT */
+ Scancode sc; /* KEYBD_EVENT */
+ struct mouse_motion mmotion; /* MOUSE_MOTION */
+ } value;
+} kd_event;
+#define m_deltaX mmotion.mm_deltaX
+#define m_deltaY mmotion.mm_deltaY
+
+/*
+ * kd_event ID's.
+ */
+#define MOUSE_LEFT 1 /* mouse left button up/down */
+#define MOUSE_MIDDLE 2
+#define MOUSE_RIGHT 3
+#define MOUSE_MOTION 4 /* mouse motion */
+#define KEYBD_EVENT 5 /* key up/down */
+
+
+#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */
+#define IOC_OUT 0x40000000 /* copy out parameters */
+#define IOC_IN 0x80000000U /* copy in parameters */
+#define _IOC(inout,group,num,len) \
+ (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
+#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
+#define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t))
+
+#define KDSKBDMODE _IOW('K', 1, int) /* set keyboard mode */
+#define KB_EVENT 1
+#define KB_ASCII 2
+
+#define KDGKBDTYPE _IOR('K', 2, int) /* get keyboard type */
+#define KB_VANILLAKB 0
+
+/* End of Mach code. */
+
+
+/* The input loop. */
+static any_t
+input_loop (any_t unused)
+{
+ while (1)
+ {
+ kd_event data_buf;
+
+ /* io_buf_ptr_t is (char *), not (void *). So I have a few
+ casts to quiet warnings. */
+ io_buf_ptr_t data_ptr = (void *) &data_buf;
+ mach_msg_type_number_t data_cnt = sizeof data_buf;
+
+ /* I suppose this could be sped up by reading multiple events
+ per call. But that isn't important since this is called just
+ a couple of times per keystroke. Things might be different
+ if we supported a mouse. */
+ error_t err = device_read (kbd_dev, /* device */
+ 0, /* mode: could be D_NOWAIT */
+ -1, /* recnum: not used by kbdread */
+ sizeof (kd_event), /* bytes_wanted */
+ &data_ptr, &data_cnt);
+ if (err)
+ /* XXX The error occured likely because KBD_DEV was closed, so
+ terminate. */
+ return 0;
+
+ if ((void *) data_ptr != &data_buf)
+ {
+ /* Copy the structure to the expected place. */
+ data_buf = *(kd_event *) data_ptr;
+ munmap (data_ptr, data_cnt);
+ }
+
+ if (data_buf.type == KEYBD_EVENT)
+ {
+ enum scancode fsc = data_buf.value.sc;
+ enum scancode sc = fsc & 0x7f;
+ int down = !(fsc & SC_FLAG_UP);
+ char buf[100];
+ size_t size = 0;
+ int modifier = -1;
+
+ static struct {
+ wchar_t direct;
+ unsigned int extended : 2;
+ unsigned int left_shift : 1;
+ unsigned int right_shift : 1;
+ unsigned int caps_lock : 1;
+ unsigned int caps_lock_pressed : 1;
+ unsigned int left_ctrl : 1;
+ unsigned int right_ctrl : 1;
+ unsigned int left_alt : 1;
+ unsigned int right_alt : 1;
+ unsigned int num_lock : 1;
+ unsigned int num_lock_pressed : 1;
+ } state;
+
+ if (!state.left_alt && !state.right_alt)
+ {
+ if (state.left_ctrl || state.right_ctrl)
+ modifier = 2;
+ else if (state.left_shift || state.right_shift)
+ modifier = 1;
+ else
+ modifier = 0;
+ }
+ else if (state.left_alt)
+ {
+ if (state.left_ctrl || state.right_ctrl)
+ modifier = 5;
+ if (state.left_shift || state.right_shift)
+ modifier = 4;
+ else
+ modifier = 3;
+ }
+ else if (state.right_alt)
+ {
+ if (!state.left_ctrl && !state.right_ctrl
+ && !state.left_shift && !state.right_shift)
+ modifier = 6;
+ }
+
+ if (!state.extended)
+ {
+ if (fsc == SC_EXTENDED1)
+ state.extended = 1;
+ else if (fsc == SC_EXTENDED2)
+ state.extended = 2;
+ else if (sc == SC_LEFT_SHIFT)
+ state.left_shift = down;
+ else if (sc == SC_RIGHT_SHIFT)
+ state.right_shift = down;
+ else if (sc == SC_CAPSLOCK)
+ {
+ if (down && !state.caps_lock_pressed)
+ {
+ state.caps_lock = !state.caps_lock;
+ state.caps_lock_pressed = 1;
+ }
+ else if (!down)
+ state.caps_lock_pressed = 0;
+ }
+ else if (sc == SC_NUMLOCK)
+ {
+ if (down && !state.num_lock_pressed)
+ {
+ state.num_lock = !state.num_lock;
+ state.num_lock_pressed = 1;
+ }
+ else if (!down)
+ state.num_lock_pressed = 0;
+ }
+ else if (sc == SC_LEFT_CTRL)
+ state.left_ctrl = down;
+ else if (sc == SC_LEFT_ALT)
+ state.left_alt = down;
+ else if (state.left_alt && down && sc >= SC_F1 && sc <= SC_F10) /* XXX */
+ console_switch (1 + (sc - SC_F1), 0);
+ else if (state.left_alt && state.left_ctrl && down && sc == SC_BACKSPACE)
+ console_exit ();
+ else if (state.right_alt && down && sc == SC_PAD_0) /* XXX */
+ state.direct = (state.direct << 4) | 0x0;
+ else if (state.right_alt && down && sc == SC_PAD_1) /* XXX */
+ state.direct = (state.direct << 4) | 0x1;
+ else if (state.right_alt && down && sc == SC_PAD_2) /* XXX */
+ state.direct = (state.direct << 4) | 0x2;
+ else if (state.right_alt && down && sc == SC_PAD_3) /* XXX */
+ state.direct = (state.direct << 4) | 0x3;
+ else if (state.right_alt && down && sc == SC_PAD_4) /* XXX */
+ state.direct = (state.direct << 4) | 0x4;
+ else if (state.right_alt && down && sc == SC_PAD_5) /* XXX */
+ state.direct = (state.direct << 4) | 0x5;
+ else if (state.right_alt && down && sc == SC_PAD_6) /* XXX */
+ state.direct = (state.direct << 4) | 0x6;
+ else if (state.right_alt && down && sc == SC_PAD_7) /* XXX */
+ state.direct = (state.direct << 4) | 0x7;
+ else if (state.right_alt && down && sc == SC_PAD_8) /* XXX */
+ state.direct = (state.direct << 4) | 0x8;
+ else if (state.right_alt && down && sc == SC_PAD_9) /* XXX */
+ state.direct = (state.direct << 4) | 0x9;
+ else if (state.right_alt && down && sc == SC_NUMLOCK) /* XXX */
+ state.direct = (state.direct << 4) | 0xa;
+ else if (state.right_alt && down && sc == SC_PAD_ASTERISK) /* XXX */
+ state.direct = (state.direct << 4) | 0xc;
+ else if (state.right_alt && down && sc == SC_PAD_MINUS) /* XXX */
+ state.direct = (state.direct << 4) | 0xd;
+ else if (state.right_alt && down && sc == SC_PAD_PLUS) /* XXX */
+ state.direct = (state.direct << 4) | 0xe;
+ else if (down && sc < sizeof (sc_to_kc)/sizeof (sc_to_kc[0]))
+ {
+#if QUAERENDO_INVENIETIS
+ if (state.left_alt && state.right_alt
+ && sc_to_kc[sc][0][0] >= '0' && sc_to_kc[sc][0][0] <= '9'
+ && sc_to_kc[sc][0][1] == '\0')
+ console_deprecated (sc_to_kc[sc][0][0] - '0');
+ else
+#endif
+ {
+ /* Special rule for caps lock. */
+ if (modifier == 0 && state.caps_lock
+ && sc_to_kc[sc][modifier]
+ && sc_to_kc[sc][modifier][0] >= 'a'
+ && sc_to_kc[sc][modifier][0] <= 'z'
+ && sc_to_kc[sc][modifier][1] == '\0')
+ modifier = 1;
+ else if (state.num_lock && sc == SC_PAD_0)
+ {
+ modifier = 0;
+ sc = SC_0;
+ }
+ else if (state.num_lock && sc == SC_PAD_1)
+ {
+ modifier = 0;
+ sc = SC_1;
+ }
+ else if (state.num_lock && sc == SC_PAD_2)
+ {
+ modifier = 0;
+ sc = SC_2;
+ }
+ else if (state.num_lock && sc == SC_PAD_3)
+ {
+ modifier = 0;
+ sc = SC_3;
+ }
+ else if (state.num_lock && sc == SC_PAD_4)
+ {
+ modifier = 0;
+ sc = SC_4;
+ }
+ else if (state.num_lock && sc == SC_PAD_5)
+ {
+ modifier = 0;
+ sc = SC_5;
+ }
+ else if (state.num_lock && sc == SC_PAD_6)
+ {
+ modifier = 0;
+ sc = SC_6;
+ }
+ else if (state.num_lock && sc == SC_PAD_7)
+ {
+ modifier = 0;
+ sc = SC_7;
+ }
+ else if (state.num_lock && sc == SC_PAD_8)
+ {
+ modifier = 0;
+ sc = SC_8;
+ }
+ else if (state.num_lock && sc == SC_PAD_9)
+ {
+ modifier = 0;
+ sc = SC_9;
+ }
+ else if (state.num_lock && sc == SC_PAD_DECIMAL)
+ {
+ modifier = 0;
+ sc = SC_PERIOD;
+ }
+
+ if (modifier >= 0 && sc_to_kc[sc][modifier])
+ {
+ if (!sc_to_kc[sc][modifier][0])
+ {
+ /* Special meaning, emit NUL. */
+ assert (size < 100);
+ buf[size++] = '\0';
+ }
+ else
+ {
+ assert (size
+ < 101 - strlen(sc_to_kc[sc][modifier]));
+ strcpy (&buf[size], sc_to_kc[sc][modifier]);
+ size += strlen (sc_to_kc[sc][modifier]);
+ }
+ }
+ }
+ }
+ }
+ else if (state.extended == 1)
+ {
+ state.extended = 0;
+ if (sc == SC_X1_RIGHT_CTRL)
+ state.right_ctrl = down;
+ else if (sc == SC_X1_RIGHT_ALT)
+ {
+ state.right_alt = down;
+
+ /* Handle the AltGR+Keypad direct input. */
+ if (down)
+ state.direct = (wchar_t) 0;
+ else
+ {
+ if (state.direct != (wchar_t) 0)
+ {
+ char *buffer = &buf[size];
+ size_t left = sizeof (buf) - size;
+ char *inbuf = (char *) &state.direct;
+ size_t inbufsize = sizeof (wchar_t);
+ int nr;
+
+ nr = iconv (cd, &inbuf, &inbufsize, &buffer, &left);
+ if (nr == (size_t) -1)
+ {
+ if (errno == E2BIG)
+ console_error (L"Input buffer overflow");
+ else if (errno == EILSEQ)
+ console_error
+ (L"Input contained invalid byte sequence");
+ else if (errno == EINVAL)
+ console_error
+ (L"Input contained incomplete byte sequence");
+ else
+ console_error
+ (L"Input caused unexpected error");
+ }
+ size = sizeof (buf) - left;
+ }
+ }
+ }
+ else if (state.right_alt && down && sc == SC_X1_PAD_SLASH) /* XXX */
+ state.direct = (state.direct << 4) | 0xb;
+ else if (state.right_alt && down && sc == SC_X1_PAD_ENTER) /* XXX */
+ state.direct = (state.direct << 4) | 0xf;
+ else if (state.left_alt && down && sc == SC_X1_RIGHT) /* XXX */
+ console_switch (0, 1);
+ else if (state.left_alt && down && sc == SC_X1_LEFT) /* XXX */
+ console_switch (0, -1);
+ else if (state.left_alt && down && sc == SC_X1_UP) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_LINES, 1);
+ else if (state.left_alt && down && sc == SC_X1_DOWN) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_LINES, -1);
+ else if (state.right_shift && down && sc == SC_X1_PGUP) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_SCREENS, 0.5);
+ else if (state.right_shift && down && sc == SC_X1_PGDN) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_SCREENS, -0.5);
+ else if (down && sc < sizeof (sc_x1_to_kc)/sizeof (sc_x1_to_kc[0]))
+ {
+ if (modifier >= 0 && sc_x1_to_kc[sc][modifier])
+ {
+ assert (size < 101 - strlen(sc_x1_to_kc[sc][modifier]));
+ strcpy (&buf[size], sc_x1_to_kc[sc][modifier]);
+ size += strlen (sc_x1_to_kc[sc][modifier]);
+ }
+ }
+ }
+ else if (state.extended == 2)
+ state.extended = 3;
+ else if (state.extended == 3)
+ state.extended = 0;
+
+ if (size)
+ console_input (buf, size);
+ }
+ }
+ return 0;
+}
+
+
+
+/* Initialize the PC keyboard driver. */
+static error_t
+pc_kbd_init (void **handle, int no_exit, int argc, char *argv[], int *next)
+{
+ return 0;
+}
+
+
+/* Start the PC keyboard driver. */
+static error_t
+pc_kbd_start (void *handle)
+{
+ error_t err;
+ device_t device_master;
+ int data[1];
+
+ cd = iconv_open ("UTF-8", "WCHAR_T");
+ if (cd == (iconv_t) -1)
+ return errno;
+
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ {
+ iconv_close (cd);
+ return err;
+ }
+
+ err = device_open (device_master, D_READ, "kbd", &kbd_dev);
+ mach_port_deallocate (mach_task_self (), device_master);
+ if (err)
+ {
+ iconv_close (cd);
+ return err;
+ }
+
+ data[0] = KB_EVENT;
+ err = device_set_status (kbd_dev, KDSKBDMODE, data, 1);
+ if (err)
+ {
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+ return err;
+ }
+
+ err = driver_add_input (&pc_kbd_ops, NULL);
+ if (err)
+ {
+ device_set_status (kbd_dev, KDSKBDMODE, data, 1);
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+ return err;
+ }
+ cthread_detach (cthread_fork (input_loop, NULL));
+
+ return 0;
+}
+
+/* Deinitialize the PC keyboard driver. */
+static error_t
+pc_kbd_fini (void *handle, int force)
+{
+ int data[1];
+
+ driver_remove_input (&pc_kbd_ops, NULL);
+ data[0] = KB_ASCII;
+ device_set_status (kbd_dev, KDSKBDMODE, data, 1);
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+
+ return 0;
+}
+
+
+/* Set the scroll lock status indication (Scroll LED) to ONOFF. */
+static error_t
+pc_kbd_set_scroll_lock_status (void *handle, int onoff)
+{
+ /* XXX */
+ return 0;
+}
+
+
+struct driver_ops driver_pc_kbd_ops =
+ {
+ pc_kbd_init,
+ pc_kbd_start,
+ pc_kbd_fini
+ };
+
+static struct input_ops pc_kbd_ops =
+ {
+ pc_kbd_set_scroll_lock_status,
+ NULL
+ };