diff options
Diffstat (limited to 'console-client/xkb/xkb.c')
-rw-r--r-- | console-client/xkb/xkb.c | 1488 |
1 files changed, 314 insertions, 1174 deletions
diff --git a/console-client/xkb/xkb.c b/console-client/xkb/xkb.c index f0c36a64..31253f5c 100644 --- a/console-client/xkb/xkb.c +++ b/console-client/xkb/xkb.c @@ -26,7 +26,6 @@ #include <errno.h> #include <ctype.h> #include <stdlib.h> -#include <iconv.h> #include <locale.h> #include <error.h> #include <device/device.h> @@ -34,73 +33,26 @@ #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> +#include <xkbcommon/xkbcommon-compose.h> +#include <assert.h> - -/* The converter. */ -extern iconv_t cd; +/* The xkbcommon kdb context */ +struct xkb_context *ctx; -/* All interpretations for compatibility. (Translation from keysymbol - to actions). */ -xkb_interpret_t *interpretations; +/* The loaded keymap (immutable) */ +struct xkb_keymap *keymap; -/* All keysymbols and how they are handled by XKB. */ -struct key *keys = NULL; -int min_keys; -int max_keys; +/* The keyboard state */ +struct xkb_state *state; -/* 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; +/* The compose context and table */ +struct xkb_compose_table *compose_table; +struct xkb_compose_state *compose_state; -/* 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 separate 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, ...) @@ -109,922 +61,19 @@ debug_printf (const char *f, ...) int ret = 0; va_start (ap, f); -#ifdef XKB_DEBUG +#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 subtracting 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) -{ - /* XXX this needs a closer look. */ - if (!key.rel) - { - //setcontrols (key, boolctrls, flags); - //if (!(flags & noLock)) - // lboolctrls |= boolctrls; - } - else - { - // clearcontrols (key, boolctrls, flags); - /* This unlock behaviour doesn't 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) +symtoctrlsym (xkb_keysym_t c) { - /* 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; + c = xkb_keysym_to_upper(c); - return 0; -} - -static symbol -symtoctrlsym (symbol c) -{ - c = toupper (c); - switch (c) { case 'A' ... 'Z': @@ -1056,263 +105,276 @@ symtoctrlsym (symbol c) break; } - return c; + return (int) 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 +execute_action(keycode_t keycode) { - 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) + xkb_keysym_t keysym = xkb_state_key_get_one_sym (state, keycode); + /* if CTRL+ALT+Delete is pressed notify the caller */ + if (keysym == XKB_KEY_Delete && + xkb_state_mod_names_are_active (state, XKB_STATE_MODS_EFFECTIVE, XKB_STATE_MATCH_ALL, XKB_MOD_NAME_CTRL, + XKB_MOD_NAME_ALT) > 0) { - 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); - } + console_exit (); + return 1; } - if (actioncompl == KEYCONSUMED && !key.rel) + if (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE) > 0) { - /* 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; + if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) + { + console_switch (keysym - XKB_KEY_F1 + 1, 0); + return 1; + } + if (keysym == XKB_KEY_Right) + { + console_switch (0, 1); + return 1; + } + if (keysym == XKB_KEY_Left) + { + console_switch (0, -1); + return 1; + } + if (keysym == XKB_KEY_Up) + { + console_scrollback (CONS_SCROLL_DELTA_LINES, 1); + return 1; + } + if (keysym == XKB_KEY_Down) + { + console_scrollback (CONS_SCROLL_DELTA_LINES, -1); + return 1; + } + if (keysym == XKB_KEY_Page_Up) + { + console_scrollback (CONS_SCROLL_DELTA_SCREENS, -0.5); + return 1; + } + if (keysym == XKB_KEY_Page_Up) + { + console_scrollback (CONS_SCROLL_DELTA_SCREENS, 0.5); + return 1; + + } + if (keysym == XKB_KEY_Home) + { + console_scrollback (CONS_SCROLL_ABSOLUTE_PERCENTAGE, 100 - 0); + return 1; + } + if (keysym == XKB_KEY_End) + { + console_scrollback (CONS_SCROLL_ABSOLUTE_PERCENTAGE, 100 - 100); + return 1; + } } - 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; + if (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE) > 0) + { + if (keysym == XKB_KEY_Home) + { + console_scrollback (CONS_SCROLL_ABSOLUTE_PERCENTAGE, 100 - 25); + return 1; + } + if (keysym == XKB_KEY_End) + { + console_scrollback (CONS_SCROLL_ABSOLUTE_PERCENTAGE, 100 - 75); + return 1; + } + } + return 0; } -void -xkb_input (keypress_t key) +char* +get_special_char_interpretation(xkb_keysym_t input) { - 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: + case XKB_KEY_Up: case XKB_KEY_KP_Up: escseq = CONS_KEY_UP; break; - case XK_Down: case XK_KP_Down: + case XKB_KEY_Down: case XKB_KEY_KP_Down: escseq = CONS_KEY_DOWN; break; - case XK_Left: case XK_KP_Left: + case XKB_KEY_Left: case XKB_KEY_KP_Left: escseq = CONS_KEY_LEFT; break; - case XK_Right: case XK_KP_Right: + case XKB_KEY_Right: case XKB_KEY_KP_Right: escseq = CONS_KEY_RIGHT; break; - case XK_BackSpace: + case XKB_KEY_BackSpace: escseq = CONS_KEY_BACKSPACE; break; - case XK_F1: case XK_KP_F1: + case XKB_KEY_F1: case XKB_KEY_KP_F1: escseq = CONS_KEY_F1; break; - case XK_F2: case XK_KP_F2: + case XKB_KEY_F2: case XKB_KEY_KP_F2: escseq = CONS_KEY_F2; break; - case XK_F3: case XK_KP_F3: + case XKB_KEY_F3: case XKB_KEY_KP_F3: escseq = CONS_KEY_F3; break; - case XK_F4: case XK_KP_F4: + case XKB_KEY_F4: case XKB_KEY_KP_F4: escseq = CONS_KEY_F4; break; - case XK_F5: + case XKB_KEY_F5: escseq = CONS_KEY_F5; break; - case XK_F6: + case XKB_KEY_F6: escseq = CONS_KEY_F6; break; - case XK_F7: + case XKB_KEY_F7: escseq = CONS_KEY_F7; break; - case XK_F8: + case XKB_KEY_F8: escseq = CONS_KEY_F8; break; - case XK_F9: + case XKB_KEY_F9: escseq = CONS_KEY_F9; break; - case XK_F10: + case XKB_KEY_F10: escseq = CONS_KEY_F10; break; - case XK_F11: + case XKB_KEY_F11: escseq = CONS_KEY_F11; break; - case XK_F12: + case XKB_KEY_F12: escseq = CONS_KEY_F12; break; - case XK_F13: + case XKB_KEY_F13: escseq = CONS_KEY_F13; break; - case XK_F14: + case XKB_KEY_F14: escseq = CONS_KEY_F14; break; - case XK_F15: + case XKB_KEY_F15: escseq = CONS_KEY_F15; break; - case XK_F16: + case XKB_KEY_F16: escseq = CONS_KEY_F16; break; - case XK_F17: + case XKB_KEY_F17: escseq = CONS_KEY_F17; break; - case XK_F18: + case XKB_KEY_F18: escseq = CONS_KEY_F18; break; - case XK_F19: + case XKB_KEY_F19: escseq = CONS_KEY_F19; break; - case XK_F20: + case XKB_KEY_F20: escseq = CONS_KEY_F20; break; - case XK_Home: case XK_KP_Home: + case XKB_KEY_Home: case XKB_KEY_KP_Home: escseq = CONS_KEY_HOME; break; - case XK_Insert: case XK_KP_Insert: + case XKB_KEY_Insert: case XKB_KEY_KP_Insert: escseq = CONS_KEY_IC; break; - case XK_Delete: case XK_KP_Delete: + case XKB_KEY_Delete: case XKB_KEY_KP_Delete: escseq = CONS_KEY_DC; break; - case XK_End: case XK_KP_End: + case XKB_KEY_End: case XKB_KEY_KP_End: escseq = CONS_KEY_END; break; - case XK_Page_Up: case XK_KP_Page_Up: + case XKB_KEY_Prior: case XKB_KEY_KP_Prior: escseq = CONS_KEY_PPAGE; break; - case XK_Page_Down: case XK_KP_Page_Down: + case XKB_KEY_Next: case XKB_KEY_KP_Next: escseq = CONS_KEY_NPAGE; break; - case XK_KP_Begin: + case XKB_KEY_KP_Begin: escseq = CONS_KEY_B2; break; - case XK_ISO_Left_Tab: + case XKB_KEY_ISO_Left_Tab: escseq = CONS_KEY_BTAB; break; - case XK_Return: case XK_KP_Enter: + case XKB_KEY_Return: case XKB_KEY_KP_Enter: escseq = "\x0d"; break; - case XK_Tab: case XK_KP_Tab: + case XKB_KEY_Tab: case XKB_KEY_KP_Tab: escseq = "\t"; break; - case XK_Escape: + case XKB_KEY_Escape: escseq = "\e"; break; } + return escseq; +} + +void +xkb_compose_update (keypress_t key) +{ + if (!key.rel) + xkb_compose_state_feed(compose_state, key.keycode); +} + +void +xkb_compose_update_fini (void) +{ + enum xkb_compose_status status = xkb_compose_state_get_status(compose_state); + if (status == XKB_COMPOSE_CANCELLED || status == XKB_COMPOSE_COMPOSED) + xkb_compose_state_reset(compose_state); +} + +/* update the xkb state with the key event*/ +void +xkb_state_update_input_key (keypress_t key) +{ + enum xkb_key_direction direction = key.rel ? XKB_KEY_UP : XKB_KEY_DOWN; + xkb_state_update_key (state, key.keycode, direction); +} + +/* convert the keycode to a xkb keysym */ +static xkb_keysym_t +get_keysym_from_keycode (keycode_t keycode) +{ + xkb_keysym_t sym; + + sym = xkb_state_key_get_one_sym (state, keycode); + enum xkb_compose_status status = xkb_compose_state_get_status (compose_state); + if (status == XKB_COMPOSE_COMPOSING || status == XKB_COMPOSE_CANCELLED) + return XKB_KEYSYM_MAX + 1; + + if (status == XKB_COMPOSE_COMPOSED) { + sym = xkb_compose_state_get_one_sym(compose_state); + } + + return sym; +} + +/* Take an input event and apply his effect, sending the result to the console */ +void +process_keypress_event (keycode_t keycode) +{ + char buf[100]; + size_t size = 0; + xkb_keysym_t input; + + debug_printf ("input: %d\n", keycode); + + if (execute_action (keycode)) // execute action if any + return; + + input = get_keysym_from_keycode (keycode); // convert key to input + + debug_printf ("handle: %d\n", input); + if (input > XKB_KEYSYM_MAX) + return; + + /* If the real modifier MOD1 (AKA Alt) is set generate an ESC symbol. */ + if(xkb_state_mod_name_is_active (state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE) > 0) + buf[size++] = '\e'; + + buf[size] = '\0'; + + char *escseq = get_special_char_interpretation (input); if (escseq != NULL) { @@ -1323,60 +385,138 @@ xkb_input (keypress_t key) { char *buffer = &buf[size]; size_t left = sizeof (buf) - size; - char *inbuf = (char *) &input; - size_t inbufsize = sizeof (wchar_t); - size_t nr; + int 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 (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE) > 0) + { + input = symtoctrlsym (input); + buffer[0] = input; + buffer[1] = '\0'; + nr = 2; + size++; + } + else + { + nr = xkb_keysym_to_utf8 (input, buffer, left); + } + + if (nr == -1) + { + console_error (L"Input buffer overflow"); + size = 0; + } + else if (nr == 0) + size = 0; + else + size = nr - 1; // don’t include terminating byte } - if (size) + if (size > 0 && size <= sizeof(buf)) console_input (buf, size); - size = 0; } -error_t parse_xkbconfig (char *xkbdir, char *xkbkeymapfile, char *xkbkeymap); +void +process_input(keypress_t key) +{ + debug_printf ("keyboard event, keycode: %i, rel %i\n", key.keycode, key.rel); + + /* update the compose state to be able to know the modifiers when retrieving the key */ + xkb_compose_update (key); + + /* activate timers */ + if (key.rel || xkb_keymap_key_repeats (keymap, key.keycode)) + xkb_timer_notify_input (key); + /* send input for key pressed */ + if (!key.rel) + process_keypress_event (key.keycode); + /* clear compose if finished or canceled */ + xkb_compose_update_fini (); + /* update the keyboard state for the next input */ + xkb_state_update_input_key (key); +} + error_t -xkb_load_layout (char *xkbdir, char *xkbkeymapfile, char *xkbkeymap) +xkb_load_keymap (const char *rules, const char *model, const char *layout, const char *variant, const char* options) { - error_t err; + struct xkb_rule_names names = { + .rules = rules, + .model = model, + .layout = layout, + .variant = variant, + .options = options + }; + keymap = xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS); - err = parse_xkbconfig (xkbdir, xkbkeymapfile, xkbkeymap); - if (err) - return err; + if (!keymap) + return ENOMEM; - determine_keytypes (); - interpret_all (); return 0; } + +error_t +xkb_compose_init (const char *composefile) { + const char *locale; + FILE *cf; + locale = setlocale (LC_CTYPE, NULL); + + if (composefile != NULL) + { + cf = fopen (composefile, "r"); + if (cf == NULL) + return errno; + compose_table = xkb_compose_table_new_from_file (ctx, cf, locale, XKB_COMPOSE_FORMAT_TEXT_V1, XKB_COMPOSE_COMPILE_NO_FLAGS); + } + else + compose_table = xkb_compose_table_new_from_locale (ctx, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); + + if (!compose_table) + return ENOMEM; + + compose_state = xkb_compose_state_new (compose_table, XKB_COMPOSE_STATE_NO_FLAGS); + if (!compose_state) + return ENOMEM; + return 0; +} + +error_t +xkb_context_init (const char *rules, const char *model, const char *layout, const char *variant, const char* options, const char *composefile) +{ + /* initialize a xka context */ + ctx = xkb_context_new (XKB_CONTEXT_NO_FLAGS); + if (!ctx) + return ENOMEM; + + xkb_load_keymap (rules, model, layout, variant, options); + + /* load the state */ + state = xkb_state_new (keymap); + if (!state) + return ENOMEM; + + return xkb_compose_init (composefile); +} + +void +xkb_context_cleanup (void) +{ + /* compose cleanup */ + xkb_compose_state_unref (compose_state); + xkb_compose_table_unref (compose_table); + + /* state cleanup */ + xkb_state_unref (state); + + /* keymap cleanup */ + xkb_keymap_unref (keymap); + + /* context cleanup */ + xkb_context_unref (ctx); +} + +int +get_min_keycode (void) +{ + return xkb_keymap_min_keycode (keymap); +} |