aboutsummaryrefslogtreecommitdiff
path: root/console-client
diff options
context:
space:
mode:
Diffstat (limited to 'console-client')
-rw-r--r--console-client/Makefile52
-rw-r--r--console-client/pc-kbd.c282
-rw-r--r--console-client/xkb/MISSING-FEATURES32
-rw-r--r--console-client/xkb/README178
-rw-r--r--console-client/xkb/TODO7
-rw-r--r--console-client/xkb/compose.c593
-rw-r--r--console-client/xkb/kstoucs.c50
-rw-r--r--console-client/xkb/kstoucs_map.sh20
-rw-r--r--console-client/xkb/lex.l386
-rw-r--r--console-client/xkb/parser.y1605
-rw-r--r--console-client/xkb/xkb-data/keymap/hurd392
-rw-r--r--console-client/xkb/xkb-data/symbols/hurd125
-rw-r--r--console-client/xkb/xkb-data/types/hurd18
-rw-r--r--console-client/xkb/xkb.c1380
-rw-r--r--console-client/xkb/xkb.h431
-rw-r--r--console-client/xkb/xkbdata.c464
-rw-r--r--console-client/xkb/xkbtimer.c231
17 files changed, 6236 insertions, 10 deletions
diff --git a/console-client/Makefile b/console-client/Makefile
index 3ec682b3..a5c14ffe 100644
--- a/console-client/Makefile
+++ b/console-client/Makefile
@@ -31,17 +31,28 @@ NCURSESW_SO_SRCS = ncursesw.c
endif
SRCS = $(CONSOLE_SRCS) \
$(VGA_SO_SRCS) $(PC_KBD_SO_SRCS) $(PC_MOUSE_SO_SRCS) \
- $(GENERIC_SPEAKER_SO_SRCS) $(CURRENT_VCS_SO_SRCS) $(NCURSESW_SO_SRCS)
+ $(GENERIC_SPEAKER_SO_SRCS) $(CURRENT_VCS_SO_SRCS) $(NCURSESW_SO_SRCS) \
+ $(XKB_SRCS)
-OBJS = $(SRCS:.c=.o) kdioctlServer.o
+VPATH += $(srcdir)/xkb
+OBJS = $(addsuffix .o,$(basename $(notdir $(SRCS)))) kdioctlServer.o
HURDLIBS = cons threads ports netfs fshelp iohelp ihash shouldbeinlibc
LDLIBS = -ldl
module-dir = $(libdir)/hurd/console
console-LDFLAGS = -Wl,-E
+CPPFLAGS += -I$(srcdir)/xkb
+LFLAGS = -i
+YFLAGS = -by
+XKB_DATA_FILES = keymap/hurd types/hurd symbols/hurd
+
# In seeking, thou shalt find it!
CPPFLAGS += -DQUAERENDO_INVENIETIS
+DIST_FILES = xkb/HACKING xkb/MISSING-FEATURES xkb/README xkb/TODO \
+ xkb/kstoucs_map.sh \
+ $(addprefix xkb/xkb-data/, $(XKB_DATA_FILES))
+
include ../Makeconf
driver-CPPFLAGS = -D'CONSOLE_DEFPATH="$(module-dir)\0"' \
@@ -57,7 +68,7 @@ modules = vga pc_kbd generic_speaker pc_mouse current_vcs
vga-CPPFLAGS = -DDEFAULT_VGA_FONT_DIR=\"${datadir}/hurd/\"
vga.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(VGA_SO_SRCS))
-pc_kbd.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(PC_KBD_SO_SRCS)) \
+pc_kbd.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(PC_KBD_SO_SRCS)) \
kdioctlServer_pic.o
pc_mouse.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(PC_MOUSE_SO_SRCS))
generic_speaker.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(GENERIC_SPEAKER_SO_SRCS))
@@ -88,3 +99,38 @@ $(module-dir)/%: %
$(CC) -shared -Wl,-soname=$@ -o $@ $(rpath) \
$(CFLAGS) $($*-CFLAGS) $(LDFLAGS) \
'-Wl,-(' $($*-LDLIBS) '-Wl,-)' $^
+
+lex.c: lex.l parser.tab.h
+parser.tab.h: parser.y
+ if $(YACC) $(YFLAGS) -d $<; then \
+ mv y.tab.h $@; \
+ rm y.tab.c; \
+ fi
+
+XKB_SRCS = xkb/compose.c xkb/kstoucs.c xkb/parser.y xkb/lex.l \
+ xkb/xkb.c xkb/xkbdata.c xkb/xkbtimer.c
+ifeq ($(HAVE_X11),yes)
+XKB_UNITS = $(basename $(notdir $(XKB_SRCS)))
+pc_kbd.so.$(hurd-version): $(addsuffix _pic.o,$(XKB_UNITS))
+pc-kbd-CFLAGS = -DXKB_SUPPORT -DXKB_DATA_DIR=\"$(XKB_BASE)\" $(X11_CFLAGS)
+$(foreach XKB_UNIT, $(XKB_UNITS), $(eval $(XKB_UNIT)-CFLAGS = $(X11_CFLAGS)))
+compose-CFLAGS += -DDATADIR=\"$(datadir)\"
+pc_kbd-LDLIBS = $(X11_LIBS)
+install: $(XKB_BASE) $(addprefix $(XKB_BASE)/, $(XKB_DATA_FILES))
+
+$(XKB_BASE):
+ @$(MKINSTALLDIRS) $@
+
+$(XKB_BASE)/%: xkb/xkb-data/%
+ $(INSTALL_DATA) $< $@
+
+# FIXME: dependency files won't catch this one.
+$(srcdir)/xkb/kstoucs.c: kstoucs_map.c
+kstoucs_map.c: $(X11_KEYSYMDEF_H) $(srcdir)/xkb/kstoucs_map.sh
+ SED=$(SED) \
+ AWK=$(AWK) \
+ sh $(srcdir)/xkb/kstoucs_map.sh \
+ < $< \
+ > map.tmp && \
+ mv map.tmp $@
+endif
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 ();
diff --git a/console-client/xkb/MISSING-FEATURES b/console-client/xkb/MISSING-FEATURES
new file mode 100644
index 00000000..237c13d7
--- /dev/null
+++ b/console-client/xkb/MISSING-FEATURES
@@ -0,0 +1,32 @@
+Required for 100% compatibility with XKB:
+
+- Jukebox (possibility that this won't ever be done)
+- Loading the keydatabase
+- Proper indicator support
+- ISOLock
+- key lock
+- radio groups
+- overlays
+- Latching (properly, mostly works)
+- Enabling/disabling controls
+- The following controls are not implemented at all:
+ - SlowKeys
+ - BounceKeys
+ - StickyKeys
+ - MouseKeysAccel
+ - AccesXKeys
+ - AccesXTimeout
+ - AccessXFreedback (jukebox required)
+ - Overlay1 + Overlay2
+ - AudibleBell
+ - IgnoreGroupLock
+ - EnabledControls
+
+Hurd features:
+
+- Binding a string to a key (requires new action)
+ (It should be possible to insert this on other vcs too)
+- Binding executable to a key (requires new action)
+
+I'm sure I forgot some missing features, please report them:
+metgerards@student.han.nl
diff --git a/console-client/xkb/README b/console-client/xkb/README
new file mode 100644
index 00000000..de781143
--- /dev/null
+++ b/console-client/xkb/README
@@ -0,0 +1,178 @@
+-- Some random notes about the XKB module. --
+
+This XKB module used by the pc_kbd input driver can load XKB configuration
+files. XKB configuration files, the keymap files currently used in XFree,
+are very versatile.
+
+One of the biggest advantages of using XKB configurations is that both
+the Hurd and XFree work similarly. Another advantage is that it has many
+features:
+
+* Human readable configuration files with mechanisms like include
+ files, replacing keys, etc.
+
+* Many shift levels, all configurable per key type.
+
+* Support for four groups. These groups can be used for things like
+ additional alphabets.
+
+* Accessibility features like SlowKeys, StickyKeys, etc.
+
+* Dynamic behaviour; the user can define how all keys and indicators operate.
+
+
+Most support for basic operation have been implemented. Still there
+are many things not implemented. If some of these things are really
+important to you, please tell me!
+
+List of not implemented XKB features:
+
+* Accessibility and software repeat.
+* Jukebox support (user configurable audible messages)
+* Key database; loading new keynames from the X key database.
+* Error handling; partially done.
+* Indicators (Keyboard LEDs, etc.) not working, partially implemented.
+* ISOLock not implemented.
+* No support for non UTF-8 locales.
+* No support for rarely used features (Many of they don't even work in
+ X AFAIK).
+* Many other stuff doesn't work (lock, radio group, overlays, etc.).
+ If I forgot something important, please report it :)
+
+* The scanner and parser are still ugly and far from optimal!
+
+---
+
+Installation:
+
+This XKB module is an optional feature of pc-kbd input driver. Whether
+it is compiled in or not is defined by the precense of XKB_SUPPORT
+preprocessor symbol.
+
+In addition to the usual Hurd dependencies, you need yacc and lex
+programs to generate the scanner and parser.
+
+--
+
+Using it:
+
+To use it you need XKB configuration files. These are included with
+XFree and will be placed in /share/X11/xkb on most systems.
+
+This module adds the following set of options to pc-kbd for overriding
+the default behaviour:
+
+--xkbdir : The root directory of the xkb configuration, by default
+ this is /share/X11/xkb.
+
+--keymapfile : The file that hold the descriptions of the default
+ keymaps file. This file holds the description of all keymaps. This
+ path should be relative to the path set by `xkbdir'. By default
+ "keymap/xfree86" is used.
+
+--keymap : The keymap to use. By default en_US is used. Examples of
+ some other keymaps are: fr, us, de, dvorak. Example: --keymap=de
+
+--ctrlaltbs : CTRL+Alt+Backspace will exit the console client.
+--no-ctrlaltbs : CTRL+Alt+Backspace will not exit the console client.
+
+--repeat-delay : The number of jiffies the driver should wait before
+ starting to repeat keys. By default this is 50 jiffies.
+
+--repeat-interval : The number of jiffies the driver should wait
+ between each repeated key. By default this is 10 jiffies.
+
+I wrote some XKB extensions and configuration files to use these
+extensions. You can find these files in the xkb-data directory.
+
+The build system will copy these files to where your XKB
+configuration files are (usually /share/X11/xkb).
+
+for example: xkb-data/keymap/hurd will be copied to /share/X11/xkb/keymap.
+
+To use these extensions you have to use the hurd keymaps file. This
+holds all keymaps extended with Hurd features. Use "--keymapfile
+keymap/hurd" to select this file.
+
+After that you can use these keybindings:
+
+Alt + F1...F12: Switch VC.
+
+Alt + Left, Right: Switch to the console left or right of the current
+ console.
+
+Alt + Up, Down: Scroll the console by one line up or down.
+Ctrl + PgUp, PgDown: Scroll the console up or down with 1/2 screen.
+
+Alt + Home: Scroll the console to the 0% of the scrollback buffer.
+Ctrl + Home: Scroll the console to the 25% of the scrollback buffer.
+Alt + End: Scroll the console to the 100% of the scrollback buffer.
+Alt + End: Scroll the console to the 75% of the scrollback buffer.
+
+--
+
+Hurd features:
+
+If you want to use the Hurd features yourself make sure you put the
+changes in files that are not used by Xfree because it cannot parse
+these options. See how I did it for the configuration described in the
+previous paragraph.
+
+Function list:
+
+--
+ConsScroll: scroll the console x lines or to a fixed position.
+
+parameters:
+Screen = pos : Scroll to screen #pos.
+Screen += i : Scroll i screens up.
+Screen -= i : Scroll i screens down.
+line = pos : Scroll to line #pos.
+line += i : Scroll i lines up.
+line -= i : Scroll i lines down.
+percent = percentage : Scroll to PERCENTAGE % of the scrollback
+ buffer.
+
+Example:
+ConsScroll (screen += 0.5) --> Scroll down a 1/2 screen.
+
+--
+SwitchScreen: Switch to a VC.
+
+paramaters:
+screen = i : Switch to VC #i.
+screen += i : Switch to #i consoles to the right.
+screen -= i : Switch to #i consoles to the left.
+
+sameserver is a flag that will be added. I want to use it to switch to
+external consoles like X servers and SVGALib screens.
+
+example:
+SwitchScreen (screen += 1) --> Switch to the console right of the
+ current console.
+
+
+--
+More functions will be added. One to send keysyms to other VCs (can be
+usefull to control a mixer, ogg vorbis player, etc.). It should also
+be capable of inserting often used strings like "apfelkorn" :).
+
+A function to call the configuration dialog should be added.
+
+Functions to execute things should be added. Think about binding the
+reboot command to Ctrl+Alt+Delete for example. Wolfgang also asked me
+for scheme support, but I don't know enough about scheme to know what
+cool stuff is possible with this (I don't know scheme... Hey! Not
+everyone can be perfect ;)).
+
+Perhaps functions can be added to control the console client in other
+ways.
+
+More ideas would be interesting to hear :)
+
+--
+
+Enjoy this stuff and please send me many bug reports :)
+
+Marco Gerards
+(metgerards@student.han.nl)
diff --git a/console-client/xkb/TODO b/console-client/xkb/TODO
new file mode 100644
index 00000000..275cbaf5
--- /dev/null
+++ b/console-client/xkb/TODO
@@ -0,0 +1,7 @@
+For release:
+
+Indicators.
+Use libihash.
+Better memory handling.
+Better debug output
+CLEAN UP!
diff --git a/console-client/xkb/compose.c b/console-client/xkb/compose.c
new file mode 100644
index 00000000..65854e14
--- /dev/null
+++ b/console-client/xkb/compose.c
@@ -0,0 +1,593 @@
+/* compose.c -- Keysym composing
+
+ Copyright (C) 2003 Marco Gerards
+
+ Written by Marco Gerards <metgerards@student.han.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/keysymdef.h>
+#include "xkb.h"
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <locale.h>
+#include <assert.h>
+
+/* Tokens that can be recognised by the scanner. */
+enum tokentype
+ {
+ UNKNOWN,
+ EOL,
+ REQKS,
+ SEMICOL,
+ STR,
+ PRODKS,
+ END
+ };
+
+/* The current token. */
+struct token
+{
+ enum tokentype toktype;
+ char value[50];
+} tok;
+
+/* The linenumber of the line currently parsed, used for returning
+ errors and warnings. */
+static int linenum;
+
+/* Read a token from the file CF. */
+static void
+read_token (FILE *cf)
+{
+ int c = fgetc (cf);
+ int pos = 0;
+
+ /* Remove whitespaces. */
+ while (c == ' ' || c == '\t')
+ c = fgetc (cf);
+
+ /* Comment, remove until end of line and return a EOL token. */
+ if (c == '#')
+ {
+ while (c != '\n')
+ c = fgetc (cf);
+ tok.toktype = EOL;
+ linenum++;
+ return;
+ }
+
+ /* End of file. */
+ if (c == EOF)
+ {
+ tok.toktype = END;
+ return;
+ }
+
+ /* Semicolon. */
+ if (c == ':')
+ {
+ tok.toktype = SEMICOL;
+ return;
+ }
+
+ /* End of line. */
+ if (c == '\n')
+ {
+ linenum++;
+ tok.toktype = EOL;
+ return;
+ }
+
+
+ /* Required keysym. */
+ if (c == '<')
+ {
+ while ((c = fgetc (cf)) != '>')
+ tok.value[pos++] = c;
+ tok.value[pos] = '\0';
+ tok.toktype = REQKS;
+ return;
+ }
+
+ /* Character string. */
+ if (c == '"')
+ {
+ while ((c = fgetc (cf)) != '"')
+ {
+ if (c == '\\')
+ c = fgetc (cf);
+
+ tok.value[pos++] = c;
+ }
+ tok.value[pos] = '\0';
+ tok.toktype = STR;
+ return;
+ }
+
+ /* Produced keysym. */
+ if (isalpha (c))
+ {
+ tok.value[pos++] = c;
+ while (isgraph (c = fgetc (cf)))
+ tok.value[pos++] = c;
+ tok.value[pos] = '\0';
+ tok.toktype = PRODKS;
+ ungetc (c, cf);
+ return;
+ }
+
+ /* Unknown token. */
+ tok.toktype = UNKNOWN;
+ return;
+}
+
+/* Compose sequence. */
+struct compose
+{
+ struct compose *left;
+ struct compose *right;
+ symbol *expected;
+ symbol produced;
+} *compose_tree;
+
+
+/* Compare symbol sequence s1 to symbol sequence s1. This function
+ works just like the strcmp function. */
+static int
+symbolscmp (symbol *s1, symbol *s2)
+{
+ while (*s1 && *s2 && (*s1 == *s2))
+ {
+ s1++;s2++;
+ }
+ if (*s1 < *s2)
+ return -1;
+ if (*s1 > *s2)
+ return 1;
+ return 0;
+}
+
+/* Compare symbol sequence s1 to symbol sequence s1, compare a maximum
+ of N symbols. This function works just like the strcmp function.
+ */
+static int
+symbolsncmp (symbol *s1, symbol *s2, int n)
+{
+ int cnt = 0;
+ while (*s1 && *s2 && (*s1 == *s2))
+ {
+ if (++cnt == n)
+ break;
+ s1++;s2++;
+ }
+
+ if (*s1 < *s2)
+ return -1;
+ if (*s1 > *s2)
+ return 1;
+ return 0;
+}
+
+
+/* Add the compose sequence EXP to the binary tree, store RESULT as
+ the keysym produced by EXP. */
+static struct compose *
+composetree_add (struct compose *tree, symbol *exp, symbol result)
+{
+ int cmp;
+
+ if (tree == NULL)
+ {
+ tree = malloc (sizeof (struct compose));
+ tree->expected = exp;
+ tree->produced = result;
+ tree->left = tree->right = NULL;
+
+ return tree;
+ }
+
+ cmp = symbolscmp (exp, tree->expected);
+ if (cmp == 0)
+ {
+ printf ("Warning: line %d: Double sequence.\n", linenum);
+ free (exp);
+ }
+ else if (cmp < 0)
+ tree->left = composetree_add (tree->left, exp, result);
+ else
+ tree->right = composetree_add (tree->right, exp, result);
+ return tree;
+}
+
+/* Parse the composefile CF and put all sequences in the binary tree
+ COMPOSE_TREE. This function may never fail because of syntactical or
+ lexalical errors, generate a warning instead. */
+static error_t
+parse_composefile (FILE *cf)
+{
+ void skip_line (void)
+ {
+ while (tok.toktype != EOL && tok.toktype != END)
+ read_token (cf);
+ }
+
+ for (;;)
+ {
+ /* Expected keysyms. */
+ symbol exp[50];
+ symbol *exps;
+ size_t expcnt = 0;
+ symbol sym;
+
+ read_token (cf);
+ /* Blank line. */
+ if (tok.toktype == EOL)
+ continue;
+
+ /* End of file, done parsing. */
+ if (tok.toktype == END)
+ return 0;
+
+ if (tok.toktype != REQKS)
+ {
+ printf ("Warning: line %d: Keysym expected on beginning of line.\n",
+ linenum);
+ skip_line ();
+ continue;
+ }
+
+ /* Keysym was recognised, add it. */
+ sym = XStringToKeysym (tok.value);
+ if (!sym)
+ {
+ printf ("Warning: line %d: Unknown keysym \"%s\".\n", linenum,
+ tok.value);
+ skip_line ();
+ continue;
+ }
+ exp[expcnt++] = sym;
+
+ do
+ {
+ read_token (cf);
+ /* If another required keysym is recognised, add it. */
+ if (tok.toktype == REQKS)
+ {
+ sym = XStringToKeysym (tok.value);
+ if (!sym)
+ {
+ printf ("Warning: line %d: Unknown keysym \"%s\".\n",
+ linenum, tok.value);
+ skip_line ();
+ continue;
+ }
+ exp[expcnt++] = sym;
+ }
+ } while (tok.toktype == REQKS);
+
+ if (tok.toktype != SEMICOL)
+ {
+ printf ("Warning: line %d: Semicolon expected.\n", linenum);
+ skip_line ();
+ continue;
+ }
+
+ read_token (cf);
+ /* Force token and ignore it. */
+ if (tok.toktype != STR)
+ {
+ printf ("Warning: line %d: string expected.\n", linenum);
+ skip_line ();
+ continue;
+ }
+
+ read_token (cf);
+ if (tok.toktype != PRODKS)
+ {
+ printf ("Warning: line %d: keysym expected.\n", linenum);
+ skip_line ();
+ continue;
+ }
+ sym = XStringToKeysym (tok.value);
+ if (!sym)
+ {
+ printf ("Warning: line %d: Unknown keysym \"%s\".\n", linenum,
+ tok.value);
+ skip_line ();
+ continue;
+ }
+
+ read_token (cf);
+ if (tok.toktype != EOL && tok.toktype != END)
+ {
+ printf ("Warning: line %d: end of line or end of file expected.\n",
+ linenum);
+ skip_line ();
+ continue;
+ }
+
+ /* Add the production rule. */
+ exp[expcnt++] = 0;
+ exps = malloc (sizeof (symbol) * expcnt);
+ memcpy (exps, exp, sizeof (symbol) * expcnt);
+ compose_tree = composetree_add (compose_tree, exps, sym);
+ }
+ return 0;
+}
+
+/* Read keysyms passed to this function by S until a keysym can be
+ composed. If the first keysym cannot start a compose sequence return
+ the keysym. */
+symbol
+compose_symbols (symbol s)
+{
+ /* Current position in the compose tree. */
+ static struct compose *treepos = NULL;
+ /* Current compose sequence. */
+ static symbol syms[100];
+ /* Current position in the compose sequence. */
+ static int pos = 0;
+ int cmp;
+
+ if (!treepos)
+ treepos = compose_tree;
+
+ /* Maximum sequence length reached. Some idiot typed this many
+ symbols and now we throw it all away, wheee!!! */
+ if (pos == 99)
+ {
+ treepos = compose_tree;
+ pos = 0;
+ }
+
+ /* Put the keysym in the compose sequence array. */
+ syms[pos++] = s;
+ syms[pos] = 0;
+
+ /* Search the tree for a keysym sequence that can match the current one. */
+ while (treepos)
+ {
+ cmp = symbolsncmp (syms, treepos->expected, pos);
+ if (cmp == 0)
+ {
+ /* The keysym sequence was partially recognised, check if it
+ can completely match. */
+ if (!symbolscmp (syms, treepos->expected))
+ {
+ symbol ret = treepos->produced;
+ treepos = compose_tree;
+ pos = 0;
+ return ret;
+ }
+
+ /* The sequence was partially recognised. */
+ return -1;
+ }
+
+ if (cmp < 0)
+ treepos = treepos->left;
+ else
+ treepos = treepos->right;
+ }
+
+ /* Nothing can be found. */
+ treepos = compose_tree;
+
+ /* This ks should've started a sequence but couldn't be found,
+ just return it. */
+ if (pos == 1)
+ {
+ pos = 0;
+ return s;
+ }
+
+ debug_printf ("Invalid\n");
+ /* Invalid keysym sequence. */
+ pos = 0;
+ return -1;
+}
+
+struct map_entry
+{
+ const char *left;
+ const char *right;
+};
+
+enum callback_result
+ {
+ NEXT,
+ DONE
+ };
+
+typedef enum callback_result (*map_callback) (void *context, struct map_entry *entry);
+
+static error_t
+map_iterate(const char *map_path, map_callback action, void *context)
+{
+ FILE *map;
+ char *buffer = NULL;
+ size_t buffer_size = 0;
+ size_t line_length = 0;
+
+ assert (map_path != NULL);
+ assert (action != NULL);
+
+ map = fopen (map_path, "r");
+
+ if (map == NULL)
+ return errno;
+
+ while ( (line_length = getline (&buffer, &buffer_size, map)) != -1)
+ {
+ /* skips empty lines and comments */
+ if (line_length < 1 || buffer[0] == '#')
+ continue;
+ else
+ {
+ struct map_entry entry = {NULL, NULL};
+ char *end = buffer + line_length;
+ char *p = buffer;
+
+ while (p != end && isspace(*p)) p++;
+
+ if (p == end)
+ continue;
+
+ entry.left = p;
+
+ while (p != end && !isspace(*p)) p++;
+
+ if (p != end)
+ {
+ *(p++) = 0;
+ while (p != end && isspace(*p)) p++;
+
+ if (p != end)
+ {
+ entry.right = p;
+ while (p != end && !isspace(*p)) p++;
+ if (p != end)
+ *p = 0;
+ }
+ }
+
+ if (action (context, &entry) == DONE)
+ break;
+ }
+ }
+ free (buffer);
+ fclose (map);
+ return 0;
+}
+
+struct matcher_context
+{
+ char *value;
+ char *result;
+};
+
+static enum callback_result
+match_left_set_right (void *context, struct map_entry *entry)
+{
+ struct matcher_context *ctx = (struct matcher_context *) context;
+
+ if (strcmp (ctx->value, entry->left) == 0)
+ {
+ ctx->result = strdup (entry->right);
+ return DONE;
+ }
+ return NEXT;
+}
+
+static enum callback_result
+match_right_set_left (void *context, struct map_entry *entry)
+{
+ struct matcher_context *ctx = (struct matcher_context *) context;
+
+ if (strcmp (ctx->value, entry->right) == 0)
+ {
+ ctx->result = strdup (entry->left);
+ return DONE;
+ }
+ return NEXT;
+}
+
+/* Search for a compose file.
+
+ According to Compose(5) man page the compose file searched in the
+ following locations:
+ - XCOMPOSEFILE variable.
+ - .XCompose at $HOME.
+ - System wide compose file for the current locale. */
+static char *
+get_compose_file_for_locale()
+{
+ struct matcher_context context = { NULL };
+ char *xcomposefile;
+ char *to_be_freed;
+ char *home;
+ int err;
+
+ xcomposefile = getenv ("XCOMPOSEFILE");
+ if (xcomposefile != NULL)
+ return strdup (xcomposefile);
+
+ home = getenv ("HOME");
+ if (home != NULL)
+ {
+ err = asprintf (&xcomposefile, "%s/.XCompose", home);
+ if (err != -1)
+ {
+ if (faccessat(AT_FDCWD, xcomposefile, R_OK, AT_EACCESS) == 0)
+ return xcomposefile;
+ else
+ {
+ free (xcomposefile);
+ /* TODO: check and report whether the compose file doesn't exist or
+ read permission was not granted to us. */
+ }
+ }
+ }
+
+ context.value = setlocale (LC_ALL, NULL);
+ map_iterate (DATADIR "/X11/locale/locale.alias", match_left_set_right, &context);
+ to_be_freed = context.result;
+
+ if (context.result != NULL)
+ {
+ /* Current locale is an alias. Use the real name to index the database. */
+ context.value = context.result;
+ }
+ context.result = NULL;
+ map_iterate (DATADIR "/X11/locale/compose.dir", match_right_set_left, &context);
+ free (to_be_freed);
+
+ /* compose.dir contains relative paths to compose files. */
+ to_be_freed = context.result;
+ err = asprintf (&context.result, DATADIR "/X11/locale/%s", context.result);
+ if (err == -1)
+ context.result = NULL;
+
+ free (to_be_freed);
+ return context.result;
+}
+
+/* Read a Compose file. */
+error_t
+read_composefile (char *composefn)
+{
+ FILE *cf;
+
+ error_t err;
+
+ if (composefn == NULL)
+ composefn = get_compose_file_for_locale ();
+
+ cf = fopen (composefn, "r");
+ if (cf == NULL)
+ return errno;
+
+ err = parse_composefile (cf);
+ if (err)
+ fclose (cf);
+
+ return err;
+}
diff --git a/console-client/xkb/kstoucs.c b/console-client/xkb/kstoucs.c
new file mode 100644
index 00000000..b4602e17
--- /dev/null
+++ b/console-client/xkb/kstoucs.c
@@ -0,0 +1,50 @@
+struct ksmap {
+ int keysym;
+ unsigned int ucs;
+};
+
+#include "kstoucs_map.c"
+
+unsigned int
+KeySymToUcs4 (int keysym)
+{
+#ifdef XKB_DEBUG
+ char *XKeysymToString(int keysym);
+ printf ("KeySymToUcs4: %s (%d) -> ", XKeysymToString (keysym), keysym);
+unsigned int doit (int keysym)
+{
+#endif
+
+ /* Control characters not covered by keysym map. */
+ if (keysym > 0 && keysym < 32)
+ return keysym;
+
+ /* 'Unicode keysym' */
+ if ((keysym & 0xff000000) == 0x01000000)
+ return (keysym & 0x00ffffff);
+
+ unsigned int
+ find_ucs (int keysym, struct ksmap *first, struct ksmap *last)
+ {
+ struct ksmap *middle = first + (last - first) / 2;
+
+ if (middle->keysym == keysym)
+ return middle->ucs; /* base case: needle found. */
+ else if (middle == first && middle == last)
+ return 0; /* base case: empty search space. */
+ /* recursive cases: halve search space. */
+ else if (middle->keysym < keysym)
+ return find_ucs (keysym, middle, last);
+ else if (middle->keysym > keysym)
+ return find_ucs (keysym, first, middle);
+ }
+
+ #define NUM_KEYSYMS (sizeof kstoucs_map / sizeof(struct ksmap))
+ return find_ucs(keysym, &kstoucs_map[0], &kstoucs_map[NUM_KEYSYMS - 1]);
+#ifdef XKB_DEBUG
+}
+ unsigned int ret = doit (keysym);
+ printf ("%d\n", ret);
+ return ret;
+#endif
+}
diff --git a/console-client/xkb/kstoucs_map.sh b/console-client/xkb/kstoucs_map.sh
new file mode 100644
index 00000000..624d3518
--- /dev/null
+++ b/console-client/xkb/kstoucs_map.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+SED=${SED:-sed}
+AWK=${AWK:-awk}
+
+$SED -n -e 's/#define XK_[a-zA-Z0-9_]\+\s\+\(0x[0-9a-fA-F]\+\)\s*\/\*\s*U+\([0-9a-fA-F]\+\).*\*\//\1\t0x\2/p' \
+ | $AWK '{ print strtonum($1) "\t" $2; }' \
+ | sort -n -k1 \
+ | $AWK '
+ BEGIN { print "struct ksmap kstoucs_map[] = {" }
+ {
+ if (NR == 1)
+ separator =" ";
+ else
+ separator =" , ";
+
+ if (strtonum($1) < 0x1000000)
+ print separator "{ " $1 ", " $2 " }"
+ }
+ END { print "};" }'
diff --git a/console-client/xkb/lex.l b/console-client/xkb/lex.l
new file mode 100644
index 00000000..d9198981
--- /dev/null
+++ b/console-client/xkb/lex.l
@@ -0,0 +1,386 @@
+/* XKB scanner.
+
+ Copyright (C) 2002, 03 Marco Gerards
+
+ Written by Marco Gerards <marco@student.han.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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. */
+
+
+ #include "xkb.h"
+ #include "parser.tab.h"
+ #include <string.h>
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <error.h>
+
+ int close_include (void);
+ int lineno = 1;
+ char *filename = "foo";
+
+%option nodebug
+
+%option UNPUT
+KEYCODE "<"[A-Z][-+A-Z0-9]*">"
+DIGIT [0-9]
+NUM {DIGIT}{DIGIT}*
+FLOAT {DIGIT}{DIGIT}*\.{DIGIT}{DIGIT}*
+HEX 0x[A-Za-z0-9]*
+IDENTIFIER [a-zA-Z][a-zA-Z0-9_]*
+CPPCOMMENT "//".*"\n"
+%%
+ /* When the end of a file is reached, close the
+ current one and pop the next file to process
+ of the stack. */
+
+ /* Filter out comment. */
+{CPPCOMMENT} { lineno++; }
+ "/*" {
+ int c;
+
+ while((c = input()) != 0)
+ {
+ if(c == '\n')
+ lineno++;
+
+ else if(c == '*')
+ {
+ if((c = input()) == '/')
+ break;
+ else
+ unput(c);
+ }
+ }
+ }
+
+\n { lineno++; }
+
+ /* Beginning of sections. */
+xkb_keymap { return XKBKEYMAP; }
+xkb_symbols { return XKBSYMBOLS; }
+xkb_keycodes { return XKBKEYCODES; }
+xkb_types { return XKBTYPES; }
+xkb_compatibility { return XKBCOMPAT; }
+xkb_geometry { return XKBGEOMETRY; }
+
+
+ /* Real modifiers. */
+shift { return SHIFT; }
+lock { return LOCK; }
+control { return CONTROL; }
+ctrl { return CONTROL; }
+mod1 { return MOD1; }
+mod2 { return MOD2; }
+mod3 { return MOD3; }
+mod4 { return MOD4; }
+mod5 { return MOD5; }
+
+ /* Levels. */
+anylevel { yylval.val = 0; return LEVEL; }
+levelone { yylval.val = 1; return LEVEL; }
+level1 { yylval.val = 1; return LEVEL; }
+level2 { yylval.val = 2; return LEVEL; }
+level3 { yylval.val = 3; return LEVEL; }
+level4 { yylval.val = 4; return LEVEL; }
+level[1-9][0-9]* { yylval.val = atoi(yytext + 5); return LEVEL; }
+
+ /* Groups. */
+group1 { yylval.val = 1; return GROUPNUM; }
+group2 { yylval.val = 2; return GROUPNUM; }
+group3 { yylval.val = 3; return GROUPNUM; }
+group4 { yylval.val = 4; return GROUPNUM; }
+
+ /* Booleans */
+true { yylval.val = 1; return BOOLEAN; }
+false { yylval.val = 0; return BOOLEAN; }
+
+ /* Interpretation */
+interpret { return INTERPRET; }
+usemodmap { return USEMODMAP; }
+usemodmapmods { return USEMODMAP; }
+modmapmods { return USEMODMAP; }
+repeat { return REPEAT; }
+locking { return LOCKING; }
+locks { return LOCKING; }
+virtualmodifier { return VIRTUALMODIFIER; }
+virtualmod { return VIRTUALMODIFIER; }
+
+ /* Interpretation match. */
+noneof { yylval.val = 0; return INTERPMATCH ;}
+anyofornone { yylval.val = 1; return INTERPMATCH ;}
+anyof { yylval.val = 2; return INTERPMATCH ;}
+allof { yylval.val = 3; return INTERPMATCH ;}
+exactly { yylval.val = 4; return INTERPMATCH ;}
+
+ /* SetMods action. */
+clearlocks { return CLEARLOCKS; }
+mods { return MODS; }
+
+unlock { return UNLOCK; }
+both { return BOTH; }
+neither { return NEITHER; }
+
+ /* Actions. */
+setmods { return SETMODS; }
+latchmods { return LATCHMODS; }
+lockmods { return LOCKMODS; }
+setgroup { return SETGROUP; }
+latchgroup { return LATCHGROUP; }
+lockgroup { return LOCKGROUP; }
+setptrdflt { return PTRDFLT; }
+setpointerdefault { return PTRDFLT; }
+lockptrbtn { return LOCKPTRBTN; }
+lockpointerbutton { return LOCKPTRBTN; }
+lockptrbutton { return LOCKPTRBTN; }
+lockpointerbtn { return LOCKPTRBTN; }
+setcontrols { return SETCONTROLS; }
+lockcontrols { return LOCKCONTROLS; }
+terminateserver { return TERMINATE; }
+terminate { return TERMINATE; }
+switchscreen { return SWITCHSCREEN; }
+consscroll { return CONSSCROLL; }
+consolescroll { return CONSSCROLL; }
+moveptr { return MOVEPTR; }
+private { return PRIVATE; }
+ /* Action parameters. */
+latchtolock { return LATCHTOLOCK; }
+group { return GROUP; }
+groups { return GROUPS; }
+accel { return ACCEL; }
+accelerate { return ACCEL; }
+default { return DEFAULT; }
+count { return COUNT; }
+controls { return CONTROLS; }
+same { return SAMESERVER; }
+sameserver { return SAMESERVER; }
+screen { return SCREEN; }
+line { return LINE; }
+percentage { return PERCENT; }
+ptrbtn { return PTRBTN ; }
+pointerbutton { return PTRBTN ; }
+
+action { return ACTION; }
+actions { return ACTIONS; }
+
+whichmodstate { return WHICHMODSTATE; }
+whichmodifierstate { return WHICHMODSTATE; }
+whichgroupstate { return WHICHGROUPSTATE; }
+
+ /* Match state for indicator. */
+base { yylval.val = 0; return WHICHSTATE; }
+latched { yylval.val = 1; return WHICHSTATE; }
+locked { yylval.val = 4; return WHICHSTATE; }
+effective { yylval.val = 8; return WHICHSTATE; }
+
+ /* Bits for binary controls. */
+repeatkeys { yylval.val = 0; return CONTROLFLAG; }
+autorepeat { yylval.val = 0; return CONTROLFLAG; }
+accessxkeys { yylval.val = 0; return CONTROLFLAG; }
+slowkeys { yylval.val = 0; return CONTROLFLAG; }
+bouncekeys { yylval.val = 0; return CONTROLFLAG; }
+stickykeys { yylval.val = 0; return CONTROLFLAG; }
+accessxtimeout { yylval.val = 0; return CONTROLFLAG; }
+accessxfeedback { yylval.val = 0; return CONTROLFLAG; }
+mousekeys { yylval.val = 0; return CONTROLFLAG; }
+mousekeysaccel { yylval.val = 0; return CONTROLFLAG; }
+audiblebell { yylval.val = 0; return CONTROLFLAG; }
+ignoregrouplock { yylval.val = 0; return CONTROLFLAG; }
+
+index { return INDEX; }
+name { return NAME; }
+symbols { return SYMBOLS; }
+key { return KEY; }
+
+ /* Mouse buttons. */
+button1 { yylval.val = 1; return BUTTONNUM; }
+button2 { yylval.val = 2; return BUTTONNUM; }
+button3 { yylval.val = 3; return BUTTONNUM; }
+button4 { yylval.val = 4; return BUTTONNUM; }
+button5 { yylval.val = 5; return BUTTONNUM; }
+button { return BUTTON; }
+
+ /* Fuzzyness. */
+any { return ANY; }
+all { return ALL; }
+none { return NONE; }
+
+defaultbutton { return DEFAULTBTN; }
+affect { return AFFECT; }
+
+allowexplicit { return ALLOWEXPLICIT; }
+
+ /* Feedback to the keyboard. */
+driveskeyboard { return DRIVESKBD; }
+driveskbd { return DRIVESKBD; }
+ledsdrivekbd { return DRIVESKBD; }
+ledsdrivekeyboard { return DRIVESKBD; }
+indicatordriveskbd { return DRIVESKBD; }
+indicatordriveskeyboard { return DRIVESKBD; }
+
+
+modifier_map { return MODMAP; }
+minimum { return MINIMUM; }
+maximum { return MAXIMUM; }
+virtual { return VIRTUAL; }
+alias { return ALIAS; }
+indicator { return INDICATOR; }
+virtual_modifiers { return VMODS; }
+virtualmods { return VMODS; }
+vmods { return VMODS; }
+type { return TYPE; }
+data { return DATA; }
+modifiers { return MODS; }
+map { return MAP; }
+level_name { return LEVEL_NAME; }
+preserve { return PRESERVE; }
+
+ /* Section flags. */
+partial { yylval.val = 1; return FLAGS; }
+complete { yylval.val = 2; return FLAGS; }
+fc { yylval.val = 4; return FLAGS; }
+fd { yylval.val = 8; return FLAGS; }
+cp { return XKBCOMPAT; }
+
+ /* Section merge modes. */
+include { yylval.mergemode = defaultmm; return INCLUDE; }
+augment { yylval.mergemode = augment; return AUGMENT; }
+replace { yylval.mergemode = replace; return REPLACE; }
+override { yylval.mergemode = override; return OVERRIDE; }
+
+isolock { return ISOLOCK; }
+pointers { return POINTERS;}
+ptr { return POINTERS;}
+noaction { return NOACTION;}
+groupswrap { return GROUPSWRAP; }
+wrapgroups { return GROUPSWRAP; }
+clampgroups { return GROUPSCLAMP; }
+groupsredirect { return GROUPSREDIRECT; }
+overlay1 { yylval.val = 1; return OVERLAY; }
+overlay2 { yylval.val = 2; return OVERLAY; }
+
+ /* String. */
+\"([^"]|\\\")*\" {
+ yytext[strlen (yytext) - 1] = '\0';
+ yylval.str = strdup (yytext + 1);
+ return STR;
+ }
+ /* Ignore whitespace. */
+[ \t]*
+ /* A keycode. */
+{KEYCODE} { yylval.str = strdup (yytext) + 1; yylval.str[strlen (yylval.str) - 1] = 0; return KEYCODE; }
+ /* A float vlaue. */
+{FLOAT} { yylval.dbl = atof (yytext); return FLOAT; }
+ /* An integer. */
+{NUM} { yylval.val = atoi (yytext); return NUM; }
+ /* A hexadecimal value. */
+{HEX} { sscanf (yytext, "0x%X", &yylval.val); return HEX; }
+ /* An identifier. */
+{IDENTIFIER} { yylval.str = strdup (yytext); return IDENTIFIER; }
+ /* All unrecognized characters. */
+. { return yytext[0]; }
+%%
+ /* Stupid hack, the current version of flex is fucked. */
+ #define yytext_ptr yytext
+
+ void
+ scanner_unput (int c)
+ {
+ unput (c);
+ }
+
+ int
+ yywrap (void)
+ {
+ if (close_include () == 0)
+ return 0;
+ else
+ return 1;
+ }
+
+ #define MAX_INCLUDE_DEPTH 50
+
+ /* An include file on the stack. */
+ struct include_stack
+ {
+ YY_BUFFER_STATE buffer;
+ mergemode merge_mode;
+ int currline;
+ char *filename;
+ } include_stack[MAX_INCLUDE_DEPTH];
+ int include_stack_ptr = 0;
+
+ /* Add an file to the stack. */
+ void
+ include_file (FILE *file, mergemode new_mm, char *fname)
+ {
+ YY_BUFFER_STATE buffer;
+
+ debug_printf ("including file %s\n.", fname);
+
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
+ {
+ fprintf (stderr, "Includes nested too deeply\n");
+ exit (EXIT_FAILURE);
+ }
+
+ include_stack[include_stack_ptr].filename = filename;
+ include_stack[include_stack_ptr].currline = lineno;
+ include_stack[include_stack_ptr].merge_mode = merge_mode;
+ include_stack[include_stack_ptr++].buffer = YY_CURRENT_BUFFER;
+ filename = fname;
+ lineno = 1;
+ merge_mode = new_mm;
+
+ buffer = yy_create_buffer (file, YY_BUF_SIZE);
+ yy_switch_to_buffer (buffer);
+ }
+
+ /* Close an includefile. returns 0 on success */
+ int
+ close_include (void)
+ {
+ if ( --include_stack_ptr < 0 )
+ {
+ fprintf (stderr, "Unexpected end of file at %s:%d.\n", filename, lineno);
+ return (1);
+ }
+ else
+ {
+ fclose (yyin);
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ merge_mode = include_stack[include_stack_ptr].merge_mode;
+ lineno = include_stack[include_stack_ptr].currline;
+ filename = include_stack[include_stack_ptr].filename;
+ yy_switch_to_buffer (include_stack[include_stack_ptr].buffer);
+ debug_printf ("closing file. going back to %s.\n", filename);
+ return (0);
+ }
+ }
+
+ void
+ yyerror (char *s)
+ {
+ fprintf (stderr, "%s:%d: %s\n", filename, lineno, s);
+ // error_at_line (0, 1, filename, lineno, "foo %d\n", 2);
+ }
+
+ int
+ scanner_get_current_location()
+ {
+ return lineno;
+ }
+
+ const char*
+ scanner_get_current_file()
+ {
+ return filename;
+ }
diff --git a/console-client/xkb/parser.y b/console-client/xkb/parser.y
new file mode 100644
index 00000000..27b62145
--- /dev/null
+++ b/console-client/xkb/parser.y
@@ -0,0 +1,1605 @@
+/* parser.y -- XKB parser.
+
+ Copyright (C) 2003, 2004 Marco Gerards
+
+ Written by Marco Gerards <marco@student.han.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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. */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "xkb.h"
+
+void yyerror(char *);
+int yylex (void);
+static error_t include_section (char *incl, int sectionsymbol, char *dirname,
+ mergemode);
+static error_t include_sections (char *incl, int sectionsymbol, char *dirname,
+ mergemode);
+void close_include ();
+static void skipsection (void);
+static error_t set_default_action (struct xkb_action *, struct xkb_action **);
+static void key_set_keysym (struct key *key, group_t group, int level,
+ symbol ks);
+static void key_new (char *keyname);
+static void key_delete (char *keyname);
+void scanner_unput (int c);
+static void remove_symbols (struct key *key, group_t group);
+
+struct xkb_interpret *current_interpretation;
+struct xkb_action *current_action;
+struct xkb_indicator indi;
+struct xkb_indicator *current_indicator = &indi;
+struct key defkey;
+struct key *default_key = &defkey;
+
+/* The default settings for actions. */
+struct xkb_action default_setmods = { SA_SetMods };
+struct xkb_action default_lockmods = { SA_LockMods };
+struct xkb_action default_latchmods = { SA_LatchMods };
+struct xkb_action default_setgroup = { SA_SetGroup };
+struct xkb_action default_latchgroup = { SA_LatchGroup };
+struct xkb_action default_lockgroup = { SA_LockGroup };
+struct xkb_action default_moveptr = { SA_MovePtr };
+struct xkb_action default_ptrbtn = { SA_PtrBtn };
+struct xkb_action default_lockptrbtn = { SA_LockPtrBtn };
+struct xkb_action default_ptrdflt = { SA_SetPtrDflt };
+struct xkb_action default_setcontrols = { SA_SetControls };
+struct xkb_action default_lockcontrols = { SA_LockControls };
+struct xkb_action default_isolock = { SA_ISOLock };
+struct xkb_action default_switchscrn = { SA_SwitchScreen };
+struct xkb_action default_consscroll = { SA_ConsScroll };
+
+static struct key *current_key;
+
+/* The dummy gets used when the original may not be overwritten. */
+static struct key dummy_key;
+
+/* The current parsed group. */
+static int current_group;
+static int current_rmod = 0;
+
+/* The current symbol in the currently parsed key. */
+static int symbolcnt;
+static int actioncnt;
+
+mergemode merge_mode = override;
+
+//#define YYDEBUG 1
+
+#ifndef YY_NULL
+#define YY_NULL 0
+#endif
+
+static struct keytype *current_keytype;
+%}
+
+%union {
+ int val;
+ char *str;
+ modmap_t modmap;
+ struct xkb_action *action;
+ double dbl;
+ mergemode mergemode;
+}
+
+%token XKBKEYMAP "xkb_keymap"
+%token XKBKEYCODES "xkb_keycodes"
+%token XKBCOMPAT "xkb_compatibility"
+%token XKBGEOMETRY "xkb_geometry"
+%token XKBTYPES "xkb_types"
+%token XKBSYMBOLS "xkb_symbols"
+%token STR
+%token HEX
+%token FLAGS
+%token KEYCODE
+%token NUM
+%token MINIMUM "minimum"
+%token MAXIMUM "maximum"
+%token VIRTUAL "virtual"
+%token INDICATOR "indicator"
+%token ALIAS "alias"
+%token IDENTIFIER
+%token VMODS "virtualmods"
+%token TYPE "type"
+%token DATA "data"
+%token MAP "map"
+%token LEVEL_NAME "level_name"
+%token PRESERVE "preserve"
+%token LEVEL
+%token USEMODMAP "usemodmap"
+%token REPEAT "repeat"
+%token LOCKING "locking"
+%token VIRTUALMODIFIER "virtualmod"
+%token BOOLEAN
+%token INTERPRET "interpret"
+%token INTERPMATCH
+%token CLEARLOCKS "clearlocks"
+%token MODS "mods"
+%token SETMODS "setmods"
+%token LATCHMODS "latchmods"
+%token LOCKMODS "lockmods"
+%token ACTION "action"
+%token LATCHTOLOCK "latchtolock"
+%token GROUP "group"
+%token GROUPS "groups"
+%token SETGROUP "setgroup"
+%token LATCHGROUP "latchgroup"
+%token LOCKGROUP "lockgroup"
+%token ACCEL "accel"
+%token MOVEPTR "moveptr"
+%token PRIVATE "private"
+%token BUTTON "button"
+%token BUTTONNUM
+%token DEFAULT "default"
+%token COUNT "count"
+%token PTRBTN "ptrbtn"
+%token DEFAULTBTN "defaultbutton"
+%token ALL "all"
+%token NONE "none"
+%token ANY "any"
+%token CONTROLFLAG
+%token AFFECT "affect"
+%token PTRDFLT "setptrdflt"
+%token LOCKPTRBTN "lockptrbtn"
+%token SETCONTROLS "setcontrols"
+%token LOCKCONTROLS "lockcontrols"
+%token CONTROLS "controls"
+%token TERMINATE "terminate"
+%token WHICHMODSTATE "whichmodstate"
+%token WHICHGROUPSTATE "whichgroupstate"
+%token WHICHSTATE "whichstate"
+%token INDEX "index"
+%token ALLOWEXPLICIT "allowexplicit"
+%token DRIVESKBD "driveskbd"
+//%token AFFECTBTNLOCK
+%token SYMBOLS "symbols"
+%token NAME "name"
+%token GROUPNUM
+%token ACTIONS "actions"
+%token KEY "key"
+%token MODMAP "modifier_map"
+%token SHIFT "shift"
+%token LOCK "lock"
+%token CONTROL "control"
+%token MOD1 "mod1"
+%token MOD2 "mod2"
+%token MOD3 "mod3"
+%token MOD4 "mod4"
+%token MOD5 "mod5"
+%token UNLOCK "unlock"
+%token BOTH "both"
+%token NEITHER "neither"
+
+%token INCLUDE "include"
+%token AUGMENT "augment"
+%token OVERRIDE "override"
+%token REPLACE "replace"
+
+
+%token ISOLOCK "isolock"
+%token POINTERS "pointers"
+%token NOACTION "noaction"
+%token GROUPSWRAP "groupswrap"
+%token GROUPSCLAMP "groupsclamp"
+%token GROUPSREDIRECT "groupsredirect"
+%token OVERLAY "overlay"
+%token SWITCHSCREEN "switchscreen"
+%token SAMESERVER "sameserver"
+%token SCREEN "screen"
+%token LINE "line"
+%token PERCENT "percent"
+%token CONSSCROLL "consscroll"
+%token FLOAT "float"
+%type <str> STR KEYCODE IDENTIFIER
+%type <val> FLAGS NUM HEX vmod level LEVEL rmod BOOLEAN symbol INTERPMATCH
+%type <val> clearlocks usemodmap latchtolock noaccel button BUTTONNUM
+%type <val> ctrlflags allowexplicit driveskbd
+%type <val> DRIVESKBD GROUPNUM group symbolname groups whichstate WHICHSTATE
+/* Booleans */
+%type <val> locking repeat groupswrap groupsclamp sameserver
+%type <modmap> mods
+%type <action> action
+%type <action> ctrlparams
+%type <mergemode> include
+%type <dbl> FLOAT
+//%debug
+
+%%
+/* A XKB keymap. */
+xkbkeymap:
+ "xkb_keymap" '{' keymap '}' ';' { YYACCEPT; }
+| "xkb_keymap" STR '{' keymap '}' ';' { YYACCEPT; }
+| '{' keymap '}' { YYACCEPT; } ';'
+;
+
+/* A XKB configuration has many sections. */
+keymap:
+ /* empty */
+| keymap types
+| keymap keycodes
+| keymap compat
+| keymap symbols
+| keymap geometry
+;
+
+include:
+ "include" { $$ = defaultmm; }
+| "augment" { $$ = augment; }
+| "replace" { $$ = replace; }
+| "override" { $$= override; }
+;
+
+/* All flags assigned to a section. */
+flags:
+ /* empty */
+| flags FLAGS
+;
+
+/* The header of a keycode section. */
+keycodes:
+ flags "xkb_keycodes" '{' keycodesect '}' ';'
+| flags "xkb_keycodes" STR '{' keycodesect '}' ';'
+;
+
+/* Process the includes on the stack. */
+keycodesinclude:
+ '{' keycodesect '}' { close_include (); }
+| keycodesinclude '{' keycodesect '}' { close_include (); }
+;
+
+/* The first lines of a keycode section. The amount of keycodes are
+ declared here. */
+keycodesect:
+/* empty */
+| "minimum" '=' NUM ';' keycodesect
+ {
+ min_keys = $3;
+ debug_printf ("working on key: %d\n", $3);
+ current_key = &keys[$3];
+ }
+| MAXIMUM '=' NUM ';' keycodesect
+ {
+ max_keys = $3;
+ keys = calloc ($3, sizeof (struct key));
+ }
+| KEYCODE '=' NUM ';'
+ { keyname_add ($1, $3); }
+ keycodesect
+| "replace" KEYCODE '=' NUM ';'
+ { keyname_add ($2, $4); }
+ keycodesect
+| "indicator" NUM '=' STR ';' keycodesect { }
+| "virtual" INDICATOR NUM '=' STR ';' keycodesect
+| "alias" KEYCODE '=' KEYCODE ';'
+ {
+ keycode_t key = keyname_find ($4);
+ if (key)
+ keyname_add ($2, key);
+ else
+ {
+ key = keyname_find ($2);
+ if (key)
+ keyname_add ($4, key);
+ }
+ }
+ keycodesect
+| include STR
+ { include_sections ($2, XKBKEYCODES, "keycodes", $1); }
+ keycodesinclude keycodesect
+;
+
+/* The header of a keytypes section. */
+types:
+ flags "xkb_types" '{' typessect '}' ';'
+| flags "xkb_types" STR '{' typessect '}' ';'
+;
+
+/* A list of virtual modifier declarations (see vmods_def), seperated
+ by commas. */
+vmodslist:
+ IDENTIFIER { vmod_add ($1); }
+| vmodslist ',' IDENTIFIER { vmod_add ($3); }
+;
+
+/* Virtual modifiers must be declared before they can be used. */
+vmods_def:
+ "virtualmods" vmodslist ';'
+;
+
+/* Return the number of the virtual modifier. */
+vmod:
+ IDENTIFIER
+ { if (($$ = vmod_find ($1)) != 0)
+ $$ = 1 << ($$ - 1);
+ else
+ fprintf(stderr, "warning: %s virtual modifier is not defined.", $1);
+ }
+;
+
+/* A single realmodifier. */
+rmod:
+ "shift" { $$ = RMOD_SHIFT; }
+| "lock" { $$ = RMOD_LOCK; }
+| "control" { $$ = RMOD_CTRL; }
+| "mod1" { $$ = RMOD_MOD1; }
+| "mod2" { $$ = RMOD_MOD2; }
+| "mod3" { $$ = RMOD_MOD3; }
+| "mod4" { $$ = RMOD_MOD4; }
+| "mod5" { $$ = RMOD_MOD5; }
+;
+
+/* One of more modifiers, seperated by '+'. A modmap_t will return all real
+ and virtual modifiers specified. */
+mods:
+ mods '+' rmod { $$.rmods = $1.rmods | $3; }
+| mods '+' vmod { $$.vmods = $1.vmods | $3; }
+ /* Use a mid-rule action to start with no modifiers. */
+| { $<modmap>$.rmods = 0; $<modmap>$.vmods = 0; } rmod { $$.rmods = $2; }
+| { $<modmap>$.rmods = 0; $<modmap>$.vmods = 0; } vmod { $$.vmods = $2; }
+| "all" { $$.rmods = 0xFF; $$.vmods = 0xFFFF; }
+| "none" { $$.rmods = 0; $$.vmods = 0; }
+;
+
+/* The numeric level starts with 0. Level1-Level4 returns 0-3, also
+ numeric values can be used to describe a level. */
+level:
+ LEVEL { $$ = $1 - 1; }
+| "any" { $$ = 0; }
+| NUM { $$ = $1 - 1; }
+;
+
+/* A single keytype. */
+type:
+ /* Empty */
+| type MODS '=' mods ';'
+ { current_keytype->modmask = $4; }
+| type MAP '[' mods ']' '=' level ';'
+ { keytype_mapadd (current_keytype, $4, $7); }
+| type "level_name" '[' level ']' '=' STR ';'
+| type "preserve" '[' mods ']' '=' mods ';'
+ { keytype_preserve_add (current_keytype, $4, $7); }
+;
+
+/* Process the includes on the stack. */
+typesinclude:
+ '{' typessect '}' { close_include (); }
+| typesinclude '{' typessect '}' { close_include (); }
+;
+
+/* A keytype section contains keytypes and virtual modifier declarations. */
+typessect:
+ /* Empty */
+| typessect vmods_def
+| typessect TYPE STR { keytype_new ($3, &current_keytype); }'{' type '}' ';' { }
+| typessect include STR
+ { include_sections ($3, XKBTYPES, "types", $2); }
+ typesinclude
+;
+
+/* The header of a compatibility section. */
+compat:
+ flags "xkb_compatibility" '{' compatsect '}' ';'
+| flags "xkb_compatibility" STR '{' compatsect '}' ';'
+;
+
+/* XXX: A symbol can be more than just an identifier (hex). */
+symbol:
+ IDENTIFIER { $$ = (int) XStringToKeysym ( $1) ? : -1; }
+| ANY { $$ = 0; }
+| error { yyerror ("Invalid symbol."); }
+;
+
+/* Which kinds of modifiers (like base, locked, etc.) can affect the
+ indicator. */
+whichstate:
+ WHICHSTATE { $$ = $1; }
+| "none" { $$ = 0; }
+| "any" { $$ = 0xff; } /* XXX */
+;
+
+/* The groups that can affect a indicator. */
+groups:
+ groups '+' group
+| groups '-' group
+| group {}
+| "all" { $$ = 0xff; } /* XXX */
+;
+
+indicators:
+/* empty */
+| indicators indicator
+;
+
+/* An indicator desciption. */
+indicator:
+ "mods" '=' mods ';' { current_indicator->modmap = $3; }
+| "groups" '=' groups ';' { current_indicator->groups = $3; }
+| "controls" '=' ctrls ';'
+| "whichmodstate" '=' whichstate ';' { current_indicator->which_mods = $3; }
+| "whichgroupstate" '=' whichstate ';' { current_indicator->which_mods = $3; }
+| allowexplicit ';' {} /* Ignored for now. */
+| driveskbd ';' {}
+| "index" '=' NUM ';' {}
+;
+
+/* Boolean for allowexplicit. */
+allowexplicit:
+ '~' "allowexplicit" { $$ = 0; }
+| '!' "allowexplicit" { $$ = 0; }
+| "allowexplicit" { $$ = 1; }
+| "allowexplicit" '=' BOOLEAN { $$ = $3; }
+;
+
+/* Boolean for driveskbd. */
+driveskbd:
+ '~' "driveskbd" { $$ = 0; }
+| '!' "driveskbd" { $$ = 0; }
+| "driveskbd" { $$ = 1; }
+| "driveskbd" '=' BOOLEAN { $$ = $3; }
+;
+
+interprets:
+ /* Empty */
+| interprets interpret
+;
+
+/* A single interpretation. */
+interpret:
+ "usemodmap" '=' level ';'
+ { current_interpretation->match &= 0x7F | ($3 << 7); } /* XXX */
+| repeat ';'
+ {
+ current_interpretation->flags &= ~(KEYREPEAT | KEYNOREPEAT);
+ current_interpretation->flags |= $1;
+ }
+| locking ';' {}
+| "virtualmod" '=' vmod ';' { current_interpretation->vmod = $3; }
+| "action" '=' action ';'
+ {
+ memcpy (&current_interpretation->action, $3, sizeof (xkb_action_t));
+ free ($3);
+ }
+;
+
+/* Process the includes on the stack. */
+compatinclude:
+ '{' compatsect '}' { close_include (); }
+| compatinclude '{' compatsect '}' { close_include (); }
+;
+
+/* The body of a compatibility section. */
+compatsect:
+ /* Empty */
+| compatsect vmods_def
+| compatsect "interpret" '.'
+ { current_interpretation = &default_interpretation; }
+ interpret
+| compatsect "interpret" symbol
+ {
+ if ($3 != -1)
+ {
+ interpret_new (&current_interpretation, $3);
+ current_interpretation->match |= 1;
+ }
+ }
+ '{' interprets '}' ';'
+| compatsect "interpret" symbol '+' rmod
+ {
+ if ($3 != -1)
+ {
+ interpret_new (&current_interpretation, $3);
+ current_interpretation->rmods = $5;
+ current_interpretation->match |= 4;
+ }
+ }
+ '{' interprets '}' ';'
+| compatsect "interpret" symbol '+' "any"
+ {
+ if ($3 != -1)
+ {
+ interpret_new (&current_interpretation, $3);
+ current_interpretation->rmods = 255;
+ current_interpretation->match |= 2;
+ }
+ }
+ '{' interprets '}' ';'
+| compatsect "interpret" symbol '+' INTERPMATCH '(' mods ')'
+ {
+ if ($3 != -1)
+ {
+ interpret_new (&current_interpretation, $3);
+ current_interpretation->rmods = $7.rmods;
+ current_interpretation->match |= $5;
+ }
+ }
+ '{' interprets '}' ';'
+| compatsect GROUP NUM '=' mods ';'
+| compatsect "indicator" STR '{' indicators '}' ';'
+| compatsect include STR
+ { include_sections ($3, XKBCOMPAT, "compat", $2); }
+ compatinclude
+| compatsect actiondef
+| compatsect "indicator" '.' indicator
+;
+
+
+ /* Booleans */
+/* Boolean for clearlocks. */
+clearlocks:
+ '~' "clearlocks" { $$ = 0; }
+| '!' "clearlocks" { $$ = 0; }
+| "clearlocks" { $$ = 1; }
+| "clearlocks" '=' BOOLEAN { $$ = $3; }
+;
+
+/* Boolean for latchtolock. */
+latchtolock:
+ '~' "latchtolock" { $$ = 0; }
+| '!' "latchtolock" { $$ = 0; }
+| "latchtolock" { $$ = 1; }
+| "latchtolock" '=' BOOLEAN { $$ = $3; }
+;
+
+/* Boolean for useModMap. */
+usemodmap:
+ '~' "usemodmap" { $$ = 0; }
+| '!' "usemodmap" { $$ = 0; }
+| "usemodmap" { $$ = 1; }
+| "usemodmap" '=' BOOLEAN { $$ = $3; }
+;
+
+/* Boolean for locking. */
+locking:
+ '~' "locking" { $$ = 0; }
+| '!' "locking" { $$ = 0; }
+| "locking" { $$ = 1; }
+| "locking" '=' BOOLEAN { $$ = $3; }
+;
+
+/* Boolean for repeat. */
+repeat:
+ '~' "repeat" { $$ = KEYNOREPEAT; }
+| '!' "repeat" { $$ = KEYNOREPEAT; }
+| "repeat" { $$ = KEYREPEAT; }
+| "repeat" '=' BOOLEAN
+ {
+ if ($3)
+ $$ = KEYREPEAT;
+ else
+ $$ = KEYNOREPEAT;
+ }
+;
+
+/* Boolean for groupswrap. */
+groupswrap:
+ '~' "groupswrap" { $$ = 0; }
+| '!' "groupswrap" { $$ = 0; }
+| "groupswrap" { $$ = 1; }
+| "groupswrap" '=' BOOLEAN { $$ = $3; }
+;
+
+/* Boolean for groupsclamp. */
+groupsclamp:
+ '~' "groupsclamp" { $$ = 0; }
+| '!' "groupsclamp" { $$ = 0; }
+| "groupsclamp" { $$ = 1; }
+| "groupsclamp" '=' BOOLEAN { $$ = $3; }
+;
+
+/* Boolean for noaccel. */
+noaccel:
+ '~' "accel" { $$ = 0; }
+| '!' "accel" { $$ = 0; }
+| "accel" { $$ = 1; }
+| "accel" '=' BOOLEAN { $$ = $3; }
+;
+
+
+sameserver:
+ '~' "sameserver" { $$ = 0; }
+| '!' "sameserver" { $$ = 0; }
+| "sameserver" { $$ = 1; }
+| "sameserver" '=' BOOLEAN { $$ = $3; }
+;
+
+setmodsparams:
+ /* empty */
+| setmodsparam
+| setmodsparams ',' setmodsparam
+;
+
+
+/* Parameter for the (Set|Lock|Latch)Mods action. */
+setmodsparam:
+ "mods" '=' mods
+ {
+ ((action_setmods_t *) current_action)->modmap = $3;
+ }
+| "mods" '=' "usemodmap"
+ { ((action_setmods_t *) current_action)->flags |= useModMap;
+ }
+| clearlocks
+ {
+ ((action_setmods_t *) current_action)->flags &= ~clearLocks;
+ ((action_setmods_t *) current_action)->flags |= $1;
+ }
+| usemodmap
+ {
+ ((action_setmods_t *) current_action)->flags &= ~useModMap;
+ ((action_setmods_t *) current_action)->flags |= $1;
+ }
+| latchtolock
+ {
+ ((action_setmods_t *) current_action)->flags &= ~latchToLock;
+ ((action_setmods_t *) current_action)->flags |= $1;
+ }
+;
+
+setgroupparams:
+/* empty */
+| setgroupparam
+| setgroupparams ',' setgroupparam
+;
+
+/* Parameter for the (Set|Lock|Latch)Group action. */
+setgroupparam:
+ "group" '=' NUM
+ {
+ ((action_setgroup_t *) current_action)->group = $3;
+ ((action_setgroup_t *) current_action)->flags |= groupAbsolute;
+ }
+| "group" '=' '+' NUM
+ {
+ ((action_setgroup_t *) current_action)->group = $4;
+ }
+| "group" '=' '-' NUM
+ {
+ ((action_setgroup_t *) current_action)->group = -$4;
+ }
+| clearlocks
+ {
+ ((action_setgroup_t *) current_action)->flags |= $1;
+ }
+| latchtolock
+ {
+ ((action_setgroup_t *) current_action)->flags |= $1;
+ }
+;
+
+moveptrparams:
+/* empty */
+| moveptrparam
+| moveptrparams ',' moveptrparam
+;
+
+/* Parameters for the MovePtr action. */
+moveptrparam:
+ IDENTIFIER '=' NUM
+ {
+ ((action_moveptr_t *) current_action)->x = $3;
+ ((action_setgroup_t *) current_action)->flags |= MoveAbsoluteX;
+ }
+| IDENTIFIER '=' '+' NUM
+ {
+ ((action_moveptr_t *) current_action)->x = $4;
+ }
+| IDENTIFIER '=' '-' NUM
+ {
+ ((action_moveptr_t *) current_action)->x = -$4;
+ }
+| noaccel
+ {
+ ((action_moveptr_t *) current_action)->flags |= NoAcceleration;
+ }
+;
+
+/* A mouse button. */
+button:
+ NUM { $$ = $1; }
+| BUTTONNUM { $$ = $1; }
+| "default" { $$ = 0; }
+;
+
+affectbtnlock:
+ "lock"
+| "unlock"
+| "both"
+| "neither"
+;
+
+ptrbtnparams:
+ /* empty */
+| ptrbtnparam
+| ptrbtnparams ',' ptrbtnparam
+;
+
+/* Parameters for the (Set|Lock|Latch)PtrBtn action. */
+ptrbtnparam:
+ "button" '=' button
+ { ((action_ptrbtn_t *) current_action)->button = $3; }
+| "count" '=' NUM
+ { ((action_ptrbtn_t *) current_action)->count = $3; }
+| "affect" '=' affectbtnlock
+ {
+ // ((action_ptrbtn_t *) $$)->a = $3;
+ }
+;
+
+/* XXX: This should be extended. */
+affectbtns:
+ "defaultbutton"
+| "button"
+| "all"
+;
+
+ptrdfltparams:
+/* empty */
+| ptrdfltparam
+| ptrdfltparams ',' ptrdfltparam
+;
+
+/* Parameters for the SetPtrDflt action. */
+ptrdfltparam:
+ "button" '=' button { }
+| "button" '=' '+' button { }
+| "button" '=' '-' button { }
+| "affect" '=' affectbtns { }
+;
+
+/* A list of controlflags. */
+ctrls:
+ ctrls '+' CONTROLFLAG// { $$ |= $3; }
+| CONTROLFLAG// { $$ = $1; }
+| OVERLAY
+;
+
+/* Modified controlflags. */
+ctrlflags:
+ ctrls { /*$$ = $1;*/ }
+| "all" { $$ = 0xFFFF; }
+| "none" { $$ = 0; }
+;
+
+/* The parameters of a (Set|Lock|Latch)Ctrls Action. */
+ctrlparams:
+ "controls" '=' ctrlflags
+ { /* ((action_setcontrols_t *) $$)->controls = $3; */ }
+;
+
+isoaffect:
+ "mods"
+| "groups"
+| "controls"
+| "pointers"
+| "all"
+| "none"
+;
+
+isolockparams:
+/* empty */
+| isolockparam
+| isolockparams ',' isolockparam
+;
+
+/* Parameters for the ISOLock action. */
+isolockparam:
+ "mods" '=' mods
+| "mods" '=' USEMODMAP
+| "group" '=' group
+| "controls" '=' ctrlflags
+| "affect" '=' isoaffect
+;
+
+switchscrnparams:
+ switchscrnparam
+ | switchscrnparams ',' switchscrnparam
+;
+
+/* Parameters for the SwitchScreen action. */
+switchscrnparam:
+ "screen" '=' NUM
+ {
+ ((action_switchscrn_t *) current_action)->screen = $3;
+ ((action_switchscrn_t *) current_action)->flags |= screenAbs;
+ }
+| "screen" '+' '=' NUM
+ {
+ ((action_switchscrn_t *) current_action)->screen = $4;
+ }
+| "screen" '-' '=' NUM
+ {
+ ((action_switchscrn_t *) current_action)->screen = -$4;
+ }
+| sameserver
+ {
+ /* XXX: Implement this. */
+/* ((action_switchscrn_t *) current_action)->flags &= ~0; */
+/* ((action_switchscrn_t *) current_action)->flags |= $1; */
+ }
+;
+
+consscrollparams:
+ consscrollparam
+ | consscrollparams ',' consscrollparam
+;
+
+/* Parameters for the ConsScroll action. */
+consscrollparam:
+ "screen" '+' '=' FLOAT
+ {
+ ((action_consscroll_t *) current_action)->screen = $4;
+ }
+| "screen" '-' '=' FLOAT
+ {
+ ((action_consscroll_t *) current_action)->screen = -$4;
+ }
+| "line" '=' NUM
+ {
+ ((action_consscroll_t *) current_action)->line = $3;
+ ((action_consscroll_t *) current_action)->flags |= lineAbs;
+ }
+| "line" '+' '=' NUM
+ {
+ ((action_consscroll_t *) current_action)->line = $4;
+ }
+| "line" '-' '=' NUM
+ {
+ ((action_consscroll_t *) current_action)->line = -$4;
+ }
+| "percent" '=' NUM
+ {
+ ((action_consscroll_t *) current_action)->percent = $3;
+ ((action_consscroll_t *) current_action)->flags |= usePercentage;
+ }
+;
+
+privateparams:
+ /* empty */
+ | privateparam
+ | privateparams ',' privateparam
+;
+
+privateparam:
+ "type" '=' HEX
+ {
+ }
+| "data" '=' STR
+ {
+ }
+;
+
+/* An action definition. */
+action:
+ "setmods"
+ {
+ if (set_default_action (&default_setmods, &current_action))
+ YYABORT;
+ }
+ '(' setmodsparams ')' { $$ = current_action; }
+| "latchmods"
+ {
+ if (set_default_action (&default_latchmods, &current_action))
+ YYABORT;
+ }
+ '(' setmodsparams ')' { $$ = current_action; }
+| "lockmods"
+ {
+ if (set_default_action (&default_lockmods, &current_action))
+ YYABORT;
+ }
+ '(' setmodsparams ')' { $$ = current_action; }
+| "setgroup"
+ {
+ if (set_default_action (&default_setgroup, &current_action))
+ YYABORT;
+ }
+ '(' setgroupparams ')' { $$ = current_action; }
+| "latchgroup"
+ {
+ if (set_default_action (&default_latchgroup, &current_action))
+ YYABORT;
+ }
+ '(' setgroupparams ')' { $$ = current_action; }
+| "lockgroup"
+ {
+ if (set_default_action (&default_lockgroup, &current_action))
+ YYABORT;
+ }
+ '(' setgroupparams ')' { $$ = current_action; }
+| "moveptr"
+ {
+ if (set_default_action (&default_moveptr, &current_action))
+ YYABORT;
+ }
+ '(' moveptrparams ')' { $$ = current_action; }
+| "ptrbtn"
+ {
+ if (set_default_action (&default_ptrbtn, &current_action))
+ YYABORT;
+ }
+ '(' ptrbtnparams ')' { $$ = current_action; }
+| "lockptrbtn"
+ {
+ if (set_default_action (&default_lockptrbtn, &current_action))
+ YYABORT;
+ }
+ '(' ptrbtnparams ')' { $$ = current_action; }
+| "setptrdflt"
+ {
+ if (set_default_action (&default_ptrdflt, &current_action))
+ YYABORT;
+ }
+ '(' ptrdfltparams ')' { $$ = current_action; }
+| "setcontrols"
+ {
+ if (set_default_action (&default_setcontrols, &current_action))
+ YYABORT;
+ }
+ '(' ctrlparams ')' { $$ = current_action; }
+| "lockcontrols"
+ {
+ if (set_default_action (&default_lockcontrols, &current_action))
+ YYABORT;
+ }
+ '(' ctrlparams ')' { $$ = current_action; }
+| "terminate" '(' ')'
+ { $$ = calloc (1, sizeof (xkb_action_t)); $$->type = SA_TerminateServer; }
+| "switchscreen"
+ {
+ if (set_default_action (&default_switchscrn, &current_action))
+ YYABORT;
+ }
+'(' switchscrnparams ')' { $$ = current_action; }
+| "consscroll"
+ {
+ if (set_default_action (&default_consscroll, &current_action))
+ YYABORT;
+ }
+ '(' consscrollparams ')' { $$ = current_action; }
+| "isolock"
+ {
+ if (set_default_action (&default_isolock, &current_action))
+ YYABORT;
+ }
+ '(' isolockparams ')' { $$ = current_action; }
+| "private" '(' privateparams ')'
+ { $$ = calloc (1, sizeof (xkb_action_t)); $$->type = SA_NoAction; }
+| "noaction" '(' ')'
+ { $$ = calloc (1, sizeof (xkb_action_t)); $$->type = SA_NoAction; }
+| error ')' { yyerror ("Invalid action\n"); }
+;
+
+/* Define values for default actions. */
+actiondef:
+ "setmods" '.' { current_action = &default_setmods; } setmodsparam ';'
+| "latchmods" '.' { current_action = &default_latchmods; } setmodsparam ';'
+| "lockmods" '.' { current_action = &default_lockmods; } setmodsparam ';'
+| "setgroup" '.' { current_action = &default_setgroup; } setgroupparam ';'
+| "latchgroup" '.' { current_action = &default_latchgroup; } setgroupparam ';'
+| "lockgroup" '.' { current_action = &default_lockgroup; } setgroupparam ';'
+| "moveptr" '.' { current_action = &default_moveptr; } moveptrparam ';'
+| "ptrbtn" '.' { current_action = &default_ptrbtn; } ptrbtnparam ';'
+| "lockptrbtn" '.' { current_action = &default_lockptrbtn; } ptrbtnparam ';'
+| "setptrdflt" '.' { current_action = &default_ptrdflt; } ptrdfltparam ';'
+| "setcontrols" '.' { current_action = &default_setcontrols; } ctrlparams ';'
+| "lockcontrols" '.' { current_action = &default_lockcontrols; } ctrlparams ';'
+| "isolock" '.' { current_action = &default_isolock; } isolockparam ';'
+| "switchscreen" '.' { current_action = &default_switchscrn; } switchscrnparam ';'
+;
+
+/* The header of a symbols section. */
+symbols:
+ flags "xkb_symbols" '{' symbolssect '}' ';'
+| flags "xkb_symbols" STR '{' symbolssect '}' ';'
+;
+
+/* A group. */
+group:
+ GROUPNUM { $$ = $1 - 1; }
+| NUM { $$ = $1 - 1; }
+| HEX { $$ = $1 - 1; }
+;
+
+/* A list of keysyms and keycodes bound to a realmodifier. */
+key_list:
+ key_list ',' KEYCODE { set_rmod_keycode ($3, current_rmod); }
+| key_list ',' symbolname { ksrm_add ($3, current_rmod); }
+| KEYCODE { set_rmod_keycode ($1, current_rmod); }
+| symbolname { ksrm_add ($1, current_rmod); }
+;
+
+/* Process the includes on the stack. */
+symbolinclude:
+ '{' symbolssect '}' { close_include (); }
+| symbolinclude '{' symbolssect '}' { close_include (); }
+;
+
+/* A XKB symbol section. It is used to bind keysymbols, actions and
+ realmodifiers to keycodes. */
+symbolssect:
+ /* Empty */
+| symbolssect vmods_def
+| symbolssect NAME '[' group ']' '=' STR ';'
+| symbolssect "key" KEYCODE
+ {
+ key_new ($3);
+ current_group = 0;
+ } '{' keydescs '}' ';'
+| symbolssect "replace" "key" KEYCODE
+ {
+ key_delete ($4);
+ key_new ($4);
+ current_group = 0;
+ } '{' keydescs '}' ';'
+| symbolssect "override" "key" KEYCODE
+ {
+ key_delete ($4);
+ key_new ($4);
+ current_group = 0;
+ } '{' keydescs '}' ';'
+| symbolssect "modifier_map" rmod { current_rmod = $3; } '{' key_list '}' ';'
+| symbolssect include STR
+ { include_sections ($3, XKBSYMBOLS, "symbols", $2); }
+ symbolinclude
+| symbolssect actiondef
+| symbolssect "key" '.' {debug_printf ("working on default key.\n"); current_key = default_key; } keydesc ';'
+| symbolssect error ';' { yyerror ("Error in symbol section\n"); }
+;
+
+/* Returns a keysymbols, the numberic representation. */
+symbolname:
+ IDENTIFIER { $$ = XStringToKeysym ($1); }
+| NUM
+ {
+ if (($1 >= 0) && ($1 < 10))
+ $$ = $1 + '0';
+ else
+ $$ = $1;
+ }
+| HEX { $$ = $1; }
+;
+
+/* None or more keysyms, assigned to a single group of the current
+ key. */
+groupsyms:
+ /* empty */
+| groupsyms ',' symbolname
+ { key_set_keysym (current_key, current_group, symbolcnt++, $3); }
+| { symbolcnt = 0; } symbolname
+ {
+ symbolcnt = 0;
+ key_set_keysym (current_key, current_group, symbolcnt++, $2);
+ }
+;
+
+/* A list of actions. */
+actions:
+ actions ',' action
+ { key_set_action (current_key, current_group, actioncnt++, $3); }
+| { actioncnt = 0; } action
+ { key_set_action ( current_key, current_group, actioncnt++, $2); }
+;
+
+keydescs:
+ keydesc
+| keydescs ',' keydesc
+;
+
+/* A single key and everything assigned to it. */
+keydesc:
+ "type" '[' group ']' '=' STR
+ {
+ current_key->groups[$3].keytype = keytype_find ($6);
+ }
+| "type" '[' error ']' { yyerror ("Invalid group.\n"); }
+| "type" '=' STR
+ { current_key->groups[current_group].keytype = keytype_find ($3); }
+| { symbolcnt = 0; } "symbols" '[' group ']' { current_group = $4; } '=' '[' groupsyms ']'
+ {
+ current_key->numgroups = ($4 + 1) > current_key->numgroups ?
+ ($4 + 1) : current_key->numgroups;
+ }
+| {actioncnt = 0; } "actions" '[' group ']' { current_group = $4; } '=' '[' actions ']'
+ {
+ current_key->numgroups = ($4 + 1) > current_key->numgroups ?
+ ($4 + 1) : current_key->numgroups;
+ }
+| "virtualmods" '=' mods
+ { current_key->mods.vmods = $3.vmods; }
+| '[' groupsyms ']'
+ {
+ current_group++;
+ current_key->numgroups = current_group > current_key->numgroups ?
+ current_group : current_key->numgroups;
+ }
+| '[' actions ']'
+ {
+ current_group++;
+ current_key->numgroups = current_group > current_key->numgroups ?
+ current_group : current_key->numgroups;
+ }
+| locking {}/* This is not implemented - YET. */
+/* XXX: There 3 features are described in Ivan Pascals docs about XKB,
+ but aren't used in the standard keymaps and cannot be used because it
+ cannot be stored in the XKM dataformat. */
+| groupswrap {}
+| groupsclamp {}
+| "groupsredirect" '=' NUM
+| "overlay" '=' KEYCODE /* If you _REALLY_ need overlays, mail me!!!! */
+| repeat
+ {
+ current_key->flags &= ~(KEYREPEAT | KEYNOREPEAT);
+ current_key->flags |= $1;
+ }
+;
+
+/* The geometry map is ignored. */
+
+/* The header of a geometry section. */
+geometry:
+ flags "xkb_geometry" '{' { skipsection (); } '}' ';'
+| flags "xkb_geometry" STR '{' { skipsection (); } '}' ';'
+;
+
+%%
+/* Skip all tokens until a section of the type SECTIONSYMBOL with the
+ name SECTIONNAME is found. */
+static int
+skip_to_sectionname (char *sectionname, int sectionsymbol)
+{
+ int symbol;
+
+ do
+ {
+ do
+ {
+ symbol = yylex ();
+ } while ((symbol != YY_NULL) && (symbol != sectionsymbol));
+
+ if (symbol != YY_NULL)
+ symbol = yylex ();
+
+ if (symbol == YY_NULL) {
+ return 1;
+ } else if (symbol != STR)
+ continue;
+
+ } while (strcmp (yylval.str, sectionname));
+ return 0;
+}
+
+/* Skip all tokens until the first section of the type SECTIONSYMBOL
+ is found. */
+static int
+skip_to_firstsection (int sectionsymbol)
+{
+ int symbol;
+
+ do
+ {
+ do
+ {
+ symbol = yylex ();
+ } while ((symbol != YY_NULL) && (symbol != sectionsymbol));
+
+ if (symbol != YY_NULL)
+ symbol = yylex ();
+
+ if (symbol == YY_NULL)
+ return 1;
+ } while (symbol != STR);
+ return 0;
+}
+
+/* Skip all tokens until the default section is found. */
+static int
+skip_to_defaultsection (void)
+{
+ int symbol;
+
+ /* Search the default section. */
+ do
+ {
+ if ((symbol = yylex ()) == YY_NULL)
+ return 1;
+ } while (symbol != DEFAULT);
+
+ do
+ {
+ if ((symbol = yylex ()) == YY_NULL)
+ return 1;
+ } while (symbol != '{');
+ scanner_unput ('{');
+ return 0;
+}
+
+/* Include a single file. INCL is the filename. SECTIONSYMBOL is the
+ token that marks the beginning of the section. DIRNAME is the name
+ of the directory from where the includefiles must be loaded. NEW_MM
+ is the mergemode that should be used. */
+static error_t
+include_section (char *incl, int sectionsymbol, char *dirname,
+ mergemode new_mm)
+{
+ void include_file (FILE *, mergemode, char *);
+ int scanner_get_current_location ();
+ const char* scanner_get_current_file ();
+
+ char *filename;
+ char *sectionname = NULL;
+ FILE *includefile;
+
+ int current_location = scanner_get_current_location ();
+ char* current_file = strdup (scanner_get_current_file ());
+
+ sectionname = strchr (incl, '(');
+ if (sectionname)
+ {
+ int snlen;
+
+ snlen = strlen (sectionname);
+ if (sectionname[snlen-1] != ')')
+ {
+ free(current_file);
+ return 0;
+ }
+ sectionname[snlen-1] = '\0';
+ sectionname[0] = '\0';
+ sectionname++;
+
+ if (asprintf (&filename, "%s/%s", dirname, incl) < 0)
+ {
+ free (current_file);
+ return ENOMEM;
+ }
+ }
+ else
+ {
+ if (asprintf (&filename, "%s/%s", dirname, incl) < 0)
+ {
+ free (current_file);
+ return ENOMEM;
+ }
+ }
+
+ includefile = fopen (filename, "r");
+
+ if (includefile == NULL)
+ {
+ fprintf (stderr, "Couldn't open include file \"%s\"\n", filename);
+ free (current_file);
+ free (filename);
+ exit (EXIT_FAILURE);
+ }
+
+ include_file (includefile, new_mm, strdup (filename));
+ debug_printf ("skipping to section %s\n", (sectionname ? sectionname : "default"));
+ /* If there is a sectionname not the entire file should be included,
+ the scanner should be positioned at the required section. */
+ int err;
+ if (sectionname)
+ err = skip_to_sectionname (sectionname, sectionsymbol);
+ else
+ if ((err = skip_to_defaultsection ()) != 0)
+ {
+ /* XXX: after skip_to_defaultsection failed the whole file was
+ consumed and it is required to include it here, too. */
+ include_file (includefile, new_mm, strdup (filename));
+ err = skip_to_firstsection (sectionsymbol);
+ }
+ if (err != 0) {
+ char* tmpbuf = malloc (sizeof(char)*1024);
+ if (tmpbuf) {
+ snprintf (tmpbuf, 1023, "cannot find section %s in file %s included from %s:%d.\n"
+ , (sectionname ? sectionname : "DEFAULT")
+ , filename, current_file, current_location);
+ yyerror (tmpbuf);
+ free (tmpbuf);
+ }
+ free (current_file);
+ free (filename);
+ exit (err);
+ }
+ free (current_file);
+ free (filename);
+ return 0;
+}
+
+/* Include multiple file sections, seperated by '+'. INCL is the
+ include string. SECTIONSYMBOL is the token that marks the beginning
+ of the section. DIRNAME is the name of the directory from where the
+ includefiles must be loaded. NEW_MM is the mergemode that should be
+ used. */
+static error_t
+include_sections (char *incl, int sectionsymbol, char *dirname,
+ mergemode new_mm)
+{
+ char *curstr;
+ char *s;
+
+ if (new_mm == defaultmm)
+ new_mm = merge_mode;
+
+/* printf ("dir: %s - include: %s: %d\n", dirname, incl, new_mm); */
+ /* Cut of all includes, starting with the first. The includes are
+ pushed on the stack in reversed order. */
+ do {
+ curstr = strrchr (incl, '+');
+ if (curstr)
+ {
+ curstr[0] = '\0';
+ curstr++;
+
+ s = strdup (curstr);
+ if (s == NULL)
+ return ENOMEM;
+
+ include_section (s, sectionsymbol, dirname, new_mm);
+ free (s);
+ }
+ } while (curstr);
+
+ s = strdup (incl);
+ if (s == NULL)
+ return ENOMEM;
+
+ include_section (s, sectionsymbol, dirname, new_mm);
+ free (s);
+
+ return 0;
+}
+
+/* Skip all tokens until the end of the section is reached. */
+static void
+skipsection (void)
+{
+ /* Pathesensis counter. */
+ int p = 0;
+ while (p >= 0)
+ {
+ int symbol = yylex ();
+ if (symbol == '{')
+ p++;
+ if (symbol == '}')
+ p--;
+ }
+ scanner_unput ('}');
+}
+
+/* Initialize the default action with the default DEF. */
+static error_t
+set_default_action (struct xkb_action *def,
+ struct xkb_action **newact)
+{
+ struct xkb_action *newaction;
+ newaction = malloc (sizeof (struct xkb_action));
+ if (newaction == NULL)
+ return ENOMEM;
+ memcpy (newaction, def, sizeof (struct xkb_action));
+
+ *newact = newaction;
+
+ return 0;
+}
+
+/* Remove all keysyms bound to the group GROUP or the key KEY. */
+static void
+remove_symbols (struct key *key, group_t group)
+{
+ // printf ("rem: group: %d\n", group);
+ if (key->groups[group].symbols)
+ {
+ free (key->groups[group].symbols);
+ key->groups[group].symbols = NULL;
+ key->groups[group].width = 0;
+ }
+}
+
+/* Set the keysym KS for key KEY on group GROUP and level LEVEL. */
+static void
+key_set_keysym (struct key *key, group_t group, int level, symbol ks)
+{
+ symbol *keysyms = key->groups[group].symbols;
+
+ if ((level + 1) > key->groups[group].width)
+ {
+ keysyms = realloc (keysyms, (level + 1)*sizeof(symbol));
+
+ if (!keysyms)
+ {
+ fprintf (stderr, "No mem\n");
+ exit (EXIT_FAILURE);
+ }
+
+ key->groups[group].symbols = keysyms;
+ key->groups[group].width++;
+ }
+ else
+ /* For NoSymbol leave the old symbol intact. */
+ if (!ks) {
+ debug_printf ("symbol %d was not added to key.\n", ks);
+ return;
+ }
+
+ debug_printf ("symbol '%c'(%d) added to key for group %d and level %d.\n", ks, ks, group, level);
+ keysyms[level++] = ks;
+}
+
+/* Set the action ACTION for key KEY on group GROUP and level LEVEL. */
+void
+key_set_action (struct key *key, group_t group, int level, xkb_action_t *action)
+{
+ xkb_action_t **actions = key->groups[group].actions;
+ size_t width = key->groups[group].actionwidth;
+
+ if ((size_t) (level + 1) > width)
+ {
+ actions = realloc (actions, (level + 1)*sizeof(xkb_action_t *));
+ /* Levels between 'width' and 'level' have no actions defined. */
+ memset (&actions[width], 0, (level - width)*sizeof(xkb_action_t *));
+
+ if (!actions)
+ {
+ fprintf (stderr, "No mem\n");
+ exit (EXIT_FAILURE);
+ }
+
+ key->groups[group].actions = actions;
+ key->groups[group].actionwidth += level - width + 1;
+ }
+
+ actions[level++] = action;
+}
+
+/* Delete keycode to keysym mapping. */
+void
+key_delete (char *keyname)
+{
+ group_t group;
+ keycode_t kc = keyname_find (keyname);
+
+ current_key = &keys[kc];
+ for (group = 0; group < current_key->numgroups; group++)
+ remove_symbols (current_key, group);
+ memset (current_key, 0, sizeof (struct key));
+
+}
+
+/* Create a new keycode to keysym mapping, check if the old one should
+ be removed or preserved. */
+static void
+key_new (char *keyname)
+{
+ group_t group;
+
+ int isempty (char *mem, int size)
+ {
+ int i;
+ for (i = 0; i < size; i++)
+ if (mem[i])
+ return 0;
+ return 1;
+ }
+
+ keycode_t kc = keyname_find (keyname);
+
+ if (merge_mode == augment)
+ {
+ if (!isempty ((char *) &keys[kc], sizeof (struct key)))
+ {
+ current_key = &dummy_key;
+ debug_printf ("working on dummy key due to merge mode.\n");
+ return;
+ }
+ else
+ current_key = &keys[kc];
+ }
+
+ if (merge_mode == override)
+ current_key = &keys[kc];
+
+ if (merge_mode == replace)
+ {
+ key_delete (keyname);
+ current_key = &keys[kc];
+ }
+
+ debug_printf ("working on key %s(%d)", keyname, kc);
+
+ if (current_key->numgroups == 0 || merge_mode == replace)
+ {
+ debug_printf (" cloned default key");
+ /* Clone the default key. */
+ memcpy (current_key, default_key, sizeof (struct key));
+ for (group = 0; group < 3; group++)
+ {
+ current_key->groups[group].symbols = NULL;
+ current_key->groups[group].actions = NULL;
+ current_key->groups[group].actionwidth = 0;
+ current_key->groups[group].width = 0;
+ }
+ }
+ debug_printf ("\n");
+}
+
+/* Load the XKB configuration from the section XKBKEYMAP in the
+ keymapfile XKBKEYMAPFILE. Use XKBDIR as root directory for relative
+ pathnames. */
+error_t
+parse_xkbconfig (char *xkbdir, char *xkbkeymapfile, char *xkbkeymap)
+{
+ error_t err;
+ char *cwd = getcwd (NULL, 0);
+ extern FILE *yyin;
+ extern char *filename;
+
+ debug_printf ("Dir: %s, file: %s sect: %s\n", xkbdir, xkbkeymapfile, xkbkeymap);
+
+ if (xkbkeymapfile)
+ {
+ filename = xkbkeymapfile;
+
+ if (chdir (xkbdir) == -1)
+ {
+ fprintf (stderr, "Could not set \"%s\" as the active directory\n",
+ xkbdir);
+ free (cwd);
+ return errno;
+ }
+
+ yyin = fopen (xkbkeymapfile, "r");
+ if (yyin == NULL)
+ {
+ fprintf (stderr, "Couldn't open keymap file\n");
+ free (cwd);
+ return errno;
+ }
+
+ if (xkbkeymap)
+ skip_to_sectionname (xkbkeymap, XKBKEYMAP);
+ else
+ skip_to_defaultsection();
+ }
+ else
+ {
+ free (cwd);
+ return EINVAL;
+ }
+ err = yyparse ();
+ fclose (yyin);
+
+ if (err || yynerrs > 0)
+ {
+ free (cwd);
+ return EINVAL;
+ }
+
+ if (xkbkeymapfile)
+ {
+ if (chdir (cwd) == -1)
+ {
+ fprintf (stderr,
+ "Could not set \"%s\" as the active directory\n", cwd);
+ free (cwd);
+ return errno;
+ }
+ }
+
+ /* Apply keysym to realmodifier mappings. */
+ ksrm_apply ();
+
+ free (cwd);
+ return 0;
+}
diff --git a/console-client/xkb/xkb-data/keymap/hurd b/console-client/xkb/xkb-data/keymap/hurd
new file mode 100644
index 00000000..dbb874c5
--- /dev/null
+++ b/console-client/xkb/xkb-data/keymap/hurd
@@ -0,0 +1,392 @@
+// $XFree86: xc/programs/xkbcomp/keymap/xfree86,v 3.30 2003/04/03 16:34:49 dawes Exp $
+
+
+xkb_keymap "Hurd" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+us+hurd+group(win_switch)+compose(menu)" };
+ xkb_geometry { include "pc" };
+};
+
+default xkb_keymap "us" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+us+hurd" };
+ xkb_geometry { include "pc" };
+};
+
+// "ar" addition by Arabeyes Team, <support@arabeyes.org>
+xkb_keymap "ar" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ara+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "be" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+be+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "bg" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+bg+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+// us_intl and br by Ricardo Y. Igarashi (iga@that.com.br)
+xkb_keymap "br" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+br+hurd" };
+ xkb_geometry { include "pc(abnt2)" };
+};
+// cz and sk keymaps by Kamil Toman (ktoman@email.cz)
+// are designed to replace old czechoslovakian and czsk keyboards
+// and their prog variants. Those are now obsolete and should not be used anymore.
+xkb_keymap "cz" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+cz+hurd" };
+ xkb_geometry { include "pc" };
+};
+xkb_keymap "de" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+de+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "ch_de" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ch(de)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "ch_fr" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ch(fr)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "dk" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+dk+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "dvorak" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+us(dvorak)+hurd"};
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "en_US" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+us+hurd" };
+ xkb_geometry { include "pc" };
+};
+xkb_keymap "es" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+es+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "fr" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+fr+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "fr-latin9" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+fr-latin9+hurd" };
+ xkb_geometry { include "pc" };
+};
+xkb_keymap "fr_CA" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ca+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "gb" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+gb+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "hr" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+hr+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "it" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+it+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "jp106" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "jp(jp106)+hurd" };
+ xkb_geometry { include "pc(jp106)" };
+};
+xkb_keymap "lt" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+lt+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "lt_std" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+lt(std)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "lv" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+lv+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "mk" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+mk+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "mt" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+mt+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "neo" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default+caps(caps_lock)+misc(assign_shift_left_action)+level5(level5_lock)" };
+ xkb_symbols { include "pc(pc105)+de(neo)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "no" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+no+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "pl" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+pl+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "pt" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+pt+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+// ro: additions by Cristian Gafton, <gafton@redhat.com>
+xkb_keymap "ro" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ro(pc101)+hurd" };
+ xkb_geometry { include "pc(pc101)" };
+};
+xkb_keymap "ro_microsoft" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ro(pc105)+hurd" };
+ xkb_geometry { include "pc(pc105)" };
+};
+xkb_keymap "ru" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ru+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "se_FI" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+fi+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "se_SE" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+se+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "sl" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+si+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "sl_SI" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+si+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+// cz and sk keymaps by Kamil Toman (ktoman@email.cz)
+// are designed to replace old czechoslovakian and czsk keyboards
+// and their prog variants. Those are now obsolete and should not be used anymore.
+xkb_keymap "sk" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+sk+hurd" };
+ xkb_geometry { include "pc" };
+};
+// Additions by Emil Soleyman-Zomalan, <emil@nishra.com>
+xkb_keymap "syr" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+syr+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "th" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+th+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "th_tis" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+th(tis)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "th_pat" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+th(pat)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "tr" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+tr+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "uk" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+uk)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "us_flexpro" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "us(pc105)+hurd" };
+ xkb_geometry { include "keytronic(FlexPro)" };
+};
+// us_intl and br by Ricardo Y. Igarashi (iga@that.com.br)
+// us_intl means standard us keyboard plus dead_keys symbols
+// these keyboards are very popular in Brazil
+xkb_keymap "us_intl" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "us(pc101)+us(intl)+hurd" };
+ xkb_geometry { include "pc" };
+};
+xkb_keymap "us_microsoft" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "us(pc105)+hurd" };
+ xkb_geometry { include "microsoft" };
+};
+
+xkb_keymap "uz" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+uz+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+
+# svu: compatibility keymaps, based on variants
+xkb_keymap "cz_qwerty" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+cz(qwerty)+hurd" };
+ xkb_geometry { include "pc" };
+};
+xkb_keymap "de_CH" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ch(de)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "fr_CH" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+ch(fr)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "mt_us" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+mt(us)+hurd" };
+ xkb_geometry { include "pc(pc102)" };
+};
+xkb_keymap "sk_qwerty" {
+ xkb_keycodes { include "xfree86" };
+ xkb_types { include "default+hurd" };
+ xkb_compatibility { include "default" };
+ xkb_symbols { include "pc(pc105)+sk(qwerty)+hurd" };
+ xkb_geometry { include "pc" };
+};
diff --git a/console-client/xkb/xkb-data/symbols/hurd b/console-client/xkb/xkb-data/symbols/hurd
new file mode 100644
index 00000000..39edf2ae
--- /dev/null
+++ b/console-client/xkb/xkb-data/symbols/hurd
@@ -0,0 +1,125 @@
+// -*- Mode: C -*-
+default
+xkb_symbols "hurd" {
+ /* Switch to local consoles by default. */
+ // SwitchScreen.SameServer;
+
+ /* Make F1 - F10 switch virtual consoles when Alt is held down. */
+ key <FK01>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 1),
+ NoAction () ]
+ };
+ key <FK02>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 2),
+ NoAction () ]
+ };
+ key <FK03>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 3),
+ NoAction () ]
+ };
+ key <FK04>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 4),
+ NoAction () ]
+ };
+ key <FK05>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 5),
+ NoAction () ]
+ };
+ key <FK06>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 6),
+ NoAction () ]
+ };
+ key <FK07>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 7),
+ NoAction () ]
+ };
+ key <FK08>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 8),
+ NoAction () ]
+ };
+ key <FK09>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 9),
+ NoAction () ]
+ };
+ key <FK10>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction () , SwitchScreen (screen = 10),
+ NoAction () ]
+ };
+
+ // Make the left and right cursor keys switch virtual consoles when
+ // Alt is held down.
+ key <LEFT>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (), SwitchScreen (screen -= 1),
+ NoAction () ]
+ };
+ key <RGHT>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (), SwitchScreen (screen += 1),
+ NoAction () ]
+ };
+
+ // Scroll the console up or down (one line).
+ key <UP>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (), ConsScroll (line -= 1) ]
+ };
+ key <DOWN>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (), ConsScroll (line += 1) ]
+ };
+
+ // Scroll the console up or down (1/2 screen).
+ key <PGUP>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (), NoAction (),
+ ConsScroll (screen -= 0.5) ]
+ };
+ key <PGDN>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (), NoAction (),
+ ConsScroll (screen += 0.5) ]
+ };
+
+ // Scroll the console to 0%, 25%, 75% or 100%.
+ key <HOME>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (),
+ ConsScroll (percentage = 0),
+ ConsScroll (percentage = 25) ]
+ };
+ key <END>
+ {
+ type[Group1] = "HURD",
+ actions[Group1] = [ NoAction (),
+ ConsScroll (percentage = 100),
+ ConsScroll (percentage = 75) ]
+ };
+};
diff --git a/console-client/xkb/xkb-data/types/hurd b/console-client/xkb/xkb-data/types/hurd
new file mode 100644
index 00000000..e6c7aa0c
--- /dev/null
+++ b/console-client/xkb/xkb-data/types/hurd
@@ -0,0 +1,18 @@
+// -*- Mode: C -*-
+
+default xkb_types "hurd" {
+ virtual_modifiers Alt;
+
+ type "HURD"
+ {
+ modifiers = Shift + Alt + Control;
+ map[Alt] = Level2;
+ map[Shift] = Level3;
+ map[Control] = Level4;
+ level_name[Level1] = "Base";
+ level_name[Level2] = "Hurd console";
+ level_name[Level3] = "Hurd console2";
+ level_name[Level4] = "Hurd console3";
+ };
+};
+
diff --git a/console-client/xkb/xkb.c b/console-client/xkb/xkb.c
new file mode 100644
index 00000000..0b439134
--- /dev/null
+++ b/console-client/xkb/xkb.c
@@ -0,0 +1,1380 @@
+/* xkb.c -- Main XKB routines.
+
+ Copyright (C) 2002, 2003, 2004 Marco Gerards
+
+ Written by Marco Gerards <metgerards@student.han.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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-1307 USA
+*/
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <iconv.h>
+#include <locale.h>
+#include <error.h>
+#include <device/device.h>
+#include <mach/mach_port.h>
+
+#include "xkb.h"
+#include <hurd/console.h>
+#define XK_XKB_KEYS
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
+#include <driver.h>
+#include <mach-inputdev.h>
+#include <wctype.h>
+
+
+
+/* The converter. */
+extern iconv_t cd;
+
+/* All interpretations for compatibility. (Translation from keysymbol
+ to actions). */
+xkb_interpret_t *interpretations;
+
+/* All keysymbols and how they are handled by XKB. */
+struct key *keys = NULL;
+int min_keys;
+int max_keys;
+
+/* The current set of modifiers. */
+static modmap_t bmods;
+/* Temporary set of modifiers. This is a copy of mods, so mods won't
+ be consumed (Effective modifiers). */
+static modmap_t emods;
+
+/* Effective group. */
+static group_t egroup;
+/* Base group. */
+static group_t bgroup;
+/* Locked group. */
+static group_t lgroup;
+/* Latched group. */
+static group_t latchedgroup;
+
+static boolctrls bboolctrls;
+
+/* A counter to count how often the modifier was set. This is used
+ when two seperate actions set the same modifier. (example: Left
+ Shift and Right Shift.). */
+modcount_t modsc;
+
+keystate_t keystate[255];
+
+/* The locked modifiers. Lock simply works an an invertion. */
+static modmap_t lmods = {0, 0};
+
+/* When the modifier is used the modifier will be consumed. */
+static modmap_t latchedmods = {0, 0};
+
+/* Not setting GroupsWrap uses modulus to keep the value into the
+ range. */
+static int GroupsWrap = 0;
+
+/* MouseKeys, default: off. */
+static int MouseKeys = 0;
+/* Default mousebutton. */
+static int default_button = 0;
+
+static xkb_indicator_t *indicators;
+static int indicator_count;
+static int indicator_map = 0;
+
+/* unused
+static int stickykeys_active = 1;
+*/
+
+int
+debug_printf (const char *f, ...)
+{
+ va_list ap;
+ int ret = 0;
+
+ va_start (ap, f);
+#ifdef XKB_DEBUG
+ ret = vfprintf (stderr, f, ap);
+#endif
+ va_end (ap);
+
+ return ret;
+}
+
+
+static void
+interpret_kc (keycode_t kc)
+{
+ int cursym;
+ int rmods = keys[kc].mods.rmods;
+ struct xkb_interpret *interp;
+
+ for (interp = interpretations; interp; interp = interp->next)
+ {
+ group_t group;
+
+ for (group = 0; group < keys[kc].numgroups; group++)
+ {
+ int width = keys[kc].groups[group].width;
+
+ for (cursym = 0; cursym < width; cursym++)
+ {
+ int symbol = keys[kc].groups[group].symbols[cursym];
+
+ /* Check if a keysymbol requirement exists or if it
+ matches. */
+ if (interp->symbol == 0 ||
+ (symbol && (interp->symbol == symbol)))
+ {
+ int flags = interp->match & 0x7f;
+
+ /* XXX: use enum. */
+ if ((flags == 0 && (!(interp->rmods & rmods))) ||
+ (flags == 1) ||
+ (flags == 2 && (interp->rmods & rmods)) ||
+ (flags == 3 && ((interp->rmods & rmods) ==
+ interp->rmods)) ||
+ (flags == 4 && interp->rmods == rmods))
+ {
+ xkb_action_t *action;
+
+ if (keys[kc].groups[group].actionwidth > cursym &&
+ keys[kc].groups[group].actions[cursym] &&
+ keys[kc].groups[group].actions[cursym]->type !=
+ SA_NoAction)
+ continue;
+
+ action = malloc (sizeof (xkb_action_t));
+ memcpy (action, &interp->action, sizeof (xkb_action_t));
+
+ key_set_action (&keys[kc], group, cursym, action);
+
+ keys[kc].flags = interp->flags | KEYHASACTION;
+ if (!keys[kc].mods.vmods)
+ keys[kc].mods.vmods = interp->vmod;
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+/* Test if c is an uppercase letter. */
+static int islatin_upper (int c)
+{
+ return (c >= 'A' && c <= 'Z');
+}
+
+/* Test if c is an lowercase letter. */
+static int islatin_lower (int c)
+{
+ return (c >= 'a' && c <= 'z');
+}
+
+/* A key is of the keytype KEYPAD when one of the symbols that can be produced
+ by this key is in the KEYPAD symbol range. */
+static int
+iskeypad (int width, int *sym)
+{
+ int i;
+
+ for (i = 0; i < width; i++, sym++)
+ {
+ /* Numlock is in the keypad range but shouldn't be of the type
+ keypad because it will depend on itself in that case. */
+ if (*sym == XK_Num_Lock)
+ return 0;
+ if (*sym >= KEYPAD_FIRST_KEY && *sym <= KEYPAD_LAST_KEY)
+ return 1;
+ }
+ return 0;
+}
+
+/* Get the keytype (the keytype determines which modifiers are used
+ for shifting.
+
+ For reference, see FindAutomaticType@xkbcomp/symbols.c.
+
+ These rules are used:
+
+ * If the width is 1 the keytype is ONE_LEVEL.
+ * If the first symbol is lowercase and the second is uppercase
+ (latin alphabeth) the keytype is ALPHABETHIC.
+ * If one of the symbols is in the keypad range the keytype is KEYPAD.
+ * If width is 4 the type is either FOUR_LEVEL, FOUR_LEVEL_ALPHABETIC,
+ FOUR_LEVEL_SEMI_ALPHABETIC (first sym pair is alphabetic) or
+ FOUR_LEVEL_KEYPAD.
+ * Else the keytype is TWO_LEVEL. */
+static struct keytype *
+get_keytype (int width, symbol *sym)
+{
+ struct keytype *ktfound = NULL;
+
+ if (!sym)
+ ktfound = keytype_find ("TWO_LEVEL");
+ else if ((width == 1) || (width == 0))
+ ktfound = keytype_find ("ONE_LEVEL");
+ else if (width == 2) {
+ if (islatin_lower (sym[0]) && islatin_upper (sym[1]))
+ ktfound = keytype_find ("ALPHABETIC");
+ else if (iskeypad (width, sym))
+ ktfound = keytype_find ("KEYPAD");
+ else
+ ktfound = keytype_find ("TWO_LEVEL");
+ }
+ else if (width <= 4) {
+ if (islatin_lower (sym[0]) && islatin_upper (sym[1]))
+ if (islatin_lower(sym[2]) && islatin_upper(sym[3]))
+ ktfound = keytype_find ("FOUR_LEVEL_ALPHABETIC");
+ else
+ ktfound = keytype_find ("FOUR_LEVEL_SEMIALPHABETIC");
+ else if (iskeypad (2, sym))
+ ktfound = keytype_find ("FOUR_LEVEL_KEYPAD");
+ else
+ ktfound = keytype_find ("FOUR_LEVEL");
+ }
+
+ if (!ktfound)
+ ktfound = keytype_find ("TWO_LEVEL");
+ if (!ktfound)
+ {
+ console_error (L"Default keytypes have not been defined!\n");
+ exit (1);
+ }
+
+ return ktfound;
+}
+
+/* Create XKB style actions for every action described by keysymbols. */
+static void
+interpret_all (void)
+{
+ keycode_t curkc;
+
+ /* Check every key. */
+ for (curkc = 0; curkc < max_keys; curkc++)
+ interpret_kc (curkc);
+}
+
+static void
+determine_keytypes (void)
+{
+ keycode_t curkc;
+
+ /* Check every key. */
+ for (curkc = 0; curkc < max_keys; curkc++)
+ {
+ group_t group;
+ for (group = 0; group < 4; group++)
+ {
+ struct keygroup *kg = &keys[curkc].groups[group];
+
+ if (!kg->keytype)
+ kg->keytype = get_keytype (kg->width, kg->symbols);
+ }
+ }
+}
+
+/* Wrap the group GROUP into a valid group range. The method to use is
+ defined by the GroupsWrap control. */
+static int
+wrapgroup (group_t group, int maxgroup)
+{
+ /* If the group is in an invalid range, fix it. */
+ if (group < 0 || group >= maxgroup)
+ {
+ /* If RedirectIntoRange should be used use the 4 LSbs of
+ the GroupsWrap control instead of the current group. */
+ if (GroupsWrap & RedirectIntoRange)
+ group = GroupsWrap & 0x0F;
+ /* Select the closest valid group. */
+ else if (GroupsWrap & ClampIntoRange)
+ {
+ if (group < 0)
+ group = 0;
+ else
+ group = maxgroup - 1;
+ }
+ else /* Default: use modulus to wrap the group. */
+ group %= maxgroup;
+ }
+
+ return group;
+}
+
+
+
+/* This function must be called after a modifier, group or control has
+ been changed. The indicator map will be regenerated and the hardwre
+ representation of this map will be updated. */
+static void
+set_indicator_mods (void)
+{
+ int i;
+
+ /* Calculate the effective modmap. */
+ emods = bmods;
+ emods.rmods |= lmods.rmods;
+ emods.vmods |= lmods.vmods;
+ emods.rmods |= latchedmods.rmods;
+ emods.vmods |= latchedmods.vmods;
+
+ for (i = 0; i < indicator_count; i++)
+ {
+ if (!(indicators[i].flags & IM_NoAutomatic))
+ {
+ if (indicators[i].which_mods & IM_UseBase)
+ {
+ if (((indicators[i].modmap.rmods & bmods.rmods) ==
+ indicators[i].modmap.rmods) &&
+ ((indicators[i].modmap.vmods & bmods.vmods) ==
+ indicators[i].modmap.vmods))
+ {
+ indicator_map |= (1 << i);
+ continue;
+ }
+ }
+ if (indicators[i].which_mods & IM_UseLatched)
+ {
+ if (((indicators[i].modmap.rmods & latchedmods.rmods) ==
+ indicators[i].modmap.rmods) &&
+ ((indicators[i].modmap.vmods & latchedmods.vmods) ==
+ indicators[i].modmap.vmods))
+ {
+ indicator_map |= (1 << i);
+ continue;
+ }
+ }
+ if (indicators[i].which_mods & IM_UseLocked)
+ {
+ if (((indicators[i].modmap.rmods & lmods.rmods) ==
+ indicators[i].modmap.rmods) &&
+ ((indicators[i].modmap.vmods & lmods.vmods) ==
+ indicators[i].modmap.vmods))
+ {
+ indicator_map |= (1 << i);
+ continue;
+ }
+ }
+ if (indicators[i].which_mods & IM_UseEffective)
+ {
+ if (((indicators[i].modmap.rmods & emods.rmods) ==
+ indicators[i].modmap.rmods) &&
+ ((indicators[i].modmap.vmods & emods.vmods) ==
+ indicators[i].modmap.vmods))
+ {
+ indicator_map |= (1 << i);
+ continue;
+ }
+ }
+ /* The indicator shouldn't be on anymore so turn it off. */
+ indicator_map &= ~(1 << i);
+ }
+ }
+ debug_printf ("INDICATOR: %d\n", indicator_map);
+}
+
+/* Set base modifiers. A counter exists for every modifier. When a
+ modifier is set this counter will be incremented with one. */
+static void
+setmods (modmap_t smods, keypress_t key)
+{
+ /* Higher the modcount for every set modifier. */
+ void set_xmods (int xmods, int modsc[])
+ {
+ int i = 0;
+
+ while (xmods)
+ {
+ if (xmods & 1)
+ modsc[i]++;
+
+ xmods >>= 1;
+ i++;
+ }
+ }
+
+ bmods.rmods |= smods.rmods;
+ bmods.vmods |= smods.vmods;
+
+ set_xmods (smods.rmods, modsc.rmods);
+ set_xmods (smods.vmods, modsc.vmods);
+
+ set_indicator_mods ();
+}
+
+/* Clear base modifiers. A counter exists for every modifier. When a
+ key release wants to clear a modifier this counter will be
+ decreased with one. When the counter becomes 0 the modifier will be
+ cleared and unlocked if the clearLocks flag is set. */
+static void
+clearmods (modmap_t cmods, keypress_t key, int flags)
+{
+#define CLEAR_XMOD(MODTYPE) \
+ { \
+ int i = 0; \
+ int mmods = cmods.MODTYPE; \
+ \
+ while (mmods) \
+ { \
+ if (mmods & 1) \
+ if (!(--modsc.MODTYPE[i])) \
+ { \
+ bmods.MODTYPE &= ~(1 << i); \
+ if (flags & clearLocks) \
+ lmods.MODTYPE &= ~(1 << i); \
+ } \
+ mmods >>= 1; \
+ i++; \
+ } \
+ }
+
+ CLEAR_XMOD(rmods);
+ CLEAR_XMOD(vmods);
+
+ set_indicator_mods ();
+}
+
+/* Set modifiers in smods and also lock them if the flag noLock is
+ not set. */
+static void
+setlocks (modmap_t smods, keypress_t key, int flags)
+{
+ if (!key.rel)
+ {
+ modmap_t cmods;
+ cmods.rmods = lmods.rmods & smods.rmods;
+ cmods.vmods = lmods.vmods & smods.vmods;
+
+ /* Locking also sets the base modifiers. */
+ setmods (smods, key);
+
+ if (!(flags & noUnlock))
+ {
+ lmods.rmods &= ~cmods.rmods;
+ lmods.vmods &= ~cmods.vmods;
+ }
+
+ if (!(flags & noLock))
+ {
+ lmods.rmods |= (~cmods.rmods & smods.rmods);
+ lmods.vmods |= (~cmods.vmods & smods.vmods);
+ }
+ }
+ else
+ clearmods (smods, key, flags);
+}
+
+/* Latch the modifiers smods for key KEY. When another key is operated while
+ KEY is pressed the release of KEY will just clear the base
+ modifiers, otherwise latch the modifiers like is described in the
+ protocol specification. */
+static void
+latchmods (modmap_t smods, keypress_t key, int flags)
+{
+ if (!key.rel)
+ setmods (smods, key);
+ else
+ {
+ modmap_t oldlmods;
+ oldlmods = lmods;
+ clearmods (smods, key, flags);
+ /* Modifier that have been unlocked don't have effect anymore. */
+ smods.rmods &= ~(lmods.rmods & oldlmods.rmods);
+ smods.vmods &= ~(lmods.vmods & oldlmods.vmods);
+
+
+ /* If another key has been pressed while this modifier key was
+ pressed don't latch, just behave as SetMods. */
+ if (key.keycode == key.prevkc)
+ {
+ if (flags & latchToLock)
+ {
+ /* When a modifier exists as a locked modifier, consume
+ and unlock. */
+ lmods.rmods |= latchedmods.rmods & smods.rmods;
+ lmods.vmods |= latchedmods.vmods & smods.vmods;
+
+ smods.rmods &= ~(latchedmods.rmods & smods.rmods);
+ smods.vmods &= ~(latchedmods.vmods & smods.vmods);
+ }
+
+ /* Use the remaining modifiers for latching. */
+ latchedmods.rmods |= smods.rmods;
+ latchedmods.vmods |= smods.vmods;
+ }
+ }
+}
+
+static void
+setgroup (keypress_t key, group_t group, int flags)
+{
+ debug_printf ("Setgroup ()\n");
+ if (!key.rel)
+ {
+ if (flags & groupAbsolute)
+ {
+ bgroup = group;
+ keystate[key.keycode].oldgroup = bgroup;
+ }
+ else
+ bgroup += group;
+ }
+ else
+ {
+ if ((key.keycode == key.prevkc) && (flags & clearLocks))
+ lgroup = 0;
+ if (flags & groupAbsolute)
+ bgroup = keystate[key.keycode].oldgroup;
+ else
+ /* XXX: Maybe oldgroup should be restored for !groupAbsolute
+ too, because wrapgroup might have affected the calculation
+ and substracting will not undo the set operation. However
+ this way of handeling relative groups is better because the
+ order of releasing keys when multiple relative setgroup keys
+ are pressed doesn't matter. */
+ bgroup -= group;
+ }
+}
+
+static void
+latchgroup (keypress_t key, group_t sgroup, int flags)
+{
+ group_t oldlgroup = sgroup;
+ setgroup (key, sgroup, flags);
+ debug_printf ("Latchgroup ()\n");
+
+ if (key.keycode == key.prevkc && oldlgroup == lgroup)
+ {
+ if ((flags & latchToLock) && latchedgroup)
+ {
+ lgroup += sgroup;
+ latchedgroup -= sgroup;
+ }
+ else
+ latchedgroup += sgroup;
+ }
+}
+
+static void
+lockgroup (keypress_t key, group_t group, int flags)
+{
+ debug_printf (">L: %d, g: %d\n", lgroup, group);
+
+ keystate[key.keycode].oldgroup = lgroup;
+ if (flags & groupAbsolute)
+ lgroup = group;
+ else
+ lgroup += group;
+
+ lgroup = wrapgroup (lgroup, 4);
+
+ debug_printf ("<L: %d, g: %d\n", lgroup, group);
+
+}
+
+static void
+setcontrols (keypress_t key, boolctrls ctrls, int flags)
+{
+ keystate[key.keycode].bool = ctrls & ~bboolctrls;
+ bboolctrls |= ctrls;
+}
+
+static void
+clearcontrols (keypress_t key, boolctrls ctrls, int flags)
+{
+ bboolctrls &= ~keystate[key.keycode].bool;
+}
+
+static void
+lockcontrols (keypress_t key, boolctrls ctrls, int flags)
+{
+ if (!key.rel)
+ {
+ //setcontrols (key, boolctrls, flags);
+ if (!(flags & noLock));
+ // lboolctrls |= boolctrls;
+ }
+ else
+ {
+ // clearcontrols (key, boolctrls, flags);
+ /* This unlock behaviour doesnt work and sucks, just like the protocol
+ specification where it was documented. */
+ // if (!(flags & noUnlock))
+ // lboolctrls &= ~keystate[key.keycode].bool;
+ }
+
+}
+
+/* Not properly implemented, not very high priority for me. */
+/* static void */
+/* isolock (keypress_t key, group group, modmap_t mods, int flags) */
+/* { */
+/* if (!key.rel) */
+/* { */
+/* struct isolock *newiso; */
+
+/* if (flags & dfltIsGroup) */
+/* setgroup (key, group, flags & groupAbsolute); */
+/* else */
+/* setmods (key, mods, 0); */
+
+/* newiso = malloc (sizeof struct isolock); */
+/* if (!newiso) */
+/* ;// return error */
+/* active_isolocks.anchor */
+/* } */
+/* else */
+/* { */
+/* if (flags & dfltIsGroup) */
+/* { */
+/* cleargroup (key, group, flags & groupAbsolute); */
+/* if (bla) */
+/* lockgroup (key, group, flags & groupAbsolute); */
+/* } */
+/* else */
+/* { */
+/* clearmods (key, mods, 0); */
+/* if (bla) */
+/* { */
+/* lmods.rmods |= mods.rmods; */
+/* lmods.vmods |= mods.vmods; */
+/* } */
+/* } */
+/* } */
+/* } */
+
+/* Move the mousepointer relational to its current position. */
+static void
+mouse_x_move (int xdelta)
+{
+ /* XXX: Ofcouse this function has to do *something* :). */
+}
+
+/* Change the horizontal position of the mousepointer. */
+static void
+mouse_x_move_to (int x)
+{
+ /* XXX: Ofcouse this function has to do *something* :). */
+}
+
+/* Move the mousepointer relational to its current position. */
+static void
+mouse_y_move (int ydelta)
+{
+ /* XXX: Ofcouse this function has to do *something* :). */
+}
+
+/* Change the vertical position of the mousepointer. */
+static void
+mouse_y_move_to (int y)
+{
+ /* XXX: Ofcouse this function has to do *something* :). */
+}
+
+/* Simulate a mouse button press for button BUTTON. */
+static void
+mouse_button_press (int button)
+{
+ /* XXX: Ofcouse this function has to do *something* :). */
+}
+
+/* Simulate a mouse button press for button BUTTON. */
+static void
+mouse_button_release (int button)
+{
+ /* XXX: Ofcouse this function has to do *something* :). */
+}
+
+
+
+/* Forward declaration for redirected keys. */
+static symbol handle_key (keypress_t);
+
+
+/* Execute an action bound to a key. When the action isn't supported
+ or when the action doesn't consume the key return true, otherwise
+ return false. */
+static int
+action_exec (xkb_action_t *action, keypress_t key)
+{
+ if (!action)
+ return KEYNOTCONSUMED;
+
+ debug_printf ("EXEC: %d\n", action->type);
+
+ switch (action->type)
+ {
+ /* LockMods: Lock/Unlock modifiers when the key is pressed. */
+ case SA_LockMods:
+ {
+ action_setmods_t *setmodmap = (action_setmods_t *) action;
+ modmap_t modm = setmodmap->modmap;
+
+ /* UseModMap */
+ if (setmodmap->flags & useModMap)
+ {
+ modm.rmods |= keys[key.keycode].mods.rmods;
+ modm.vmods |= keys[key.keycode].mods.vmods;
+ }
+
+ setlocks (modm, key, setmodmap->flags);
+ }
+ break;
+ /* SetMods: Set/Unset modifiers. Those modifier will be set as
+ long the key is pressed. Keys like shift, alt and control are
+ used here often. */
+ case SA_SetMods:
+ {
+ action_setmods_t *setmodmap = (action_setmods_t *) action;
+ modmap_t modm = setmodmap->modmap;
+
+ /* UseModMapMods means: also use the real modifiers specified
+ in the key's modmap. */
+ if (setmodmap->flags & useModMap)
+ {
+ debug_printf ("Apply modmaps\n");
+ modm.rmods |= keys[key.keycode].mods.rmods;
+ modm.vmods |= keys[key.keycode].mods.vmods;
+ }
+
+ /* When the key is pressed set the modifiers. */
+ if (!key.rel)
+ setmods (modm, key);
+ else /* When the key is released clear the modifiers. */
+ clearmods (modm, key, setmodmap->flags);
+
+ break;
+ }
+ /* Set the basegroup. When groupAbsolute isn't used add it
+ to the basegroup. */
+ case SA_LatchMods:
+ {
+ action_setmods_t *setmodmap = (action_setmods_t *) action;
+
+ modmap_t modm = setmodmap->modmap;
+
+ /* UseModMapMods means: also use the real modifiers specified
+ in the key's modmap. */
+ if (setmodmap->flags & useModMap)
+ {
+ modm.rmods |= keys[key.keycode].mods.rmods;
+ modm.vmods |= keys[key.keycode].mods.vmods;
+ }
+
+ latchmods (modm, key, setmodmap->flags);
+
+ break;
+ }
+ case SA_SetGroup:
+ {
+ action_setgroup_t *setgroupac = (action_setgroup_t *) action;
+
+ setgroup (key, setgroupac->group, setgroupac->flags);
+ break;
+ }
+ case SA_LockGroup:
+ {
+ action_setgroup_t *setgroupac = (action_setgroup_t *) action;
+
+ if (!key.rel)
+ lockgroup (key, setgroupac->group, setgroupac->flags);
+ break;
+ }
+ case SA_LatchGroup:
+ {
+ action_setgroup_t *setgroupac = (action_setgroup_t *) action;
+
+ latchgroup (key, setgroupac->group, setgroupac->flags);
+ break;
+ }
+
+ case SA_PtrBtn:
+ {
+ action_ptrbtn_t *ptrbtnac = (action_ptrbtn_t *) action;
+ int i;
+ int button;
+
+ if (!MouseKeys)
+ return KEYNOTCONSUMED;
+
+ if (ptrbtnac->flags & useDfltBtn)
+ button = default_button;
+ else
+ button = ptrbtnac->button;
+
+ if (ptrbtnac->count)
+ for (i = 0; i < ptrbtnac->count; i++)
+ {
+ /* XXX: Should there be a delay? */
+ mouse_button_press (button);
+ mouse_button_release (button);
+ }
+ else if (!key.rel)
+ mouse_button_press (button);
+ else
+ mouse_button_release (button);
+ break;
+ }
+ case SA_LockPtrBtn:
+ {
+ action_ptrbtn_t *ptrbtnac = (action_ptrbtn_t *) action;
+
+ int button;
+
+ if (!MouseKeys)
+ return KEYNOTCONSUMED;
+
+ if (ptrbtnac->flags & useDfltBtn)
+ button = default_button;
+ else
+ button = ptrbtnac->button;
+
+ /* XXX: Do stuff. */
+
+ break;
+ }
+ case SA_SetPtrDflt:
+ {
+ action_ptr_dflt_t *ptrdfltac = (action_ptr_dflt_t *) action;
+
+ if (!MouseKeys)
+ return KEYNOTCONSUMED;
+
+ if (!key.rel)
+ {
+ if (ptrdfltac->flags & DfltBtnAbsolute)
+ default_button = ptrdfltac->value;
+ else
+ default_button += ptrdfltac->value;
+ }
+
+ if (default_button < 0)
+ default_button = 0;
+
+ if (default_button > 5)
+ default_button = 5;
+
+ break;
+ }
+ case SA_TerminateServer:
+ /* Zap! */
+ console_exit ();
+ break;
+ case SA_SwitchScreen:
+ {
+ action_switchscrn_t *switchscrnac = (action_switchscrn_t *) action;
+
+ if (key.rel)
+ break;
+
+ if (switchscrnac->flags & screenAbs)
+ /* Switch to screen. */
+ console_switch ((char) switchscrnac->screen, 0);
+ else
+ /* Move to next/prev. screen. */
+ console_switch (0, (char) switchscrnac->screen);
+ break;
+ }
+ case SA_RedirectKey:
+ {
+ action_redirkey_t *redirkeyac = (action_redirkey_t *) action;
+
+ key.keycode = redirkeyac->newkey & (key.rel ? 0x80:0);
+
+ /* For the redirected key other modifiers should be used. */
+ emods.rmods = bmods.rmods | lmods.rmods | latchedmods.rmods;
+ emods.vmods = bmods.vmods | lmods.vmods | latchedmods.vmods;
+
+ emods.rmods &= ~redirkeyac->rmodsmask;
+ emods.rmods |= redirkeyac->rmods;
+ emods.vmods &= ~redirkeyac->vmods;
+ emods.vmods |= redirkeyac->vmodsmask;
+
+ /* XXX: calc group etc. */
+
+ handle_key (key);
+ break;
+ }
+ case SA_ConsScroll:
+ {
+ action_consscroll_t *scrollac = (action_consscroll_t *) action;
+
+ if (key.rel)
+ break;
+
+ if (scrollac->flags & usePercentage)
+ console_scrollback (CONS_SCROLL_ABSOLUTE_PERCENTAGE,
+ 100 - scrollac->percent);
+
+ if (scrollac->screen)
+ console_scrollback (CONS_SCROLL_DELTA_SCREENS, -scrollac->screen);
+
+ if (scrollac->line)
+ {
+ int type = (scrollac->flags & lineAbs) ?
+ CONS_SCROLL_ABSOLUTE_LINE : CONS_SCROLL_DELTA_LINES;
+ console_scrollback (type, -scrollac->line);
+ }
+ break;
+ }
+ case SA_ActionMessage:
+ case SA_DeviceBtn:
+ case SA_LockDeviceBtn:
+ case SA_DeviceValuator:
+ return KEYNOTCONSUMED;
+ case SA_MovePtr:
+ {
+ action_moveptr_t *moveptrac = (action_moveptr_t *) action;
+
+ if (!MouseKeys)
+ return KEYNOTCONSUMED;
+
+ if (moveptrac->flags & MoveAbsoluteX)
+ mouse_x_move_to (moveptrac->x);
+ else
+ mouse_x_move (moveptrac->x);
+
+ if (moveptrac->flags & MoveAbsoluteY)
+ mouse_y_move_to (moveptrac->y);
+ else
+ mouse_y_move (moveptrac->y);
+ break;
+ }
+ case SA_SetControls:
+ {
+ action_setcontrols_t *controlsac = (action_setcontrols_t *) action;
+ if (key.rel)
+ clearcontrols (key, controlsac->controls, 0);
+ else
+ setcontrols (key, controlsac->controls, 0);
+ break;
+ }
+ case SA_LockControls:
+ {
+ action_setcontrols_t *controlsac = (action_setcontrols_t *) action;
+ lockcontrols (key, controlsac->controls, 0);
+ break;
+ }
+ default:
+ /* Preserve the keycode. */
+ return KEYNOTCONSUMED;
+ break;
+ }
+
+ /* Don't preserve the keycode because it was consumed. */
+ return KEYCONSUMED;
+}
+
+
+
+/* Calculate the shift level for a specific key. */
+static int
+calc_shift (keycode_t key)
+{
+ /* The keytype for this key. */
+ struct keytype *keytype = keys[key].groups[egroup].keytype;
+ struct typemap *map;
+
+ /* XXX: Shouldn't happen, another way to fix this? */
+ if (!keytype)
+ return 0;
+
+ /* Scan though all modifier to level maps of this keytype to search
+ the level. */
+ for (map = keytype->maps; map; map = map->next)
+ /* Does this map meet our requirements? */
+ if (map->mods.rmods == (emods.rmods & keytype->modmask.rmods) &&
+ map->mods.vmods == (emods.vmods & keytype->modmask.vmods))
+ {
+ /* Preserve all modifiers specified in preserve for this map. */
+ emods.rmods &= ~(map->mods.rmods & (~map->preserve.rmods));
+ emods.vmods &= ~(map->mods.vmods & (~map->preserve.vmods));
+ return map->level;
+ }
+
+ /* When no map is found use the default shift level and consume all
+ modifiers. */
+ emods.vmods &= ~keytype->modmask.vmods;
+ emods.rmods &= ~keytype->modmask.rmods;
+
+ return 0;
+}
+
+static symbol
+symtoctrlsym (symbol c)
+{
+ c = toupper (c);
+
+ switch (c)
+ {
+ case 'A' ... 'Z':
+ c = c - 'A' + 1;
+ break;
+ case '[': case '3':
+ c = '\e';
+ break;
+ case '\\': case '4':
+ c = '';
+ break;
+ case ']': case '5':
+ c = '';
+ break;
+ case '^': case '6':
+ c = '';
+ break;
+ case '/':
+ c = '/';
+ break;
+ case ' ':
+ c = '\0';
+ break;
+ case '_': case '7':
+ c= '';
+ break;
+ case '8':
+ c = '\x7f';
+ break;
+ }
+
+ return c;
+}
+
+
+/* Handle all actions, etc. bound to the key KEYCODE and return a XKB
+ symbol if one is generated by this key. If redirected_key contains
+ 1 this is keypress generated by the action SA_RedirectKey, don't
+ change the effective modifiers because they exist and have been
+ changed by SA_RedirectKey. */
+static symbol
+handle_key (keypress_t key)
+{
+ int actioncompl = 0;
+
+ modmap_t oldmods;
+ group_t oldgroup = 0;
+
+ /* The level for this key. */
+ int level;
+
+ /* The symbol this keypress generated. */
+ symbol sym = 0;
+
+ debug_printf ("groups\n");
+ /* If the key does not have a group there is nothing to do. */
+ if (keys[key.keycode].numgroups == 0)
+ return -1;
+
+ /* The effective group is the current group, but it can't be
+ out of range. */
+ egroup = wrapgroup (bgroup + lgroup,
+ keys[key.keycode].numgroups);
+
+ if (keys[key.keycode].groups[egroup].actions)
+ {
+ if (key.rel)
+ {
+ debug_printf ("action\n");
+ if (!keystate[key.keycode].prevstate)
+ /* Executing the inverse action of a never executed
+ action... Stop! */
+ return -1;
+
+ keystate[key.keycode].prevstate = 0;
+ emods = keystate[key.keycode].prevmods;
+ egroup = wrapgroup (keystate[key.keycode].prevgroup,
+ keys[key.keycode].numgroups);
+ }
+ else /* This is a keypress event. */
+ {
+ /* Calculate the effective modmap. */
+ emods = bmods;
+ emods.rmods |= lmods.rmods;
+ emods.vmods |= lmods.vmods;
+ emods.rmods |= latchedmods.rmods;
+ emods.vmods |= latchedmods.vmods;
+ }
+
+ oldmods = emods;
+ oldgroup = egroup;
+
+ level = calc_shift (key.keycode);// %
+
+ if (keys[key.keycode].groups[egroup].actionwidth >= level + 1
+ && keys[key.keycode].groups[egroup].actions[level])
+ {
+ actioncompl = action_exec
+ (keys[key.keycode].groups[egroup].actions[level], key);
+ }
+ }
+
+ if (actioncompl == KEYCONSUMED && !key.rel)
+ {
+ /* An action was executed. Store the effective modifier this key
+ so the reverse action can be called on key release. */
+ keystate[key.keycode].prevstate = 1;
+ keystate[key.keycode].prevmods = oldmods;
+ keystate[key.keycode].prevgroup = oldgroup;
+ }
+
+ debug_printf ("consumed: %d - %d -%d\n", actioncompl, key.rel,
+ !keys[key.keycode].groups[egroup].width);
+ /* If the action comsumed the keycode, this is a key release event
+ or if the key doesn't have any symbols bound to it there is no
+ symbol returned. */
+ if (actioncompl == KEYCONSUMED || key.rel ||
+ !keys[key.keycode].groups[egroup].width)
+ return -1;
+
+ /* Calculate the effective modmap. */
+ emods = bmods;
+ emods.rmods |= lmods.rmods;
+ emods.vmods |= lmods.vmods;
+ emods.rmods |= latchedmods.rmods;
+ emods.vmods |= latchedmods.vmods;
+
+ level = calc_shift (key.keycode) % keys[key.keycode].groups[egroup].width;
+
+ /* The latched modifier is used for a symbol, clear it. */
+ latchedmods.rmods = latchedmods.vmods = 0;
+
+ /* Search the symbol for this key in the keytable. Make sure the
+ group and shift level exists. */
+ sym = keys[key.keycode].groups[egroup].symbols[level];
+
+ /* Convert keypad symbols to symbols. XXX: Is this the right place
+ to do this? */
+ if ((sym >= XK_KP_Multiply && sym <= XK_KP_Equal) || sym == XK_KP_Enter)
+ sym &= ~0xFF80;
+
+ /* Check if this keypress was a part of a compose sequence. */
+ sym = compose_symbols (sym);
+
+ return sym;
+}
+
+void
+xkb_input (keypress_t key)
+{
+ char buf[100];
+ size_t size = 0;
+ wchar_t input;
+
+ debug_printf ("input: %d, rel: %d, rep: %d\n", key.keycode, key.rel, key.repeat);
+
+ if (key.rel)
+ keystate[key.keycode].lmods = lmods;
+ input = handle_key (key);
+
+ debug_printf ("handle: %d\n", input);
+ if (input == -1)
+ return;
+
+ /* If the realmodifier MOD1 (AKA Alt) is set generate an ESC
+ symbol. */
+ if (emods.rmods & RMOD_MOD1)
+ buf[size++] = '\e';
+
+ buf[size] = '\0';
+
+ if (!input)
+ return;
+
+ /* Special key, generate escape sequence. */
+ char *escseq = NULL;
+
+ switch (input)
+ {
+ case XK_Up: case XK_KP_Up:
+ escseq = CONS_KEY_UP;
+ break;
+ case XK_Down: case XK_KP_Down:
+ escseq = CONS_KEY_DOWN;
+ break;
+ case XK_Left: case XK_KP_Left:
+ escseq = CONS_KEY_LEFT;
+ break;
+ case XK_Right: case XK_KP_Right:
+ escseq = CONS_KEY_RIGHT;
+ break;
+ case XK_BackSpace:
+ escseq = CONS_KEY_BACKSPACE;
+ break;
+ case XK_F1: case XK_KP_F1:
+ escseq = CONS_KEY_F1;
+ break;
+ case XK_F2: case XK_KP_F2:
+ escseq = CONS_KEY_F2;
+ break;
+ case XK_F3: case XK_KP_F3:
+ escseq = CONS_KEY_F3;
+ break;
+ case XK_F4: case XK_KP_F4:
+ escseq = CONS_KEY_F4;
+ break;
+ case XK_F5:
+ escseq = CONS_KEY_F5;
+ break;
+ case XK_F6:
+ escseq = CONS_KEY_F6;
+ break;
+ case XK_F7:
+ escseq = CONS_KEY_F7;
+ break;
+ case XK_F8:
+ escseq = CONS_KEY_F8;
+ break;
+ case XK_F9:
+ escseq = CONS_KEY_F9;
+ break;
+ case XK_F10:
+ escseq = CONS_KEY_F10;
+ break;
+ case XK_F11:
+ escseq = CONS_KEY_F11;
+ break;
+ case XK_F12:
+ escseq = CONS_KEY_F12;
+ break;
+ case XK_F13:
+ escseq = CONS_KEY_F13;
+ break;
+ case XK_F14:
+ escseq = CONS_KEY_F14;
+ break;
+ case XK_F15:
+ escseq = CONS_KEY_F15;
+ break;
+ case XK_F16:
+ escseq = CONS_KEY_F16;
+ break;
+ case XK_F17:
+ escseq = CONS_KEY_F17;
+ break;
+ case XK_F18:
+ escseq = CONS_KEY_F18;
+ break;
+ case XK_F19:
+ escseq = CONS_KEY_F19;
+ break;
+ case XK_F20:
+ escseq = CONS_KEY_F20;
+ break;
+ case XK_Home: case XK_KP_Home:
+ escseq = CONS_KEY_HOME;
+ break;
+ case XK_Insert: case XK_KP_Insert:
+ escseq = CONS_KEY_IC;
+ break;
+ case XK_Delete: case XK_KP_Delete:
+ escseq = CONS_KEY_DC;
+ break;
+ case XK_End: case XK_KP_End:
+ escseq = CONS_KEY_END;
+ break;
+ case XK_Page_Up: case XK_KP_Page_Up:
+ escseq = CONS_KEY_PPAGE;
+ break;
+ case XK_Page_Down: case XK_KP_Page_Down:
+ escseq = CONS_KEY_NPAGE;
+ break;
+ case XK_KP_Begin:
+ escseq = CONS_KEY_B2;
+ break;
+ case XK_ISO_Left_Tab:
+ escseq = CONS_KEY_BTAB;
+ break;
+ case XK_Return: case XK_KP_Enter:
+ escseq = "\x0d";
+ break;
+ case XK_Tab: case XK_KP_Tab:
+ escseq = "\t";
+ break;
+ case XK_Escape:
+ escseq = "\e";
+ break;
+ }
+
+ if (escseq != NULL)
+ {
+ strcat (buf + size, escseq);
+ size += strlen (escseq);
+ }
+ else
+ {
+ char *buffer = &buf[size];
+ size_t left = sizeof (buf) - size;
+ char *inbuf = (char *) &input;
+ size_t inbufsize = sizeof (wchar_t);
+ size_t nr;
+
+ /* Control key behaviour. */
+ if (bmods.rmods & RMOD_CTRL)
+ input = symtoctrlsym (input);
+
+ /* Convert the Keysym to a UCS4 characted. */
+ input = KeySymToUcs4 (input);
+ /* if (!input) */
+ /* continue; */
+
+ debug_printf ("UCS4: %d -- %c\n", (int) input, input);
+
+ /* If CAPSLOCK is active capitalize the symbol. */
+ if (emods.rmods & 2)
+ input = towupper (input);
+
+ 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;
+ }
+
+ if (size)
+ console_input (buf, size);
+ size = 0;
+}
+
+error_t parse_xkbconfig (char *xkbdir, char *xkbkeymapfile, char *xkbkeymap);
+
+error_t
+xkb_load_layout (char *xkbdir, char *xkbkeymapfile, char *xkbkeymap)
+{
+ error_t err;
+
+ err = parse_xkbconfig (xkbdir, xkbkeymapfile, xkbkeymap);
+ if (err)
+ return err;
+
+ determine_keytypes ();
+ interpret_all ();
+ return 0;
+}
diff --git a/console-client/xkb/xkb.h b/console-client/xkb/xkb.h
new file mode 100644
index 00000000..07694930
--- /dev/null
+++ b/console-client/xkb/xkb.h
@@ -0,0 +1,431 @@
+/* Keyboard plugin for the Hurd console using XKB keymaps.
+
+ Copyright (C) 2002,03 Marco Gerards
+
+ Written by Marco Gerards <marco@student.han.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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. */
+
+#include <errno.h>
+#include <argp.h>
+#include <X11/Xlib.h>
+
+typedef int keycode_t;
+typedef unsigned int scancode_t;
+typedef int symbol;
+typedef int group_t;
+typedef unsigned int boolctrls;
+
+#define KEYCONSUMED 1
+#define KEYNOTCONSUMED 0
+
+#define RedirectIntoRange 1
+#define ClampIntoRange 2
+#define WrapIntoRange 0
+
+typedef enum mergemode
+ {
+ augment,
+ override,
+ replace,
+ alternate,
+ defaultmm
+ } mergemode;
+
+extern mergemode merge_mode;
+
+typedef unsigned long KeySym;
+
+/* Real modifiers. */
+#define RMOD_SHIFT 1 << 0
+#define RMOD_LOCK 1 << 1
+#define RMOD_CTRL 1 << 2
+#define RMOD_MOD1 1 << 3
+#define RMOD_MOD2 1 << 4
+#define RMOD_MOD3 1 << 5
+#define RMOD_MOD4 1 << 6
+#define RMOD_MOD5 1 << 7
+
+/* If set the key has action(s). */
+#define KEYHASACTION (1<<4)
+/* Normally the keytype will be calculated, but some keys like SYSRQ
+ can't be calculated. For these keys the name for the keytypes will
+ be given for every group fro whch the bit is set. */
+#define KEYHASTYPES 0xf
+#define KEYHASBEHAVIOUR (1<<5)
+/* Will the key be repeated when held down, or not. */
+#define KEYREPEAT (1<<6)
+#define KEYNOREPEAT (1<<7)
+
+/* The complete set of modifiers. */
+typedef struct modmap
+{
+ /* Real modifiers. */
+ int rmods;
+ /* Virtual modifiers. */
+ int vmods;
+} modmap_t;
+
+/* Modifier counter. */
+typedef struct modcount
+{
+ int rmods[8];
+ int vmods[16];
+} modcount_t;
+
+/* Map modifiers to a shift level. */
+typedef struct typemap
+{
+ /* Shift level used when required modifiers match the active modifiers. */
+ int level;
+ modmap_t mods;
+ modmap_t preserve;
+ struct typemap *next;
+} typemap_t;
+
+/* The keypad symbol range. */
+#define KEYPAD_FIRST_KEY 0xFF80
+#define KEYPAD_LAST_KEY 0xFFB9
+#define KEYPAD_MASK 0xFF80
+
+/* Convert a keypad symbol to a ASCII symbol. */
+#define keypad_to_ascii(c) c = (c & (~KEYPAD_MASK))
+
+/* The default keytypes. These can be calculated. */
+#define KT_ONE_LEVEL 0
+#define KT_TWO_LEVEL 1
+#define KT_ALPHA 2
+#define KT_KEYPAD 3
+
+typedef struct keytype
+{
+ /* Mask that determines which modifiers should be checked. */
+ modmap_t modmask;
+ /* Amount of levels. */
+ int levels;
+ /* The required set of modifiers for one specific level. */
+ struct typemap *maps;
+
+ char *name;
+ struct keytype *hnext;
+ struct keytype **prevp;
+} keytype_t;
+
+extern struct keytype *keytypes;
+extern int keytype_count;
+
+/* All Actions as described in the protocol specification. */
+typedef enum actiontype
+ {
+ SA_NoAction,
+ SA_SetMods,
+ SA_LatchMods,
+ SA_LockMods,
+ SA_SetGroup,
+ SA_LatchGroup,
+ SA_LockGroup,
+ SA_MovePtr,
+ SA_PtrBtn,
+ SA_LockPtrBtn,
+ SA_SetPtrDflt,
+ SA_ISOLock,
+ SA_TerminateServer,
+ SA_SwitchScreen,
+ SA_SetControls,
+ SA_LockControls,
+ SA_ActionMessage,
+ SA_RedirectKey,
+ SA_DeviceBtn,
+ SA_LockDeviceBtn,
+ SA_DeviceValuator,
+ SA_ConsScroll
+ } actiontype_t;
+
+typedef struct xkb_action
+{
+ actiontype_t type;
+ int data[15];
+} xkb_action_t;
+
+#define useModMap 4
+#define clearLocks 1
+#define latchToLock 2
+#define noLock 1
+#define noUnlock 2
+#define groupAbsolute 4
+#define NoAcceleration 1
+#define MoveAbsoluteX 2
+#define MoveAbsoluteY 4
+/* XXX: This flag is documentated and I've implemented it. Weird
+ stuff. */
+#define useDfltBtn 0
+#define DfltBtnAbsolute 2
+#define AffectDfltBtn 1
+#define switchApp 1
+#define screenAbs 4
+#define lineAbs 2
+#define usePercentage 8
+
+/* Defines how symbols and rmods are interpreted. This is used to
+ bound an action to a key that doesn't have an action bound to it,
+ only a modifier or action describing symbol. */
+typedef struct xkb_interpret
+{
+ symbol symbol;
+ int rmods;
+ int match;
+ int vmod; /* XXX: Why does this field have a size of only 8 bits? */
+ int flags;
+ struct xkb_action action;
+ struct xkb_interpret *next;
+} xkb_interpret_t;
+
+extern xkb_interpret_t *interpretations;
+extern int interpret_count;
+
+/* These are the parameter names that are used by the actions that
+ control modifiers. (this is stored in the data field of
+ xkb_action)*/
+typedef struct action_setmods
+{
+ actiontype_t type;
+ /* The flags configure the behaviour of the action. */
+ int flags;
+ /* XXX: The real modifiers that can be controlled by this action. */
+ int modmask;
+ /* The modifiers that are will be set/unset by this action. */
+ modmap_t modmap;
+} action_setmods_t;
+
+typedef struct action_setgroup
+{
+ actiontype_t type;
+ int flags;
+ int group;
+} action_setgroup_t;
+
+typedef struct action_moveptr
+{
+ actiontype_t type;
+ int flags;
+ int x;
+ int y;
+} action_moveptr_t;
+
+typedef struct action_ptrbtn
+{
+ actiontype_t type;
+ int flags;
+ int count; /* Isn't used for LockPtrBtn. */
+ int button;
+} action_ptrbtn_t;
+
+typedef struct action_ptr_dflt
+{
+ actiontype_t type;
+ int flags;
+ int affect;
+ int value;
+} action_ptr_dflt_t;
+
+typedef struct action_switchscrn
+{
+ actiontype_t type;
+ int flags;
+ int screen;
+} action_switchscrn_t;
+
+typedef struct action_consscroll
+{
+ actiontype_t type;
+ int flags;
+ double screen;
+ int line;
+ int percent;
+} action_consscroll_t;
+
+typedef struct action_redirkey
+{
+ actiontype_t type;
+ int newkey;
+ int rmodsmask;
+ int rmods;
+ int vmodsmask;
+ int vmods;
+} action_redirkey_t;
+
+typedef struct action_setcontrols
+{
+ actiontype_t type;
+ int controls;
+} action_setcontrols_t;
+
+/* Every key can have 4 groups, this is the information stored per
+ group. */
+struct keygroup
+{
+ /* All symbols for every available shift level and group. */
+ symbol *symbols;
+ /* All actions for every available shift level and group. */
+ struct xkb_action **actions;
+ /* The keytype of this key. The keytype determines the available
+ shift levels and which modiers are used to set the shift level.
+ */
+ struct keytype *keytype;
+ /* Amount of symbols held in this group of this key. */
+ int width;
+ int actionwidth;
+};
+
+/* A single key scancode stored in memory. */
+typedef struct key
+{
+ /* The flags that can be set for this key (To change the behaviour
+ of this key). */
+ int flags;
+ /* Every key has a maximum of 4 groups. (XXX: According to Ivan
+ Pascal's documentation... I'm not really sure if that is true.) */
+ struct keygroup groups[4];
+ int numgroups;
+ struct modmap mods;
+} keyinf_t;
+
+extern struct key *keys;
+extern int min_keys;
+extern int max_keys;
+
+/* The current state of every key. */
+typedef struct keystate
+{
+ /* Key is pressed. */
+ unsigned short keypressed:1;
+ unsigned short prevstate:1;
+ /* The key was disabled for bouncekeys. */
+ unsigned short disabled:1;
+ /* Information about locked modifiers at the time of the keypress,
+ this information is required for unlocking when the key is released. */
+ modmap_t lmods;
+ /* The modifiers and group that were active at keypress, make them
+ active again on keyrelease so the action will be undone. */
+ modmap_t prevmods;
+ boolctrls bool;
+ group_t prevgroup;
+ group_t oldgroup;
+} keystate_t;
+
+extern struct keystate keystate[255];
+
+typedef struct keypress
+{
+ keycode_t keycode;
+ keycode_t prevkc;
+ unsigned short repeat:1; /* It this a real keypress?. */
+ unsigned short redir:1; /* This is not a real keypress. */
+ unsigned short rel; /* Key release. */
+} keypress_t;
+
+/* Flags for indicators. */
+#define IM_NoExplicit 0x80
+#define IM_NoAutomatic 0x40
+#define IM_LEDDrivesKB 0x20
+
+#define IM_UseCompat 0x10
+#define IM_UseEffective 0x08
+#define IM_UseLocked 0x04
+#define IM_UseLatched 0x02
+#define IM_UseBase 0x01
+
+
+typedef struct xkb_indicator
+{
+ int flags;
+ int which_mods;
+ modmap_t modmap;
+ int which_groups;
+ int groups;
+ unsigned int ctrls;
+} xkb_indicator_t;
+
+unsigned int KeySymToUcs4(int keysym);
+symbol compose_symbols (symbol symbol);
+error_t read_composefile (char *);
+struct keytype *keytype_find (char *name);
+
+void key_set_action (struct key *key, group_t group, int level,
+ xkb_action_t *action);
+
+
+/* Interfaces for xkbdata.c: */
+extern struct xkb_interpret default_interpretation;
+
+
+/* Assign the name KEYNAME to the keycode KEYCODE. */
+error_t keyname_add (char *keyname, int keycode);
+
+/* Find the numberic representation of the keycode with the name
+ KEYNAME. */
+int keyname_find (char *keyname);
+
+/* Search the keytype with the name NAME. */
+struct keytype *keytype_find (char *name);
+
+/* Remove the keytype KT. */
+void keytype_delete (struct keytype *kt);
+
+/* Create a new keytype with the name NAME. */
+error_t keytype_new (char *name, struct keytype **new_kt);
+
+/* Add a level (LEVEL) to modifiers (MODS) mapping to the current
+ keytype. */
+error_t keytype_mapadd (struct keytype *kt, modmap_t mods, int level);
+
+/* For the current keytype the modifiers PRESERVE should be preserved
+ when the modifiers MODS are pressed. */
+error_t keytype_preserve_add (struct keytype *kt, modmap_t mods,
+ modmap_t preserve);
+
+/* Add a new interpretation. */
+error_t interpret_new (xkb_interpret_t **new_interpret, symbol ks);
+
+/* Get the number assigned to the virtualmodifier with the name
+ VMODNAME. */
+int vmod_find (char *vmodname);
+
+/* Give the virtualmodifier VMODNAME a number and add it to the
+ hashtable. */
+error_t vmod_add (char *vmodname);
+
+/* Initialize the list for keysyms to realmodifiers mappings. */
+void ksrm_init ();
+
+/* Add keysym to realmodifier mapping. */
+error_t ksrm_add (symbol ks, int rmod);
+
+/* Apply the rkms (realmods to keysyms) table to all keysyms. */
+void ksrm_apply (void);
+
+/* Set the current rmod for the key with keyname KEYNAME. */
+/* XXX: It shouldn't be applied immediatly because the key can be
+ replaced. */
+void set_rmod_keycode (char *keyname, int rmod);
+
+/* Initialize XKB data structures. */
+error_t xkb_data_init (void);
+
+error_t xkb_input_key (int key);
+
+error_t xkb_init_repeat (int delay, int repeat);
+
+void xkb_input (keypress_t key);
+
+int debug_printf (const char *f, ...);
+
+error_t xkb_load_layout (char *xkbdir, char *xkbkeymapfile, char *xkbkeymap);
diff --git a/console-client/xkb/xkbdata.c b/console-client/xkb/xkbdata.c
new file mode 100644
index 00000000..767bf38a
--- /dev/null
+++ b/console-client/xkb/xkbdata.c
@@ -0,0 +1,464 @@
+/* xkbdata.c -- Manage XKB datastructures.
+
+ Copyright (C) 2003 Marco Gerards
+
+ Written by Marco Gerards <marco@student.han.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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. */
+
+/* Generate a key for the string S. XXX: The are many more effecient
+ algoritms, this one should be replaced by one of those. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <hurd/ihash.h>
+#include "xkb.h"
+
+static int
+name_hash (char *s)
+{
+ int i = 0;
+ while (*s)
+ i += *(s++);
+ return i;
+}
+
+
+/* A keyname with a keycode and realmodifier bound to it. */
+struct keyname
+{
+ int keycode;
+ int rmods;
+};
+
+static struct hurd_ihash kn_mapping;
+
+/* Initialize the keyname hashtable. */
+static void
+keyname_init ()
+{
+ hurd_ihash_init (&kn_mapping, HURD_IHASH_NO_LOCP);
+ debug_printf ("Kn_mapping init");
+ /* XXX: error. */
+}
+
+static inline int
+keyname_hash(char *keyname)
+{
+ char tmp[4] = { 0 };
+ strncpy(tmp, keyname, sizeof tmp);
+ return tmp[0] + (tmp[1] << 8) + (tmp[2] << 16) + (tmp[3] << 24);
+}
+
+/* Assign the name KEYNAME to the keycode KEYCODE. */
+error_t
+keyname_add (char *keyname, int keycode)
+{
+ struct keyname *kn;
+ int kn_int;
+
+ kn = malloc (sizeof (struct keyname));
+ if (!kn)
+ return ENOMEM;
+
+ /* XXX: 4 characters can be mapped into a int, it is safe to assume
+ this will not be changed. */
+ if (strlen (keyname) > 4)
+ {
+ debug_printf ("The keyname `%s' consist of more than 4 characters;"
+ " 4 characters is the maximum.\n", keyname);
+ /* XXX: Abort? */
+ return 0;
+ }
+
+ kn->keycode = keycode;
+ kn->rmods = 0;
+
+ kn_int = keyname_hash(keyname);
+ debug_printf ("add key %s(%d) hash: %d\n", keyname, keycode, kn_int);
+ hurd_ihash_add (&kn_mapping, kn_int, kn);
+
+ return 0;
+}
+
+/* Find the numberic representation of the keycode with the name
+ KEYNAME. */
+int
+keyname_find (char *keyname)
+{
+ struct keyname *kn;
+ int kn_int;
+
+ /* XXX: 4 characters can be mapped into a int, it is safe to assume
+ this will not be changed. */
+ if (strlen (keyname) > 4)
+ {
+ debug_printf ("The keyname `%s' consist of more than 4 characters;"
+ " 4 characters is the maximum.\n", keyname);
+ /* XXX: Abort? */
+ return 0;
+ }
+ kn_int = keyname_hash(keyname);
+
+ kn = hurd_ihash_find (&kn_mapping, kn_int);
+ if (kn)
+ return kn->keycode;
+/* int h = name_hash (keyname); */
+/* struct keyname *kn; */
+/* for (kn = knhash[KNHASH(h)]; kn; kn = kn->hnext) */
+/* { */
+/* if (strcmp (kn->keyname, keyname)) */
+/* continue; */
+
+/* return kn->keycode; */
+/* } */
+
+ /* XXX: Is 0 an invalid keycode? */
+ return 0;
+}
+
+
+/* Keytypes and keytype maps. */
+
+/* The dummy gets used when the original may not be overwritten. */
+static struct keytype dummy_keytype;
+
+#define KTHSZ 16
+#if ((KTHSZ&(KTHSZ-1)) == 0)
+#define KTHASH(ktttl) ((ktttl)&(KTHSZ-1))
+#else
+#define KTHASH(ktttl) (((unsigned)(kt))%KTHSZ)
+#endif
+
+/* All keytypes. */
+struct keytype *kthash[KTHSZ];
+
+/* Initialize the keytypes hashtable. */
+static void
+keytype_init ()
+{
+ int n;
+ for (n = 0; n < KTHSZ; n++)
+ kthash[n] = 0;
+}
+
+/* Search the keytype with the name NAME. */
+struct keytype *
+keytype_find (char *name)
+{
+ int nhash = name_hash (name);
+ struct keytype *kt;
+
+ for (kt = kthash[KTHASH(nhash)]; kt; kt = kt->hnext)
+ if (!strcmp (name, kt->name))
+ return kt;
+ return NULL;
+}
+
+/* Remove the keytype KT. */
+void
+keytype_delete (struct keytype *kt)
+{
+ struct typemap *map;
+
+
+ *kt->prevp = kt->hnext;
+ if (kt->hnext)
+ kt->hnext->prevp = kt->prevp;
+
+ map = kt->maps;
+ while (map)
+ {
+ struct typemap *nextmap = map->next;
+ free (map);
+ map = nextmap;
+ }
+
+}
+
+/* Create a new keytype with the name NAME. */
+error_t
+keytype_new (char *name, struct keytype **new_kt)
+{
+ struct keytype *kt;
+ struct keytype *ktlist;
+ int nhash;
+
+ nhash = name_hash (name);
+ debug_printf ("New: %s\n", name);
+
+ kt = keytype_find (name);
+
+ if (kt)
+ {
+ /* If the merge mode is augement don't replace it. */
+ if (merge_mode == augment)
+ {
+ *new_kt = &dummy_keytype;
+ return 0;
+ }
+ else /* This keytype should replace the old one, remove the old one. */
+ keytype_delete (kt);
+ }
+
+ ktlist = kthash[KTHASH(nhash)];
+ kt = calloc (1, sizeof (struct keytype));
+ if (kt == NULL)
+ return ENOMEM;
+
+ kt->hnext = ktlist;
+ kt->name = strdup (name);
+ kt->prevp = &kthash[KTHASH(nhash)];
+ kt->maps = NULL;
+ if (kthash[KTHASH(nhash)])
+ kthash[KTHASH(nhash)]->prevp = &(kt->hnext);
+ kthash[KTHASH(nhash)] = kt;
+
+ *new_kt = kt;
+ return 0;
+}
+
+/* Add a level (LEVEL) to modifiers (MODS) mapping to the current
+ keytype. */
+error_t
+keytype_mapadd (struct keytype *kt, modmap_t mods, int level)
+{
+ struct typemap *map;
+ modmap_t nulmap = {0, 0};
+
+ map = malloc (sizeof (struct typemap));
+ if (!map)
+ return ENOMEM;
+
+ map->level = level;
+ map->mods = mods;
+ map->preserve = nulmap;
+ /* By default modifiers shouldn't be preserved. */
+ map->next = kt->maps;
+
+ kt->maps = map;
+
+ return 0;
+}
+
+/* For the current keytype the modifiers PRESERVE should be preserved
+ when the modifiers MODS are pressed. */
+error_t
+keytype_preserve_add (struct keytype *kt, modmap_t mods, modmap_t preserve)
+{
+ error_t err;
+ struct typemap *map;
+
+ map = kt->maps;
+ while (map)
+ {
+ if (mods.rmods == map->mods.rmods && mods.vmods == map->mods.vmods)
+ {
+ map->preserve = preserve;
+ return 0;
+ }
+ map = map->next;
+ }
+
+ /* No map has been found, add the default map. */
+ err = keytype_mapadd (kt, mods, 0);
+ if (err)
+ return err;
+
+ keytype_preserve_add (kt, mods, preserve);
+
+ return 0;
+}
+
+
+/* Interpretations. */
+
+struct xkb_interpret *last_interp;
+struct xkb_interpret default_interpretation;
+
+
+/* Add a new interpretation. */
+error_t
+interpret_new (xkb_interpret_t **new_interpret, symbol ks)
+{
+ struct xkb_interpret *new_interp;
+
+ new_interp = malloc (sizeof (struct xkb_interpret));
+ if (!new_interp)
+ return ENOMEM;
+
+ memcpy (new_interp, &default_interpretation, sizeof (struct xkb_interpret));
+ new_interp->symbol = ks;
+
+ if (ks)
+ {
+ new_interp->next = interpretations;
+ interpretations = new_interp;
+
+ if (!last_interp)
+ last_interp = new_interp;
+ }
+ else
+ {
+ if (last_interp)
+ last_interp->next = new_interp;
+
+ last_interp = new_interp;
+
+ if (!interpretations)
+ interpretations = new_interp;
+ }
+
+ *new_interpret = new_interp;
+
+ return 0;
+}
+
+
+/* XXX: Dead code!? */
+/* Virtual modifiers name to number mapping. */
+/* Last number assigned to a virtual modifier. */
+static int lastvmod = 0;
+
+/* One virtual modifiername -> vmod number mapping. */
+struct vmodname
+{
+ char *name;
+ struct vmodname *next;
+};
+
+/* A list of virtualmodifier names and its numberic representation. */
+static struct vmodname *vmodnamel;
+
+/* Get the number assigned to the virtualmodifier with the name
+ VMODNAME. */
+int
+vmod_find (char *vmodname)
+{
+ int i = 0;
+ struct vmodname *vmn = vmodnamel;
+
+ while (vmn)
+ {
+ if (!strcmp (vmn->name, vmodname))
+ return (lastvmod - i);
+ vmn = vmn->next;
+ i++;
+ }
+
+ return 0;
+}
+
+/* Give the virtualmodifier VMODNAME a number and add it to the
+ hashtable. */
+error_t
+vmod_add (char *vmodname)
+{
+ struct vmodname *vmn;
+
+ if (vmod_find (vmodname))
+ return 0;
+
+ vmn = malloc (sizeof (struct vmodname));
+ if (vmn == NULL)
+ return ENOMEM;
+
+ vmn->name = vmodname;
+ vmn->next = vmodnamel;
+ vmodnamel = vmn;
+
+ lastvmod++;
+ if (lastvmod > 16)
+ debug_printf("warning: only sixteen virtual modifiers are supported, %s will not be functional.\n", vmodname);
+
+ return 0;
+}
+
+
+/* XXX: Use this, no pointers. */
+struct ksrm
+{
+ symbol ks;
+
+ int rmods;
+};
+static struct hurd_ihash ksrm_mapping;
+
+/* Initialize the list for keysyms to realmodifiers mappings. */
+void
+ksrm_init ()
+{
+ hurd_ihash_init (&ksrm_mapping, HURD_IHASH_NO_LOCP);
+ debug_printf ("KSRM MAP IHASH CREATED \n");
+}
+
+/* Add keysym to realmodifier mapping. */
+error_t
+ksrm_add (symbol ks, int rmod)
+{
+ hurd_ihash_add (&ksrm_mapping, ks, (void *) rmod);
+
+ return 0;
+}
+
+/* Apply the rkms (realmods to keysyms) table to all keysyms. */
+void
+ksrm_apply (void)
+{
+ keycode_t kc;
+ for (kc = 0; kc < max_keys; kc++)
+ {
+ int group;
+ for (group = 0; group < 4; group++)
+ {
+ int cursym;
+ for (cursym = 0; cursym < keys[kc].groups[group].width; cursym++)
+ {
+ symbol ks = keys[kc].groups[group].symbols[cursym];
+ int rmods = (int) hurd_ihash_find (&ksrm_mapping, ks);
+
+ if (rmods)
+ {
+ keys[kc].mods.rmods = rmods;
+ }
+ }
+ }
+ }
+}
+
+
+/* void */
+/* indicator_new (xkb_indicator_t **, */
+
+
+/* Keycode to realmodifier mapping. */
+
+/* Set the current rmod for the key with keyname KEYNAME. */
+/* XXX: It shouldn't be applied immediatly because the key can be
+ replaced. */
+void
+set_rmod_keycode (char *keyname, int rmod)
+{
+ keycode_t kc = keyname_find (keyname);
+ keys[kc].mods.rmods = rmod;
+ debug_printf ("%s (kc %d) rmod: %d\n", keyname, kc, rmod);
+}
+
+/* Initialize XKB data structures. */
+error_t
+xkb_data_init (void)
+{
+ keyname_init ();
+ keytype_init ();
+ ksrm_init ();
+
+ return 0;
+}
diff --git a/console-client/xkb/xkbtimer.c b/console-client/xkb/xkbtimer.c
new file mode 100644
index 00000000..7621af72
--- /dev/null
+++ b/console-client/xkb/xkbtimer.c
@@ -0,0 +1,231 @@
+/* xkbtimer.c -- Manage XKB timers.
+
+ Copyright (C) 2003, 2004 Marco Gerards
+
+ Written by Marco Gerards <marco@student.han.nl>
+
+ This program 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 of the License, or
+ (at your option) any later version.
+
+ This program 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. */
+
+/* XKB requires a timer for key repeat and accessibility. Carefully
+ stack all compatibility features. */
+
+#include <mach.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "xkb.h"
+#include <timer.h>
+
+/* For key repeat. */
+static int key_delay = 0;
+static int key_repeat = 0;
+
+/* SlowKeys. */
+static int slowkeys_delay = 50;
+static int slowkeys_active = 0;
+
+/* BounceKeys. */
+static int bouncekeys_delay = 100;
+static int bouncekeys_active = 0;
+
+/* The current status of the timer. */
+enum timer_status
+ {
+ timer_stopped,
+ timer_slowkeys,
+ timer_repeat_delay,
+ timer_repeating
+ };
+
+/* Timer used to time key controls. */
+static struct per_key_timer
+{
+ /* Used for slowkeys and repeat. */
+ struct timer_list enable_timer;
+
+ /* Status of the enable timer. */
+ enum timer_status enable_status;
+
+ /* Used for bouncekeys. */
+ struct timer_list disable_timer;
+} per_key_timers[255];
+
+/* The last pressed key. Only this key may generate keyrepeat events. */
+static int lastkey = 0;
+
+error_t
+xkb_handle_key (keycode_t kc)
+{
+ static keycode_t prevkc = 0;
+ keypress_t key;
+
+ key.keycode = kc & 127;
+ key.prevkc = prevkc;
+ key.repeat = (prevkc == kc);
+ key.redir = 0;
+ key.rel = kc & 128;
+ keystate[key.keycode & 127].keypressed = key.rel ? 0 : 1;
+ debug_printf ("PRESSED: %d\n", !(key.rel));
+ xkb_input (key);
+ prevkc = key.keycode;
+ return 0;
+}
+
+error_t
+xkb_init_repeat (int delay, int repeat)
+{
+ error_t err;
+ err = timer_init ();
+ if (err)
+ return err;
+
+ key_delay = delay;
+ key_repeat = repeat;
+
+ return 0;
+}
+
+static int
+key_enable (void *handle)
+{
+ int key = (int) handle;
+
+ /* Enable the key. */
+ keystate[key].disabled = 0;
+
+ return 0;
+}
+
+/* Called by key timer. The global variable timer_status determines
+ the current control. */
+static int
+key_timing (void *handle)
+{
+ int current_key = (int) handle;
+
+ xkb_handle_key (current_key);
+
+ /* Another key was pressed after this key, stop repeating. */
+ if (lastkey != current_key)
+ {
+ per_key_timers[current_key].enable_status = timer_stopped;
+ return 0;
+ }
+
+ switch (per_key_timers[current_key].enable_status)
+ {
+ case timer_stopped:
+ assert ("Stopped timer triggered timer event\n");
+ break;
+ case timer_slowkeys:
+ per_key_timers[current_key].enable_timer.expires
+ = fetch_jiffies () + key_delay;
+ lastkey = current_key;
+
+ if (keys[current_key].flags & KEYNOREPEAT)
+ {
+ per_key_timers[current_key].enable_status = timer_stopped;
+ /* Stop the timer. */
+ return 0;
+ }
+ else
+ {
+ per_key_timers[current_key].enable_status = timer_repeat_delay;
+ }
+ break;
+ case timer_repeat_delay:
+ per_key_timers[current_key].enable_status = timer_repeating;
+ /* Fall through. */
+ case timer_repeating:
+ per_key_timers[current_key].enable_timer.expires
+ = fetch_jiffies () + key_repeat;
+ break;
+ }
+ return 1;
+}
+
+error_t
+xkb_input_key (int key)
+{
+ int pressed = !(key & 128);
+ int keyc = key & 127;
+
+ debug_printf ("KEYIN: %d\n", key);
+
+ /* Filter out any double or disabled keys. */
+ if (key == lastkey || keystate[keyc].disabled)
+ return 0;
+
+ /* Always handle keyrelease events. */
+ if (!pressed)
+ {
+ /* Stop the timer for this released key. */
+ if (per_key_timers[keyc].enable_status != timer_stopped)
+ {
+ timer_remove (&per_key_timers[keyc].enable_timer);
+ per_key_timers[keyc].enable_status = timer_stopped;
+ }
+
+ /* No more last key; it was released. */
+ if (keyc == lastkey)
+ lastkey = 0;
+
+ /* Make sure the key was pressed before releasing it, it might
+ not have been accepted. */
+ if (keystate[key & 127].keypressed)
+ xkb_handle_key (key);
+
+ /* If bouncekeys is active, disable the key. */
+ if (bouncekeys_active)
+ {
+ keystate[keyc].disabled = 1;
+
+ /* Setup a timer to enable the key. */
+ timer_clear (&per_key_timers[keyc].disable_timer);
+ per_key_timers[keyc].disable_timer.fnc = key_enable;
+ per_key_timers[keyc].disable_timer.fnc_data = (void *) keyc;
+ per_key_timers[keyc].disable_timer.expires
+ = fetch_jiffies () + bouncekeys_delay;
+ timer_add (&per_key_timers[keyc].disable_timer);
+ }
+
+ return 0;
+ }
+
+ /* Setup the timer for slowkeys. */
+ timer_clear (&per_key_timers[keyc].enable_timer);
+ lastkey = keyc;
+ per_key_timers[keyc].enable_timer.fnc = key_timing;
+ per_key_timers[keyc].enable_timer.fnc_data = (void *) keyc;
+
+ if (slowkeys_active)
+ {
+ per_key_timers[keyc].enable_status = timer_slowkeys;
+ per_key_timers[keyc].enable_timer.expires
+ = fetch_jiffies () + slowkeys_delay;
+ }
+ else
+ {
+ /* Immediatly report the keypress. */
+ xkb_handle_key (keyc);
+
+ /* Check if this repeat is allowed for this keycode. */
+ if (keys[keyc].flags & KEYNOREPEAT)
+ return 0; /* Nope. */
+
+ per_key_timers[keyc].enable_status = timer_repeat_delay;
+ per_key_timers[keyc].enable_timer.expires
+ = fetch_jiffies () + key_delay;
+ }
+ timer_add (&per_key_timers[keyc].enable_timer);
+
+ return 0;
+}