Skip to content

Commit

Permalink
feat(platform): add linux keyboard driver
Browse files Browse the repository at this point in the history
  • Loading branch information
lc-soft committed May 5, 2018
1 parent 0ff7b70 commit ad3348e
Showing 1 changed file with 239 additions and 5 deletions.
244 changes: 239 additions & 5 deletions src/platform/linux/linux_keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,264 @@
*/

#include <LCUI_Build.h>
#ifdef LCUI_BUILD_IN_LINUX
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#ifdef USE_LINUX_INPUT_EVENT
#include <linux/input.h>
#else
#include <signal.h>
#include <termios.h>
#endif
#include <LCUI/LCUI.h>
#include <LCUI/thread.h>
#include <LCUI/platform.h>
#include <LCUI/input.h>
#include <LCUI/ime.h>
#include LCUI_EVENTS_H
#include LCUI_KEYBOARD_H
#ifdef LCUI_BUILD_IN_LINUX

static struct LCUI_LinuxKeyboardDriver {
#ifdef USE_LINUX_INPUT_EVENT
int dev_fd;
char *dev_path;
#else
int fd;
struct termios tm;
#endif
LCUI_Thread tid;
LCUI_BOOL active;
} keyboard;

/* FIXME: this driver does not working, so we won't use it for now */
#ifdef USE_LINUX_INPUT_EVENT
static void LinuxKeybnoardThread(void *arg)
{
size_t bytes;
struct input_event data;

keyboard.active = TRUE;
LOG("[input] keyboard driver thread: %lld\n", keyboard.tid);
while (keyboard.active) {
bytes = read(keyboard.dev_fd, &data, sizeof(data));
if (bytes > 0 && data.type == EV_KEY) {
_DEBUG_MSG("Keypress value=%x, type=%x, code=%x\n",
data.value, data.type, data.code);
}
}
}

static int InitLinuxKeybord(void)
{
keyboard.dev_path = getenv("LCUI_KEYBOARD_DEVICE");
if (!keyboard.dev_path) {
keyboard.dev_path = "/dev/input/event0";
}
if ((keyboard.dev_fd = open(keyboard.dev_path, O_RDONLY | O_NONBLOCK)) <
0) {
perror("[input] open keyboard device failed");
return -1;
}
LCUIThread_Create(&keyboard.tid, LinuxKeybnoardThread, NULL);
return 0;
}

static int FreeLinuxKeyboard(void)
{
if (!keyboard.active) {
return -1;
}
keyboard.active = FALSE;
LCUIThread_Join(keyboard.tid, NULL);
close(keyboard.dev_fd);
return 0;
}

#else

static void DispatchKeyboardEvent(void *arg1, void *arg2)
{
wchar_t str[2];
LCUI_SysEventRec ev = { 0 };

ev.key.code = *((int *)arg1);
switch (ev.key.code) {
case 183:
ev.key.code = LCUIKEY_UP;
break;
case 184:
ev.key.code = LCUIKEY_DOWN;
break;
case 185:
ev.key.code = LCUIKEY_RIGHT;
break;
case 186:
ev.key.code = LCUIKEY_LEFT;
break;
case 127:
ev.key.code = LCUIKEY_BACKSPACE;
break;
case 293:
ev.key.code = LCUIKEY_HOME;
break;
case 295:
ev.key.code = LCUIKEY_DELETE;
break;
case 296:
ev.key.code = LCUIKEY_END;
break;
case 297:
ev.key.code = LCUIKEY_PAGEUP;
break;
case 298:
ev.key.code = LCUIKEY_PAGEDOWN;
default:
break;
}
DEBUG_MSG("%c, %d\n", ev.key.code, ev.key.code);
ev.type = LCUI_KEYDOWN;
LCUI_TriggerEvent(&ev, NULL);
LCUI_DestroyEvent(&ev);
/* FIXME: this driver is not yet possible to get the key state directly,
* the following is a temporary solution.
*/
ev.type = LCUI_KEYUP;
LCUI_TriggerEvent(&ev, NULL);
LCUI_DestroyEvent(&ev);
if (ev.key.code >= ' ' && ev.key.code <= '~') {
str[0] = ev.key.code;
ev.type = LCUI_KEYPRESS;
LCUI_TriggerEvent(&ev, NULL);
LCUI_DestroyEvent(&ev);
LCUIIME_Commit(str, 1);
}
}

