summaryrefslogtreecommitdiff
path: root/hw/kdrive/linux/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/kdrive/linux/keyboard.c')
-rw-r--r--hw/kdrive/linux/keyboard.c439
1 files changed, 439 insertions, 0 deletions
diff --git a/hw/kdrive/linux/keyboard.c b/hw/kdrive/linux/keyboard.c
new file mode 100644
index 000000000..87fc0962e
--- /dev/null
+++ b/hw/kdrive/linux/keyboard.c
@@ -0,0 +1,439 @@
+/*
+ * $Id$
+ *
+ * Copyright © 1999 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "kdrive.h"
+#include "kkeymap.h"
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+#include <X11/keysym.h>
+#include <termios.h>
+
+extern int LinuxConsoleFd;
+
+static const KeySym linux_to_x[256] = {
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, XK_Escape,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ XK_space, XK_exclam, XK_quotedbl, XK_numbersign,
+ XK_dollar, XK_percent, XK_ampersand, XK_apostrophe,
+ XK_parenleft, XK_parenright, XK_asterisk, XK_plus,
+ XK_comma, XK_minus, XK_period, XK_slash,
+ XK_0, XK_1, XK_2, XK_3,
+ XK_4, XK_5, XK_6, XK_7,
+ XK_8, XK_9, XK_colon, XK_semicolon,
+ XK_less, XK_equal, XK_greater, XK_question,
+ XK_at, XK_A, XK_B, XK_C,
+ XK_D, XK_E, XK_F, XK_G,
+ XK_H, XK_I, XK_J, XK_K,
+ XK_L, XK_M, XK_N, XK_O,
+ XK_P, XK_Q, XK_R, XK_S,
+ XK_T, XK_U, XK_V, XK_W,
+ XK_X, XK_Y, XK_Z, XK_bracketleft,
+ XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore,
+ XK_grave, XK_a, XK_b, XK_c,
+ XK_d, XK_e, XK_f, XK_g,
+ XK_h, XK_i, XK_j, XK_k,
+ XK_l, XK_m, XK_n, XK_o,
+ XK_p, XK_q, XK_r, XK_s,
+ XK_t, XK_u, XK_v, XK_w,
+ XK_x, XK_y, XK_z, XK_braceleft,
+ XK_bar, XK_braceright, XK_asciitilde, XK_Delete,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol,
+ XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling,
+ XK_currency, XK_yen, XK_brokenbar, XK_section,
+ XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft,
+ XK_notsign, XK_hyphen, XK_registered, XK_macron,
+ XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior,
+ XK_acute, XK_mu, XK_paragraph, XK_periodcentered,
+ XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright,
+ XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown,
+ XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde,
+ XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla,
+ XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis,
+ XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis,
+ XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute,
+ XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply,
+ XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex,
+ XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp,
+ XK_agrave, XK_aacute, XK_acircumflex, XK_atilde,
+ XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla,
+ XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis,
+ XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis,
+ XK_eth, XK_ntilde, XK_ograve, XK_oacute,
+ XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division,
+ XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex,
+ XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis
+};
+
+static unsigned char tbl[KD_MAX_WIDTH] =
+{
+ 0,
+ 1 << KG_SHIFT,
+ (1 << KG_ALT),
+ (1 << KG_ALT) | (1 << KG_SHIFT)
+};
+
+static void
+readKernelMapping()
+{
+ KeySym *k;
+ int i, j;
+ struct kbentry kbe;
+ int minKeyCode, maxKeyCode;
+
+ minKeyCode = NR_KEYS;
+ maxKeyCode = 0;
+ k = kdKeymap;
+ for (i = 0;
+ i < NR_KEYS && (maxKeyCode - minKeyCode + 1) < KD_MAX_LENGTH;
+ ++i)
+ {
+ kbe.kb_index = i;
+
+ for (j = 0; j < KD_MAX_WIDTH; ++j)
+ {
+ unsigned short kval;
+
+ k[j] = NoSymbol;
+
+ kbe.kb_table = tbl[j];
+ if (ioctl(LinuxConsoleFd, KDGKBENT, &kbe))
+ continue;
+
+ kval = KVAL(kbe.kb_value);
+ switch (KTYP(kbe.kb_value))
+ {
+ case KT_LATIN:
+ case KT_LETTER:
+ k[j] = linux_to_x[kval];
+ break;
+
+ case KT_FN:
+ if (kval <= 19)
+ k[j] = XK_F1 + kval;
+ else switch (kbe.kb_value)
+ {
+ case K_FIND:
+ k[j] = XK_Home; /* or XK_Find */
+ break;
+ case K_INSERT:
+ k[j] = XK_Insert;
+ break;
+ case K_REMOVE:
+ k[j] = XK_Delete;
+ break;
+ case K_SELECT:
+ k[j] = XK_End; /* or XK_Select */
+ break;
+ case K_PGUP:
+ k[j] = XK_Prior;
+ break;
+ case K_PGDN:
+ k[j] = XK_Next;
+ break;
+ case K_HELP:
+ k[j] = XK_Help;
+ break;
+ case K_DO:
+ k[j] = XK_Execute;
+ break;
+ case K_PAUSE:
+ k[j] = XK_Pause;
+ break;
+ case K_MACRO:
+ k[j] = XK_Menu;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case KT_SPEC:
+ switch (kbe.kb_value)
+ {
+ case K_ENTER:
+ k[j] = XK_Return;
+ break;
+ case K_BREAK:
+ k[j] = XK_Break;
+ break;
+ case K_CAPS:
+ k[j] = XK_Caps_Lock;
+ break;
+ case K_NUM:
+ k[j] = XK_Num_Lock;
+ break;
+ case K_HOLD:
+ k[j] = XK_Scroll_Lock;
+ break;
+ case K_COMPOSE:
+ k[j] = XK_Multi_key;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case KT_PAD:
+ switch (kbe.kb_value)
+ {
+ case K_PPLUS:
+ k[j] = XK_KP_Add;
+ break;
+ case K_PMINUS:
+ k[j] = XK_KP_Subtract;
+ break;
+ case K_PSTAR:
+ k[j] = XK_KP_Multiply;
+ break;
+ case K_PSLASH:
+ k[j] = XK_KP_Divide;
+ break;
+ case K_PENTER:
+ k[j] = XK_KP_Enter;
+ break;
+ case K_PCOMMA:
+ k[j] = XK_KP_Separator;
+ break;
+ case K_PDOT:
+ k[j] = XK_KP_Decimal;
+ break;
+ case K_PPLUSMINUS:
+ k[j] = XK_KP_Subtract;
+ break;
+ default:
+ if (kval <= 9)
+ k[j] = XK_KP_0 + kval;
+ break;
+ }
+ break;
+
+ /*
+ * KT_DEAD keys are for accelerated diacritical creation.
+ */
+ case KT_DEAD:
+ switch (kbe.kb_value)
+ {
+ case K_DGRAVE:
+ k[j] = XK_dead_grave;
+ break;
+ case K_DACUTE:
+ k[j] = XK_dead_acute;
+ break;
+ case K_DCIRCM:
+ k[j] = XK_dead_circumflex;
+ break;
+ case K_DTILDE:
+ k[j] = XK_dead_tilde;
+ break;
+ case K_DDIERE:
+ k[j] = XK_dead_diaeresis;
+ break;
+ }
+ break;
+
+ case KT_CUR:
+ switch (kbe.kb_value)
+ {
+ case K_DOWN:
+ k[j] = XK_Down;
+ break;
+ case K_LEFT:
+ k[j] = XK_Left;
+ break;
+ case K_RIGHT:
+ k[j] = XK_Right;
+ break;
+ case K_UP:
+ k[j] = XK_Up;
+ break;
+ }
+ break;
+
+ case KT_SHIFT:
+ switch (kbe.kb_value)
+ {
+ case K_ALTGR:
+ k[j] = XK_Alt_R;
+ break;
+ case K_ALT:
+ k[j] = (kbe.kb_index == 0x64 ?
+ XK_Alt_R : XK_Alt_L);
+ break;
+ case K_CTRL:
+ k[j] = (kbe.kb_index == 0x61 ?
+ XK_Control_R : XK_Control_L);
+ break;
+ case K_CTRLL:
+ k[j] = XK_Control_L;
+ break;
+ case K_CTRLR:
+ k[j] = XK_Control_R;
+ break;
+ case K_SHIFT:
+ k[j] = (kbe.kb_index == 0x36 ?
+ XK_Shift_R : XK_Shift_L);
+ break;
+ case K_SHIFTL:
+ k[j] = XK_Shift_L;
+ break;
+ case K_SHIFTR:
+ k[j] = XK_Shift_R;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ /*
+ * KT_ASCII keys accumulate a 3 digit decimal number that gets
+ * emitted when the shift state changes. We can't emulate that.
+ */
+ case KT_ASCII:
+ break;
+
+ case KT_LOCK:
+ if (kbe.kb_value == K_SHIFTLOCK)
+ k[j] = XK_Shift_Lock;
+ break;
+
+ default:
+ break;
+ }
+ if (i < minKeyCode)
+ minKeyCode = i;
+ if (i > maxKeyCode)
+ maxKeyCode = i;
+ }
+
+ if (minKeyCode == NR_KEYS)
+ continue;
+
+ if (k[3] == k[2]) k[3] = NoSymbol;
+ if (k[2] == k[1]) k[2] = NoSymbol;
+ if (k[1] == k[0]) k[1] = NoSymbol;
+ if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
+ if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol;
+
+ k += KD_MAX_WIDTH;
+ }
+ kdMinScanCode = minKeyCode;
+ kdMaxScanCode = maxKeyCode;
+}
+
+void
+LinuxKeyboardLoad (void)
+{
+ readKernelMapping ();
+}
+
+static int LinuxKbdTrans;
+static struct termios LinuxTermios;
+
+int
+LinuxKeyboardInit (void)
+{
+ struct termios nTty;
+
+ ioctl (LinuxConsoleFd, KDGKBMODE, &LinuxKbdTrans);
+ tcgetattr (LinuxConsoleFd, &LinuxTermios);
+
+ ioctl(LinuxConsoleFd, KDSKBMODE, K_MEDIUMRAW);
+ nTty = LinuxTermios;
+ nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
+ nTty.c_oflag = 0;
+ nTty.c_cflag = CREAD | CS8;
+ nTty.c_lflag = 0;
+ nTty.c_cc[VTIME]=0;
+ nTty.c_cc[VMIN]=1;
+ cfsetispeed(&nTty, 9600);
+ cfsetospeed(&nTty, 9600);
+ tcsetattr(LinuxConsoleFd, TCSANOW, &nTty);
+ return LinuxConsoleFd;
+}
+
+void
+LinuxKeyboardFini (int fd)
+{
+ ioctl(LinuxConsoleFd, KDSKBMODE, LinuxKbdTrans);
+ tcsetattr(LinuxConsoleFd, TCSANOW, &LinuxTermios);
+}
+
+void
+LinuxKeyboardRead (int fd)
+{
+ unsigned char buf[256], *b;
+ int n;
+
+ while ((n = read (fd, buf, sizeof (buf))) > 0)
+ {
+ b = buf;
+ while (n--)
+ {
+ KdEnqueueKeyboardEvent (b[0] & 0x7f, b[0] & 0x80);
+ b++;
+ }
+ }
+}
+
+void
+LinuxKeyboardLeds (int leds)
+{
+ ioctl (LinuxConsoleFd, KDSETLED, leds & 7);
+}
+
+void
+LinuxKeyboardBell (int volume, int pitch, int duration)
+{
+ if (volume && pitch)
+ {
+ ioctl(LinuxConsoleFd, KDMKTONE,
+ ((1193190 / pitch) & 0xffff) |
+ (((unsigned long)duration *
+ volume / 50) << 16));
+
+ }
+}
+
+KdKeyboardFuncs LinuxKeyboardFuncs = {
+ LinuxKeyboardLoad,
+ LinuxKeyboardInit,
+ LinuxKeyboardRead,
+ LinuxKeyboardLeds,
+ LinuxKeyboardBell,
+ LinuxKeyboardFini,
+ 3,
+};