Merge 84c3fe7ba6dd38a127bd7002f0a348f0193951fd into 0fc69a4ca5b359504bd017acecda7843a387aa78

This commit is contained in:
GitHub Merge Button 2012-01-18 10:01:10 -08:00
commit 1a241a61f6
10 changed files with 1468 additions and 893 deletions

View File

@ -28,11 +28,19 @@ libkmscon_core_la_SOURCES = \
src/eloop.c src/eloop.h \
src/vt.c src/vt.h \
src/input.c src/input.h \
src/input_xkb.c src/input_xkb.h \
external/imKStoUCS.c external\imKStoUCS.h \
src/vte.c src/vte.h \
src/terminal.c src/terminal.h
if USE_XKBCOMMON
libkmscon_core_la_SOURCES += \
src/kbd_xkb.c src/kbd.h \
external/imKStoUCS.c external\imKStoUCS.h
else
libkmscon_core_la_SOURCES += \
src/kbd_dumb.c src/kbd.h \
external/imKStoUCS.c external\imKStoUCS.h
endif
if USE_PANGO
libkmscon_core_la_SOURCES += \
src/font_pango.c src/font.h
@ -50,6 +58,7 @@ libkmscon_core_la_CPPFLAGS = \
$(PANGO_CFLAGS) \
$(UDEV_CFLAGS) \
$(FREETYPE2_CFLAGS) \
$(XPROTO_CFLAGS) \
$(XKBCOMMON_CFLAGS) \
$(GLIB_CFLAGS)
libkmscon_core_la_LIBADD = \
@ -60,6 +69,7 @@ libkmscon_core_la_LIBADD = \
$(PANGO_LIBS) \
$(UDEV_LIBS) \
$(FREETYPE2_LIBS) \
$(XPROTO_LIBS) \
$(XKBCOMMON_LIBS) \
$(GLIB_LIBS)
@ -92,11 +102,6 @@ test_terminal_SOURCES = tests/test_terminal.c
test_terminal_LDADD = libkmscon-core.la
test_input_SOURCES = tests/test_input.c
test_input_LDADD = \
libkmscon-core.la \
$(XKBCOMMON_LIBS)
test_input_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(XKBCOMMON_CFLAGS)
test_input_LDADD = libkmscon-core.la
EXTRA_DIST = README TODO COPYING

4
README
View File

@ -9,7 +9,9 @@ console.
- mesa: providing an OpenGL implementation (must be compiled with EGL, gbm
and GL libraries)
- udev: providing input device hotplug
- libxkbcommon: keyboard handling
- xproto (build time dependency): definition of key symbols
- libxkbcommon: keyboard handling (optional but strongly recommended)
Without libxkbcommon, basic US-ASCII input is provided.
- glib: only for Unicode handling
- One of:
- freetype2: drawing generic text

View File