LCUI_BOOL kbhit(void)
{
int ch, flags;
struct termios tm;

tcgetattr(keyboard.fd, &tm);
flags = fcntl(keyboard.fd, F_GETFL, 0);
fcntl(keyboard.fd, F_SETFL, flags | O_NONBLOCK);
ch = getchar();
tcsetattr(keyboard.fd, TCSANOW, &tm);
fcntl(keyboard.fd, F_SETFL, flags);
if (ch != EOF) {
ungetc(ch, stdin);
return TRUE;
}
return FALSE;
}

int getch(void)
{
int c = EOF;
struct termios tm;

tm = keyboard.tm;

/* canonical input and echo modes */
tm.c_lflag &= ~(ICANON | ECHO);
tm.c_cc[VMIN] = 0;
tm.c_cc[VTIME] = 1;
tcsetattr(keyboard.fd, TCSANOW, &tm);
/* get char from modified stdin */
c = getchar();
/* reset stdin to previous state */
tcsetattr(keyboard.fd, TCSANOW, &keyboard.tm);
return c;
}

static void on_signal(int signal)
{
tcsetattr(keyboard.fd, TCSANOW, &keyboard.tm);
exit(1);
}

static void LinuxKeybnoardThread(void *arg)
{
int key;
LCUI_TaskRec task = { 0 };

keyboard.active = TRUE;
task.func = DispatchKeyboardEvent;
task.destroy_arg[0] = free;
while (keyboard.active) {
key = getch();
if (key == EOF) {
continue;
}
while (kbhit()) {
key += getch();
}
task.arg[0] = malloc(sizeof(int));
if (!task.arg[0]) {
perror("[input] keyboard driver");
continue;
}
memcpy(task.arg[0], &key, sizeof(int));
LCUI_PostTask(&task);
}
}

static int InitLinuxKeybord(void)
{
int i = 0;
int signals[] = { SIGABRT, SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM };
int len = sizeof(signals) / sizeof(signals[0]);

keyboard.fd = STDIN_FILENO;
if (tcgetattr(keyboard.fd, &keyboard.tm) < 0) {
return -1;
}
for (; i < len; ++i) {
signal(signals[i], on_signal);
}
LCUIThread_Create(&keyboard.tid, LinuxKeybnoardThread, NULL);
LOG("[input] keyboard driver thread: %lld\n", keyboard.tid);
return 0;
}

static int FreeLinuxKeyboard(void)
{
if (!keyboard.active) {
return 0;
}
keyboard.active = FALSE;
LCUIThread_Join(keyboard.tid, NULL);
if (tcsetattr(keyboard.fd, TCSANOW, &keyboard.tm) < 0) {
return -1;
}
return 0;
}

#endif

void LCUI_InitLinuxKeyboard(void)
{
#ifdef LCUI_VIDEO_DRIVER_X11
LCUI_BOOL is_x11_mode = TRUE;
if (is_x11_mode) {
if (LCUI_GetAppId() == LCUI_APP_LINUX_X11) {
LCUI_InitLinuxX11Keyboard();
return;
}
#endif
InitLinuxKeybord();
}

void LCUI_FreeLinuxKeyboard(void)
{
#ifdef LCUI_VIDEO_DRIVER_X11
LCUI_BOOL is_x11_mode = TRUE;
if (is_x11_mode) {
if (LCUI_GetAppId() == LCUI_APP_LINUX_X11) {
LCUI_FreeLinuxX11Keyboard();
return;
}
#endif
FreeLinuxKeyboard();
}

#endif

0 comments on commit ad3348e

Please sign in to comment.