#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <X11/keysym.h>
#include <X11/XF86keysym.h>
#include <X11/extensions/XIproto.h>
#include <linux/input.h>
#include <misc.h>
#include <xf86.h>
#include <xf86str.h>
#include <xf86_OSproc.h>
#include <xf86_ansic.h>
#include <xf86_libc.h>
#include <xf86Xinput.h>
#include <exevents.h>
#include <mipointer.h>
#include <xf86Module.h>
#include <X11/extensions/XKB.h>
#include <X11/extensions/XKBstr.h>
#include <X11/extensions/XKBsrv.h>
#include "evdev.h"
#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x) ((x)%BITS_PER_LONG)
#define LONG(x) ((x)/BITS_PER_LONG)
#define TestBit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
#define MIN_KEYCODE 8
#define GLYPHS_PER_KEY 2
#define AltMask Mod1Mask
#define NumLockMask Mod2Mask
#define AltLangMask Mod3Mask
#define KanaMask Mod4Mask
#define ScrollLockMask Mod5Mask
#define CAPSFLAG 1
#define NUMFLAG 2
#define SCROLLFLAG 4
#define MODEFLAG 8
#define COMPOSEFLAG 16
static KeySym map[] = {
NoSymbol, NoSymbol,
XK_Escape, NoSymbol,
XK_1, XK_exclam,
XK_2, XK_at,
XK_3, XK_numbersign,
XK_4, XK_dollar,
XK_5, XK_percent,
XK_6, XK_asciicircum,
XK_7, XK_ampersand,
XK_8, XK_asterisk,
XK_9, XK_parenleft,
XK_0, XK_parenright,
XK_minus, XK_underscore,
XK_equal, XK_plus,
XK_BackSpace, NoSymbol,
XK_Tab, XK_ISO_Left_Tab,
XK_Q, NoSymbol,
XK_W, NoSymbol,
XK_E, NoSymbol,
XK_R, NoSymbol,
XK_T, NoSymbol,
XK_Y, NoSymbol,
XK_U, NoSymbol,
XK_I, NoSymbol,
XK_O, NoSymbol,
XK_P, NoSymbol,
XK_bracketleft, XK_braceleft,
XK_bracketright,XK_braceright,
XK_Return, NoSymbol,
XK_Control_L, NoSymbol,
XK_A, NoSymbol,
XK_S, NoSymbol,
XK_D, NoSymbol,
XK_F, NoSymbol,
XK_G, NoSymbol,
XK_H, NoSymbol,
XK_J, NoSymbol,
XK_K, NoSymbol,
XK_L, NoSymbol,
XK_semicolon, XK_colon,
XK_quoteright, XK_quotedbl,
XK_quoteleft, XK_asciitilde,
XK_Shift_L, NoSymbol,
XK_backslash, XK_bar,
XK_Z, NoSymbol,
XK_X, NoSymbol,
XK_C, NoSymbol,
XK_V, NoSymbol,
XK_B, NoSymbol,
XK_N, NoSymbol,
XK_M, NoSymbol,
XK_comma, XK_less,
XK_period, XK_greater,
XK_slash, XK_question,
XK_Shift_R, NoSymbol,
XK_KP_Multiply, NoSymbol,
XK_Alt_L, XK_Meta_L,
XK_space, NoSymbol,
XK_Caps_Lock, NoSymbol,
XK_F1, NoSymbol,
XK_F2, NoSymbol,
XK_F3, NoSymbol,
XK_F4, NoSymbol,
XK_F5, NoSymbol,
XK_F6, NoSymbol,
XK_F7, NoSymbol,
XK_F8, NoSymbol,
XK_F9, NoSymbol,
XK_F10, NoSymbol,
XK_Num_Lock, NoSymbol,
XK_Scroll_Lock, NoSymbol,
XK_KP_Home, XK_KP_7,
XK_KP_Up, XK_KP_8,
XK_KP_Prior, XK_KP_9,
XK_KP_Subtract, NoSymbol,
XK_KP_Left, XK_KP_4,
XK_KP_Begin, XK_KP_5,
XK_KP_Right, XK_KP_6,
XK_KP_Add, NoSymbol,
XK_KP_End, XK_KP_1,
XK_KP_Down, XK_KP_2,
XK_KP_Next, XK_KP_3,
XK_KP_Insert, XK_KP_0,
XK_KP_Delete, XK_KP_Decimal,
NoSymbol, NoSymbol,
XK_F13, NoSymbol,
XK_less, XK_greater,
XK_F11, NoSymbol,
XK_F12, NoSymbol,
XK_F14, NoSymbol,
XK_F15, NoSymbol,
XK_F16, NoSymbol,
XK_F17, NoSymbol,
XK_F18, NoSymbol,
XK_F19, NoSymbol,
XK_F20, NoSymbol,
XK_KP_Enter, NoSymbol,
XK_Control_R, NoSymbol,
XK_KP_Divide, NoSymbol,
XK_Print, XK_Sys_Req,
XK_Alt_R, XK_Meta_R,
NoSymbol, NoSymbol,
XK_Home, NoSymbol,
XK_Up, NoSymbol,
XK_Prior, NoSymbol,
XK_Left, NoSymbol,
XK_Right, NoSymbol,
XK_End, NoSymbol,
XK_Down, NoSymbol,
XK_Next, NoSymbol,
XK_Insert, NoSymbol,
XK_Delete, NoSymbol,
NoSymbol, NoSymbol,
NoSymbol, NoSymbol,
NoSymbol, NoSymbol,
NoSymbol, NoSymbol,
NoSymbol, NoSymbol,
NoSymbol, NoSymbol,
XK_KP_Equal, NoSymbol,
NoSymbol, NoSymbol,
NoSymbol, NoSymbol,
XK_F21, NoSymbol,
XK_F22, NoSymbol,
XK_F23, NoSymbol,
XK_F24, NoSymbol,
XK_KP_Separator, NoSymbol,
XK_Meta_L, NoSymbol,
XK_Meta_R, NoSymbol,
XK_Multi_key, NoSymbol,
};
static void
EvdevKbdBell (int percent, DeviceIntPtr device, pointer ctrl, int unused)
{
xf86SoundKbdBell(percent, ((KeybdCtrl*) ctrl)->bell_pitch,
((KeybdCtrl*) ctrl)->bell_duration);
}
static void
EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
{
static struct { int xbit, code; } bits[] = {
{ CAPSFLAG, LED_CAPSL },
{ NUMFLAG, LED_NUML },
{ SCROLLFLAG, LED_SCROLLL },
{ MODEFLAG, LED_KANA },
{ COMPOSEFLAG, LED_COMPOSE }
};
InputInfoPtr pInfo;
struct input_event ev[ArrayLength(bits)];
int i;
pInfo = device->public.devicePrivate;
for (i = 0; i < ArrayLength(bits); i++) {
ev[i].type = EV_LED;
ev[i].code = bits[i].code;
ev[i].value = (ctrl->leds & bits[i].xbit) > 0;
write(pInfo->fd, ev, sizeof ev);
}
}
int
EvdevKeyInit (DeviceIntPtr device)
{
InputInfoPtr pInfo = device->public.devicePrivate;
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
KeySymsRec keySyms;
CARD8 modMap[MAP_LENGTH];
KeySym sym;
int i, j;
static struct { KeySym keysym; CARD8 mask; } modifiers[] = {
{ XK_Shift_L, ShiftMask },
{ XK_Shift_R, ShiftMask },
{ XK_Control_L, ControlMask },
{ XK_Control_R, ControlMask },
{ XK_Caps_Lock, LockMask },
{ XK_Alt_L, AltMask },
{ XK_Alt_R, AltMask },
{ XK_Num_Lock, NumLockMask },
{ XK_Scroll_Lock, ScrollLockMask },
{ XK_Mode_switch, AltLangMask }
};
pInfo = device->public.devicePrivate;
memset(modMap, 0, sizeof modMap);
for (i = 0; i < ArrayLength(map) / GLYPHS_PER_KEY; i++) {
sym = map[i * GLYPHS_PER_KEY];
for (j = 0; j < ArrayLength(modifiers); j++) {
if (modifiers[j].keysym == sym)
modMap[i + MIN_KEYCODE] = modifiers[j].mask;
}
}
keySyms.map = map;
keySyms.mapWidth = GLYPHS_PER_KEY;
keySyms.minKeyCode = MIN_KEYCODE;
keySyms.maxKeyCode = MIN_KEYCODE + ArrayLength(map) / GLYPHS_PER_KEY - 1;
XkbSetRulesDflts (state->key->xkb_rules, state->key->xkb_model,
state->key->xkb_layout, state->key->xkb_variant,
state->key->xkb_options);
XkbInitKeyboardDeviceStruct (device, &state->key->xkbnames, &keySyms, modMap,
EvdevKbdBell, EvdevKbdCtrl);
return Success;
}
static void
SetXkbOption(InputInfoPtr pInfo, char *name, char *value, char **option)
{
char *s;
if ((s = xf86SetStrOption(pInfo->options, name, value))) {
if (!s[0]) {
xfree(s);
*option = NULL;
} else {
*option = s;
}
}
}
int
EvdevKeyNew (InputInfoPtr pInfo)
{
evdevDevicePtr pEvdev = pInfo->private;
evdevStatePtr state = &pEvdev->state;
int i, keys = 0;
for (i = 0; i <= KEY_UNKNOWN; i++)
if (TestBit (i, pEvdev->bits.key)) {
keys = 1;
break;
}
if (!keys)
for (i = KEY_OK; i <= KEY_MAX; i++)
if (TestBit (i, pEvdev->bits.key)) {
keys = 1;
break;
}
if (!keys)
return !Success;
state->key = Xcalloc (sizeof (evdevKeyRec));
pInfo->type_name = XI_KEYBOARD;
pInfo->flags |= XI86_KEYBOARD_CAPABLE | XI86_CONFIGURED;
SetXkbOption (pInfo, "XkbRules", __XKBDEFRULES__, &state->key->xkb_rules);
SetXkbOption (pInfo, "XkbModel", "evdev", &state->key->xkb_model);
SetXkbOption (pInfo, "XkbLayout", "us", &state->key->xkb_layout);
SetXkbOption (pInfo, "XkbVariant", NULL, &state->key->xkb_variant);
SetXkbOption (pInfo, "XkbOptions", NULL, &state->key->xkb_options);
SetXkbOption (pInfo, "XkbKeycodes", NULL, &state->key->xkbnames.keycodes);
SetXkbOption (pInfo, "XkbTypes", NULL, &state->key->xkbnames.types);
SetXkbOption (pInfo, "XkbCompat", NULL, &state->key->xkbnames.compat);
SetXkbOption (pInfo, "XkbSymbols", NULL, &state->key->xkbnames.symbols);
SetXkbOption (pInfo, "XkbGeometry", NULL, &state->key->xkbnames.geometry);
return Success;
}
int
EvdevKeyOn (DeviceIntPtr device)
{
return Success;
}
int
EvdevKeyOff (DeviceIntPtr device)
{
unsigned int i;
KeyClassRec *keyc = device->key;
KeySym *map = keyc->curKeySyms.map;
for (i = keyc->curKeySyms.minKeyCode, map = keyc->curKeySyms.map;
i < keyc->curKeySyms.maxKeyCode;
i++, map += keyc->curKeySyms.mapWidth)
if ((keyc->down[i >> 3] & (1 << (i & 7))))
{
switch (*map) {
case XK_Caps_Lock:
case XK_Shift_Lock:
case XK_Num_Lock:
case XK_Scroll_Lock:
case XK_Kana_Lock:
break;
default:
xf86PostKeyboardEvent(device, i, 0);
}
}
return Success;
}
void
EvdevKeyProcess (InputInfoPtr pInfo, struct input_event *ev)
{
int keycode = ev->code + MIN_KEYCODE;
if (ev->value == 2) {
DeviceIntPtr device = pInfo->dev;
KeyClassRec *keyc = device->key;
KbdFeedbackClassRec *kbdfeed = device->kbdfeed;
int num = keycode >> 3;
int bit = 1 << (keycode & 7);
if (keyc->modifierMap[keycode] ||
!(kbdfeed->ctrl.autoRepeats[num] & bit))
return;
}
xf86PostKeyboardEvent(pInfo->dev, keycode, ev->value);
}