@ -41,7 +41,12 @@ PKG_CHECK_MODULES([UDEV], [libudev])
AC_SUBST(UDEV_CFLAGS)
AC_SUBST(UDEV_LIBS)
PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon])
PKG_CHECK_MODULES([XPROTO], [xproto])
AC_SUBST(XPROTO_CFLAGS)
AC_SUBST(XPROTO_LIBS)
PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon],
[have_xkbcommon=yes], [have_xkbcommon=no])
AC_SUBST(XKBCOMMON_CFLAGS)
AC_SUBST(XKBCOMMON_LIBS)
@ -58,6 +63,18 @@ PKG_CHECK_MODULES([PANGO], [pango pangocairo cairo],
AC_SUBST(PANGO_CFLAGS)
AC_SUBST(PANGO_LIBS)
AC_MSG_CHECKING([whether to use xkbcommon keyboard backend])
AC_ARG_ENABLE([xkbcommon],
[AS_HELP_STRING([--disable-xkbcommon], [disable xkbcommon keyboard backend])])
if test x$enable_xkbcommon != xno ; then
if test x$enable_xkbcommon = xyes -a x$have_xkbcommon = xno ; then
AC_ERROR([--enable-xkbcommon given but library not found])
fi
enable_xkbcommon=$have_xkbcommon
fi
AM_CONDITIONAL([USE_XKBCOMMON], [test x$enable_xkbcommon = xyes])
AC_MSG_RESULT([$enable_xkbcommon])
AC_MSG_CHECKING([whether to use pango font backend])
AC_ARG_ENABLE([pango],
[AS_HELP_STRING([--enable-pango], [whether to use pango font backend])],

View File

@ -50,7 +50,7 @@
#include "eloop.h"
#include "input.h"
#include "input_xkb.h"
#include "kbd.h"
#include "log.h"
enum input_state {
@ -67,7 +67,7 @@ struct kmscon_input_device {
char *devnode;
struct kmscon_fd *fd;
struct xkb_state xkb_state;
struct kmscon_kbd *kbd;
};
struct kmscon_input {
@ -83,7 +83,7 @@ struct kmscon_input {
struct udev_monitor *monitor;
struct kmscon_fd *monitor_fd;
struct xkb_desc *xkb_desc;
struct kmscon_kbd_desc *desc;
};
static void remove_device(struct kmscon_input *input, const char *node);
@ -91,18 +91,20 @@ static void remove_device(struct kmscon_input *input, const char *node);
static void notify_key(struct kmscon_input_device *device,
uint16_t type, uint16_t code, int32_t value)
{
int ret;
struct kmscon_input_event ev;
bool has_event;
struct kmscon_input *input;
if (type != EV_KEY)
return;
input = device->input;
has_event = kmscon_xkb_process_evdev_key(input->xkb_desc,
&device->xkb_state, value, code, &ev);
ret = kmscon_kbd_process_key(device->kbd, value, code, &ev);
if (has_event)
if (ret && ret != -ENOKEY)
return;
if (ret != -ENOKEY && input->cb)
input->cb(input, &ev, input->data);
}
@ -155,9 +157,8 @@ int kmscon_input_device_wake_up(struct kmscon_input_device *device)
return -errno;
}
/* this rediscovers the xkb state if sth changed during sleep */
kmscon_xkb_reset_state(device->input->xkb_desc, &device->xkb_state,
device->rfd);
/* this rediscovers the keyboard state if sth changed during sleep */
kmscon_kbd_reset(device->kbd, device->rfd);
ret = kmscon_eloop_new_fd(device->input->eloop, &device->fd,
device->rfd, KMSCON_READABLE, device_data_arrived, device);
@ -187,6 +188,7 @@ void kmscon_input_device_sleep(struct kmscon_input_device *device)
static int kmscon_input_device_new(struct kmscon_input_device **out,
struct kmscon_input *input, const char *devnode)
{
int ret;
struct kmscon_input_device *device;
if (!out || !input)
@ -207,6 +209,13 @@ static int kmscon_input_device_new(struct kmscon_input_device **out,
return -ENOMEM;
}
ret = kmscon_kbd_new(&device->kbd, input->desc);
if (ret) {
free(device->devnode);
free(device);
return ret;
}
device->input = input;
device->rfd = -1;
@ -214,13 +223,13 @@ static int kmscon_input_device_new(struct kmscon_input_device **out,
return 0;
}
static void kmscon_input_device_ref(struct kmscon_input_device *device)
{
if (!device)
return;
/* static void kmscon_input_device_ref(struct kmscon_input_device *device) */
/* { */
/* if (!device) */
/* return; */
++device->ref;
}
/* ++device->ref; */
/* } */
static void kmscon_input_device_unref(struct kmscon_input_device *device)
{
@ -231,6 +240,7 @@ static void kmscon_input_device_unref(struct kmscon_input_device *device)
return;
kmscon_input_device_sleep(device);
kmscon_kbd_unref(device->kbd);
log_debug("input: destroying input device %s\n", device->devnode);
free(device->devnode);
free(device);
@ -260,7 +270,7 @@ int kmscon_input_new(struct kmscon_input **out)
variant = getenv("KMSCON_XKB_VARIANT") ?: "";
options = getenv("KMSCON_XKB_OPTIONS") ?: "";
ret = kmscon_xkb_new_desc(layout, variant, options, &input->xkb_desc);
ret = kmscon_kbd_desc_new(&input->desc, layout, variant, options);
if (ret) {
log_warning("input: cannot create xkb description\n");
goto err_free;
@ -303,7 +313,7 @@ err_monitor:
err_udev:
udev_unref(input->udev);
err_xkb:
kmscon_xkb_free_desc(input->xkb_desc);
kmscon_kbd_desc_unref(input->desc);
err_free:
free(input);
return ret;
@ -328,7 +338,7 @@ void kmscon_input_unref(struct kmscon_input *input)
kmscon_input_disconnect_eloop(input);
udev_monitor_unref(input->monitor);
udev_unref(input->udev);
kmscon_xkb_free_desc(input->xkb_desc);
kmscon_kbd_desc_unref(input->desc);
free(input);
log_debug("input: destroying input object\n");
}

View File

@ -77,17 +77,6 @@ struct kmscon_input_event {
typedef void (*kmscon_input_cb) (struct kmscon_input *input,
struct kmscon_input_event *ev, void *data);
/*
* These are the values sent by the kernel in the /value/ field of the
* /input_event/ struct.
* See Documentation/input/event-codes.txt in the kernel tree.
*/
enum kmscon_key_state {
KMSCON_KEY_RELEASED = 0,
KMSCON_KEY_PRESSED = 1,
KMSCON_KEY_REPEATED = 2,
};
int kmscon_input_new(struct kmscon_input **out);
void kmscon_input_ref(struct kmscon_input *input);
void kmscon_input_unref(struct kmscon_input *input);

View File

@ -1,48 +0,0 @@
/*
* kmscon - udev input hotplug and evdev handling
*
* Copyright (c) 2011 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef KMSCON_INPUT_XKB_H
#define KMSCON_INPUT_XKB_H
#include <inttypes.h>
#include <X11/extensions/XKBcommon.h>
#include "input.h"
int kmscon_xkb_new_desc(const char *layout, const char *variant,
const char *options,
struct xkb_desc **out);
void kmscon_xkb_free_desc(struct xkb_desc *desc);
void kmscon_xkb_reset_state(struct xkb_desc *desc,
struct xkb_state *state,
int evdev_fd);
bool kmscon_xkb_process_evdev_key(struct xkb_desc *desc,
struct xkb_state *state,
enum kmscon_key_state key_state,
uint16_t code,
struct kmscon_input_event *out);
#endif /* KMSCON_INPUT_XKB_H */

88
src/kbd.h Normal file
View File

@ -0,0 +1,88 @@
/*
* kmscon - translating key presses to input events
*
* Copyright (c) 2012 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* This defines the API the keyboard backends need to implement. The main
* function of a keyboard backend is to translate a kernel input event into a
* kmscon_input_event (see kmscon_kbd_process_key function).
*
* The two exported object are a "keyboard" object and a "keyboard
* description" object. The keyboard object holds all the device specific
* private state (e.g. active groups, modifiers). The description object
* holds all the global information (e.g. layouts, mapping tables).
*/
#ifndef KMSCON_KBD_H
#define KMSCON_KBD_H
#include <inttypes.h>
#include "input.h"
struct kmscon_kbd_desc;
struct kmscon_kbd;
/*
* These are the values sent by the kernel in the /value/ field of the
* /input_event/ struct.
* See Documentation/input/event-codes.txt in the kernel tree.
*/
enum kmscon_key_state {
KMSCON_KEY_RELEASED = 0,
KMSCON_KEY_PRESSED = 1,
KMSCON_KEY_REPEATED = 2,
};
int kmscon_kbd_desc_new(struct kmscon_kbd_desc **out, const char *layout,
const char *variant, const char *options);
void kmscon_kbd_desc_ref(struct kmscon_kbd_desc *desc);
void kmscon_kbd_desc_unref(struct kmscon_kbd_desc *desc);
int kmscon_kbd_new(struct kmscon_kbd **out, struct kmscon_kbd_desc *desc);
void kmscon_kbd_ref(struct kmscon_kbd *state);
void kmscon_kbd_unref(struct kmscon_kbd *state);
/*
* This resets the keyboard state in case it got out of sync. It's mainly used
* to sync our notion of the keyboard state with what the keyboard LEDs show.
*/
void kmscon_kbd_reset(struct kmscon_kbd *kbd, int evdev_fd);
/*
* This is the entry point to the keyboard processing.
* We get an evdev scancode and the keyboard state, and should put out a
* proper input event.
* Some evdev input events shouldn't result in us sending an input event
* (e.g. a key release):
* - If the event was filled out, 0 is returned.
* - Otherwise, if there was no error, -ENOKEY is returned.
*/
int kmscon_kbd_process_key(struct kmscon_kbd *kbd,
enum kmscon_key_state key_state,
uint16_t code,
struct kmscon_input_event *out);
void kmscon_kbd_keysym_to_string(uint32_t keysym, char *str, size_t size);
#endif /* KMSCON_KBD_H */

472
src/kbd_dumb.c Normal file
View File

@ -0,0 +1,472 @@
/*
* kmscon - translating key presses to input events using keycodes
*
* Copyright (c) 2012 Ran Benita <ran234@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
#include <X11/keysym.h>
#include "input.h"
#include "kbd.h"
#include "log.h"
#include "imKStoUCS.h"
/*
* This is a very "dumb" and simple fallback backend for keycodes
* interpretation. It uses direct mapping from kernel keycodes to X keysyms
* according to a basic US PC keyboard. It is not configurable and does not
* support unicode or other languages.
*
* The key interpretation is affected by the following modifiers: Numlock,
* Shift, Capslock, and "Normal" (no mofifiers) in that order. If a keycode is
* not affected by one of these depressed modifiers, the next matching one is
* attempted.
*/
struct kmscon_kbd_desc {
unsigned long ref;
/*
* There is no need for this structure here currently. It can contain
* pointers to alternative keytabs and modmaps, if we ever want this
* backend to support different languages, etc.
*/
};
struct kmscon_kbd {
unsigned long ref;
struct kmscon_kbd_desc *desc;
unsigned int mods;
};
/*
* These tables do not contain all possible keys from linux/input.h.
* If a keycode does not appear, it is mapped to keysym 0 and regarded as not
* found.
*/
static const uint32_t keytab_normal[] = {
[KEY_ESC] = XK_Escape,
[KEY_1] = XK_1,
[KEY_2] = XK_2,
[KEY_3] = XK_3,
[KEY_4] = XK_4,
[KEY_5] = XK_5,
[KEY_6] = XK_6,
[KEY_7] = XK_7,
[KEY_8] = XK_8,
[KEY_9] = XK_9,
[KEY_0] = XK_0,
[KEY_MINUS] = XK_minus,
[KEY_EQUAL] = XK_equal,
[KEY_BACKSPACE] = XK_BackSpace,
[KEY_TAB] = XK_Tab,
[KEY_Q] = XK_q,
[KEY_W] = XK_w,
[KEY_E] = XK_e,
[KEY_R] = XK_r,
[KEY_T] = XK_t,
[KEY_Y] = XK_y,
[KEY_U] = XK_u,
[KEY_I] = XK_i,
[KEY_O] = XK_o,
[KEY_P] = XK_p,
[KEY_LEFTBRACE] = XK_bracketleft,
[KEY_RIGHTBRACE] = XK_bracketright,
[KEY_ENTER] = XK_Return,
[KEY_LEFTCTRL] = XK_Control_L,
[KEY_A] = XK_a,
[KEY_S] = XK_s,
[KEY_D] = XK_d,
[KEY_F] = XK_f,
[KEY_G] = XK_g,
[KEY_H] = XK_h,
[KEY_J] = XK_j,
[KEY_K] = XK_k,
[KEY_L] = XK_l,
[KEY_SEMICOLON] = XK_semicolon,
[KEY_APOSTROPHE] = XK_apostrophe,
[KEY_GRAVE] = XK_grave,
[KEY_LEFTSHIFT] = XK_Shift_L,
[KEY_BACKSLASH] = XK_backslash,
[KEY_Z] = XK_z,
[KEY_X] = XK_x,
[KEY_C] = XK_c,
[KEY_V] = XK_v,
[KEY_B] = XK_b,
[KEY_N] = XK_n,
[KEY_M] = XK_m,
[KEY_COMMA] = XK_comma,
[KEY_DOT] = XK_period,
[KEY_SLASH] = XK_slash,
[KEY_RIGHTSHIFT] = XK_Shift_R,
[KEY_KPASTERISK] = XK_KP_Multiply,
[KEY_LEFTALT] = XK_Alt_L,
[KEY_SPACE] = XK_space,
[KEY_CAPSLOCK] = XK_Caps_Lock,
[KEY_F1] = XK_F1,
[KEY_F2] = XK_F2,
[KEY_F3] = XK_F3,
[KEY_F4] = XK_F4,
[KEY_F5] = XK_F5,
[KEY_F6] = XK_F6,
[KEY_F7] = XK_F7,
[KEY_F8] = XK_F8,
[KEY_F9] = XK_F9,
[KEY_F10] = XK_F10,
[KEY_NUMLOCK] = XK_Num_Lock,
[KEY_SCROLLLOCK] = XK_Scroll_Lock,
[KEY_KP7] = XK_KP_Home,
[KEY_KP8] = XK_KP_Up,
[KEY_KP9] = XK_KP_Page_Up,
[KEY_KPMINUS] = XK_KP_Subtract,
[KEY_KP4] = XK_KP_Left,
[KEY_KP5] = XK_KP_Begin,
[KEY_KP6] = XK_KP_Right,
[KEY_KPPLUS] = XK_KP_Add,
[KEY_KP1] = XK_KP_End,
[KEY_KP2] = XK_KP_Down,
[KEY_KP3] = XK_KP_Page_Down,
[KEY_KP0] = XK_KP_Insert,
[KEY_KPDOT] = XK_KP_Delete,
[KEY_F11] = XK_F11,
[KEY_F12] = XK_F12,
[KEY_KPENTER] = XK_KP_Enter,
[KEY_RIGHTCTRL] = XK_Control_R,
[KEY_KPSLASH] = XK_KP_Divide,
[KEY_RIGHTALT] = XK_Alt_R,
[KEY_LINEFEED] = XK_Linefeed,
[KEY_HOME] = XK_Home,
[KEY_UP] = XK_Up,
[KEY_PAGEUP] = XK_Page_Up,
[KEY_LEFT] = XK_Left,
[KEY_RIGHT] = XK_Right,
[KEY_END] = XK_End,
[KEY_DOWN] = XK_Down,
[KEY_PAGEDOWN] = XK_Page_Down,
[KEY_INSERT] = XK_Insert,
[KEY_DELETE] = XK_Delete,
[KEY_KPEQUAL] = XK_KP_Equal,
[KEY_LEFTMETA] = XK_Meta_L,
[KEY_RIGHTMETA] = XK_Meta_R,
};
#define KEYTAB_SIZE (KEY_RIGHTMETA + 1)
_Static_assert(
(KEYTAB_SIZE == sizeof(keytab_normal) / sizeof(*keytab_normal)),
"The KEYTAB_SIZE #define is incorrect!"
);
static const uint32_t keytab_numlock[KEYTAB_SIZE] = {
[KEY_KP7] = XK_KP_7,
[KEY_KP8] = XK_KP_8,
[KEY_KP9] = XK_KP_9,
[KEY_KP4] = XK_KP_4,
[KEY_KP5] = XK_KP_5,
[KEY_KP6] = XK_KP_6,
[KEY_KP1] = XK_KP_1,
[KEY_KP2] = XK_KP_2,
[KEY_KP3] = XK_KP_3,
[KEY_KP0] = XK_KP_0,
};
static const uint32_t keytab_shift[KEYTAB_SIZE] = {
[KEY_1] = XK_exclam,
[KEY_2] = XK_at,
[KEY_3] = XK_numbersign,
[KEY_4] = XK_dollar,
[KEY_5] = XK_percent,
[KEY_6] = XK_asciicircum,
[KEY_7] = XK_ampersand,
[KEY_8] = XK_asterisk,
[KEY_9] = XK_parenleft,
[KEY_0] = XK_parenright,
[KEY_MINUS] = XK_underscore,
[KEY_EQUAL] = XK_plus,
[KEY_Q] = XK_Q,
[KEY_W] = XK_W,
[KEY_E] = XK_E,
[KEY_R] = XK_R,
[KEY_T] = XK_T,
[KEY_Y] = XK_Y,
[KEY_U] = XK_U,
[KEY_I] = XK_I,
[KEY_O] = XK_O,
[KEY_P] = XK_P,
[KEY_LEFTBRACE] = XK_braceleft,
[KEY_RIGHTBRACE] = XK_braceright,
[KEY_A] = XK_A,
[KEY_S] = XK_S,
[KEY_D] = XK_D,
[KEY_F] = XK_F,
[KEY_G] = XK_G,
[KEY_H] = XK_H,
[KEY_J] = XK_J,
[KEY_K] = XK_K,
[KEY_L] = XK_L,
[KEY_SEMICOLON] = XK_colon,
[KEY_APOSTROPHE] = XK_quotedbl,
[KEY_GRAVE] = XK_asciitilde,
[KEY_BACKSLASH] = XK_bar,
[KEY_Z] = XK_Z,
[KEY_X] = XK_X,
[KEY_C] = XK_C,
[KEY_V] = XK_V,
[KEY_B] = XK_B,
[KEY_N] = XK_N,
[KEY_M] = XK_M,
[KEY_COMMA] = XK_less,
[KEY_DOT] = XK_greater,
[KEY_SLASH] = XK_question,
};
static const uint32_t keytab_capslock[KEYTAB_SIZE] = {
[KEY_Q] = XK_Q,
[KEY_W] = XK_W,
[KEY_E] = XK_E,
[KEY_R] = XK_R,
[KEY_T] = XK_T,
[KEY_Y] = XK_Y,
[KEY_U] = XK_U,
[KEY_I] = XK_I,
[KEY_O] = XK_O,
[KEY_P] = XK_P,
[KEY_A] = XK_A,
[KEY_S] = XK_S,
[KEY_D] = XK_D,
[KEY_F] = XK_F,
[KEY_G] = XK_G,
[KEY_H] = XK_H,
[KEY_J] = XK_J,
[KEY_K] = XK_K,
[KEY_L] = XK_L,
[KEY_Z] = XK_Z,
[KEY_X] = XK_X,
[KEY_C] = XK_C,
[KEY_V] = XK_V,
[KEY_B] = XK_B,
[KEY_N] = XK_N,
[KEY_M] = XK_M,
};
static const struct {
enum kmscon_modifier mod;
enum {
MOD_NORMAL = 1,
MOD_LOCK,
} type;
} modmap[KEYTAB_SIZE] = {
[KEY_LEFTCTRL] = { KMSCON_CONTROL_MASK, MOD_NORMAL },
[KEY_LEFTSHIFT] = { KMSCON_SHIFT_MASK, MOD_NORMAL },
[KEY_RIGHTSHIFT] = { KMSCON_SHIFT_MASK, MOD_NORMAL },
[KEY_LEFTALT] = { KMSCON_MOD1_MASK, MOD_NORMAL },
[KEY_CAPSLOCK] = { KMSCON_LOCK_MASK, MOD_LOCK },
[KEY_NUMLOCK] = { KMSCON_MOD2_MASK, MOD_LOCK },
[KEY_RIGHTCTRL] = { KMSCON_CONTROL_MASK, MOD_NORMAL },
[KEY_RIGHTALT] = { KMSCON_MOD1_MASK, MOD_NORMAL },
[KEY_LEFTMETA] = { KMSCON_MOD4_MASK, MOD_NORMAL },
[KEY_RIGHTMETA] = { KMSCON_MOD4_MASK, MOD_NORMAL },
};
int kmscon_kbd_new(struct kmscon_kbd **out, struct kmscon_kbd_desc *desc)
{
struct kmscon_kbd *kbd;
kbd = malloc(sizeof(*kbd));
if (!kbd)
return -ENOMEM;
memset(kbd, 0, sizeof(*kbd));
kbd->desc = desc;
kmscon_kbd_desc_ref(desc);
*out = kbd;
return 0;
}
void kmscon_kbd_ref(struct kmscon_kbd *kbd)
{
if (!kbd)
return;
++kbd->ref;
}
void kmscon_kbd_unref(struct kmscon_kbd *kbd)
{
if (!kbd || !kbd->ref)
return;
if (--kbd->ref)
return;
kmscon_kbd_desc_unref(kbd->desc);
free(kbd);
}
void kmscon_kbd_reset(struct kmscon_kbd *kbd, int evdev_fd)
{
int i;
/* One long should be enough (LED_MAX is currently 16). */
unsigned long leds, bit;
if (!kbd)
return;
kbd->mods = 0;
errno = 0;
ioctl(evdev_fd, EVIOCGLED(sizeof(leds)), &leds);
if (errno) {
log_warning("kbd-dumb: cannot discover modifiers state: %m\n");
return;
}
/* The LED_* constants specifiy the bit location. */
for (i=0, bit=0x01; i < LED_MAX; i++, bit<<=1) {
if (!(leds & bit))
continue;
switch (i) {
case LED_NUML:
kbd->mods |= KMSCON_MOD2_MASK;
break;
case LED_CAPSL:
kbd->mods |= KMSCON_LOCK_MASK;
break;
}
}
}
int kmscon_kbd_process_key(struct kmscon_kbd *kbd,
enum kmscon_key_state key_state,
uint16_t code,
struct kmscon_input_event *out)
{
uint32_t keysym;
enum kmscon_modifier mod;
int mod_type;
/* Ignore unknown keycodes. */
if (code >= KEYTAB_SIZE)
return -ENOKEY;
if (modmap[code].mod) {
mod = modmap[code].mod;
mod_type = modmap[code].type;
/*
* We release locked modifiers on key press, like the kernel,
* but unlike XKB.
*/
if (key_state == KMSCON_KEY_PRESSED) {
if (mod_type == MOD_NORMAL)
kbd->mods |= mod;
else if (mod_type == MOD_LOCK)
kbd->mods ^= mod;
} else if (key_state == KMSCON_KEY_RELEASED) {
if (mod_type == MOD_NORMAL)
kbd->mods &= ~mod;
}
/* Don't deliver events purely for modifiers. */
return -ENOKEY;
}
if (key_state == KMSCON_KEY_RELEASED)
return -ENOKEY;
keysym = 0;
if (!keysym && kbd->mods & KMSCON_MOD2_MASK)
keysym = keytab_numlock[code];
if (!keysym && kbd->mods & KMSCON_SHIFT_MASK)
keysym = keytab_shift[code];
if (!keysym && kbd->mods & KMSCON_LOCK_MASK)
keysym = keytab_capslock[code];
if (!keysym)
keysym = keytab_normal[code];
if (!keysym)
return -ENOKEY;
out->keycode = code;
out->keysym = keysym;
out->unicode = KeysymToUcs4(keysym) ?: KMSCON_INPUT_INVALID;
out->mods = kbd->mods;
return 0;
}
int kmscon_kbd_desc_new(struct kmscon_kbd_desc **out, const char *layout,
const char *variant, const char *options)
{
struct kmscon_kbd_desc *desc;
if (!out)
return -EINVAL;
log_debug("kbd-dumb: new keyboard description (%s, %s, %s)\n",
layout, variant, options);
desc = malloc(sizeof(*desc));
if (!desc)
return -ENOMEM;
memset(desc, 0, sizeof(*desc));
desc->ref = 1;
*out = desc;
return 0;
}
void kmscon_kbd_desc_ref(struct kmscon_kbd_desc *desc)
{
if (!desc)
return;
++desc->ref;
}
void kmscon_kbd_desc_unref(struct kmscon_kbd_desc *desc)
{
if (!desc || !desc->ref)
return;
if (--desc->ref)
return;
log_debug("kbd-dumb: destroying keyboard description\n");
free(desc);
}
void kmscon_kbd_keysym_to_string(uint32_t keysym, char *str, size_t size)
{
snprintf(str, size, "%#x", keysym);
}

File diff suppressed because it is too large Load Diff

View File

@ -32,13 +32,12 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wchar.h>
#include <X11/extensions/XKBcommon.h>
#include <X11/keysym.h>
#include "eloop.h"
#include "input.h"
#include "kbd.h"
#include "log.h"
static bool terminate;
@ -86,27 +85,17 @@ static void print_modifiers(unsigned int mods)
static void input_arrived(struct kmscon_input *input,
struct kmscon_input_event *ev, void *data)
{
int len;
char s[16];
char utf8[MB_CUR_MAX + 1];
if (ev->unicode == KMSCON_INPUT_INVALID) {
xkb_keysym_to_string(ev->keysym, s, sizeof(s));
kmscon_kbd_keysym_to_string(ev->keysym, s, sizeof(s));
printf("sym %s ", s);
} else {
/*
* Just a proof-of-concept hack. This works because glibc uses
* UTF-32 (= UCS-4) as the internal wchar_t encoding.
*/
len = wctomb(utf8, (wchar_t)ev->unicode);
if (len <= 0) {
log_info("Bad unicode char\n");
return;
} else {
utf8[len] = '\0';
}
printf("utf8 %s ", utf8);
printf("unicode %lc ", ev->unicode);
}
print_modifiers(ev->mods);
}
@ -118,7 +107,7 @@ int main(int argc, char **argv)
struct kmscon_input *input;
struct kmscon_signal *sigint, *sigquit;
if (!setlocale(LC_ALL, "en_US.UTF-8")) {
if (!setlocale(LC_ALL, "")) {
log_err("Cannot set locale: %m\n");
ret = -EFAULT;
goto err_out;