| git.druid.rocks | index | militantprogrammer | astral_canvas | src/ | input/ | input.c |
src/input/input.c
#include "input/input.h"
#include <linux/input-event-codes.h>
#include <stdlib.h>
#include <string.h>
#include <xkbcommon/xkbcommon-keysyms.h>
int inputXkbInit(InputXkb *input)
{
memset(input, 0, sizeof(*input));
input->context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!input->context)
return -1;
const char *locale = getenv("LC_ALL");
if (!locale || !locale[0])
locale = getenv("LC_CTYPE");
if (!locale || !locale[0])
locale = getenv("LANG");
if (!locale || !locale[0])
locale = "C";
input->composeTable = xkb_compose_table_new_from_locale(input->context, locale,
XKB_COMPOSE_COMPILE_NO_FLAGS);
if (input->composeTable) {
input->compose = xkb_compose_state_new(input->composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
if (!input->compose) {
xkb_compose_table_unref(input->composeTable);
input->composeTable = NULL;
}
}
return 0;
}
void inputXkbFinish(InputXkb *input)
{
if (!input)
return;
xkb_compose_state_unref(input->compose);
xkb_compose_table_unref(input->composeTable);
xkb_state_unref(input->state);
xkb_keymap_unref(input->keymap);
xkb_context_unref(input->context);
memset(input, 0, sizeof(*input));
}
void inputXkbSetKeymap(InputXkb *input, struct xkb_keymap *keymap, struct xkb_state *state)
{
xkb_state_unref(input->state);
xkb_keymap_unref(input->keymap);
input->keymap = keymap;
input->state = state;
if (input->compose)
xkb_compose_state_reset(input->compose);
}
static int modifierActive(const InputXkb *input, const char *name)
{
if (!input->state)
return 0;
return xkb_state_mod_name_is_active(input->state, name, XKB_STATE_MODS_EFFECTIVE) > 0;
}
uint32_t inputModifiers(const InputXkb *input)
{
uint32_t modifiers = 0;
if (modifierActive(input, XKB_MOD_NAME_SHIFT))
modifiers |= MOD_SHIFT;
if (modifierActive(input, XKB_MOD_NAME_CAPS))
modifiers |= MOD_CAPS;
if (modifierActive(input, XKB_MOD_NAME_CTRL))
modifiers |= MOD_CTRL;
if (modifierActive(input, "Alt") || modifierActive(input, XKB_MOD_NAME_ALT))
modifiers |= MOD_ALT;
if (modifierActive(input, "NumLock") || modifierActive(input, XKB_MOD_NAME_NUM))
modifiers |= MOD_NUM;
if (modifierActive(input, "Super") || modifierActive(input, XKB_MOD_NAME_LOGO))
modifiers |= MOD_SUPER;
return modifiers;
}
void input_fill_key(const InputXkb *input, KeyEvent *event, xkb_keycode_t keyCode,
bool pressed, bool repeat)
{
memset(event, 0, sizeof(*event));
event->keyCode = keyCode;
event->pressed = pressed;
event->repeat = repeat;
event->modifiers = inputModifiers(input);
if (!input->state)
return;
xkb_keysym_t keysym = xkb_state_key_get_one_sym(input->state, keyCode);
if (pressed && input->compose) {
if (!repeat)
xkb_compose_state_feed(input->compose, keysym);
enum xkb_compose_status status = xkb_compose_state_get_status(input->compose);
if (status == XKB_COMPOSE_COMPOSED) {
keysym = xkb_compose_state_get_one_sym(input->compose);
xkb_compose_state_get_utf8(input->compose, event->utf8, sizeof(event->utf8));
xkb_compose_state_reset(input->compose);
} else if (status == XKB_COMPOSE_COMPOSING) {
keysym = XKB_KEY_NoSymbol;
event->utf8[0] = 0;
} else if (status == XKB_COMPOSE_CANCELLED) {
xkb_compose_state_reset(input->compose);
} else {
xkb_state_key_get_utf8(input->state, keyCode, event->utf8, sizeof(event->utf8));
}
} else if (pressed) {
xkb_state_key_get_utf8(input->state, keyCode, event->utf8, sizeof(event->utf8));
}
event->keysym = keysym;
event->utf32 = xkb_keysym_to_utf32(keysym);
xkb_keysym_get_name(keysym, event->name, sizeof(event->name));
}
uint32_t linuxButtonToButton(uint32_t linuxCode)
{
switch (linuxCode) {
case BTN_LEFT: return BUTTON_LEFT;
case BTN_MIDDLE: return BUTTON_MIDDLE;
case BTN_RIGHT: return BUTTON_RIGHT;
case BTN_SIDE: return BUTTON_BACK;
case BTN_EXTRA: return BUTTON_FORWARD;
default: return 0;
}
}