Skip to content
This repository has been archived by the owner on Mar 27, 2019. It is now read-only.

Kernel user input handling #65

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
419e5e6
evdev basics
TheSheepKing Jun 3, 2018
9b48019
interactive-evdev basics from libxkbcommon
TheSheepKing Jun 23, 2018
48a3fae
removed evdev-client.c (from libxkbcommon quick guide)
TheSheepKing Jun 23, 2018
6b6e7dc
Creating a class to wrap the interactive-evdev
TheSheepKing Jun 24, 2018
ba9f68f
added the needed variables as attributes to EvdevClient
TheSheepKing Jun 24, 2018
a80da8d
initializing pointers as NULL
TheSheepKing Jun 24, 2018
b244bdd
Added a function to init the client
TheSheepKing Jun 24, 2018
f8e51c8
Added a function to test the validity of the client
TheSheepKing Jun 24, 2018
cf4d89b
Created a class that will be used as a wrapper on libxkbcommon
TheSheepKing Jun 24, 2018
c055287
Added a function to create a new xkb context in the wrapper
TheSheepKing Jun 24, 2018
16ed7bd
Added initialisation of the xkb context
TheSheepKing Jun 24, 2018
d1fb3e2
Added a proper way to destroy the client
TheSheepKing Jun 24, 2018
6b78565
Added a function to create a new xkb keymap in the wrapper and used i…
TheSheepKing Jun 24, 2018
a4d134e
Added a function to get the keyboards in the wrapper (<= need clean u…
TheSheepKing Jun 24, 2018
7e0f6f2
XkbWrapper clean up
TheSheepKing Jun 24, 2018
cfa40aa
Added a function to loop on the input reading (<= need a LOT of clean…
TheSheepKing Jun 24, 2018
ad1c595
Indentation switched to soft 4
TheSheepKing Jun 24, 2018
8442ec1
Added a main for testing, will be deleted later
TheSheepKing Jun 24, 2018
54b0c44
EvdevClient used in the main (loop is not a loop anymore => will edit…
TheSheepKing Jun 27, 2018
ae38e28
cleaned the loop function of EvdevClient /\!\ it's new name is tick
TheSheepKing Jun 28, 2018
27e3b75
Added some strerror for clarity
TheSheepKing Jun 28, 2018
49ef914
cleanup on read_keyboard and process_event
TheSheepKing Jul 2, 2018
5048a23
light general cleanup in EvdevClient
TheSheepKing Jul 2, 2018
f3515ad
initial RAI for the fd of evdev client
TheSheepKing Sep 28, 2018
ea3bd00
large cleanup of free/alloc/assert on XkbWrapper + evdev-client added…
TheSheepKing Oct 24, 2018
7e018fd
Adding the missing FileDescriptor files
TheSheepKing Oct 24, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 233 additions & 0 deletions source/evdev-client/EvdevClient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
#include "EvdevClient.hpp"

EvdevClient::EvdevClient()
:
rules(NULL),
model(NULL),
layout(NULL),
variant(NULL),
options(NULL),
keymap_path(NULL),
valid(false)
{
std::cout << "EvdevClient constructed." << std::endl;
}

EvdevClient::~EvdevClient()
{
destroyClient();
std::cout << "EvdevClient destructed." << std::endl;
}

bool EvdevClient::initClient()
{
ctx = xkbWrapper.newContext();
if (!ctx)
{
fprintf(stderr, "Couldn't create xkb context.\n");
return (valid);
}
destructionFlag = toDestroy::ONLY_CONTEXT;
keymap = xkbWrapper.newKeymap(ctx);
if (!keymap)
{
fprintf(stderr, "Couldn't create xkb keymap.\n");
return (valid);
}
destructionFlag = toDestroy::FROM_KEYMAP;
kbds = xkbWrapper.getKeyboards(keymap);
if (!kbds) {
fprintf(stderr, "Couldn't get any keyboard.\n");
return (valid);
}
destructionFlag = toDestroy::FROM_KEYBOARDS;
fdWrapper.init(epoll_create1(0));
if (fdWrapper.fd < 0)
{
fprintf(stderr, "Couldn't create epoll instance: %s\n", strerror(errno));
return (valid);
}
for (struct keyboard *kbd = kbds; kbd; kbd = kbd->next)
{
struct epoll_event ev;

memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
ev.data.ptr = kbd;
if (epoll_ctl(fdWrapper.fd, EPOLL_CTL_ADD, kbd->fd, &ev))
{
fprintf(stderr, "Couldn't add %s to epoll: %s\n", kbd->path, strerror(errno));
return (valid);
}
}
valid = true;
return (valid);
}

void EvdevClient::destroyClient()
{
switch (destructionFlag)
{
case toDestroy::ALL:
case toDestroy::FROM_KEYBOARDS:
xkbWrapper.freeKeyboards(kbds);
[[fallthrough]];
case toDestroy::FROM_KEYMAP:
xkb_keymap_unref(keymap);
[[fallthrough]];
case toDestroy::ONLY_CONTEXT:
xkb_context_unref(ctx);
default:
break;
}
}

bool EvdevClient::isValid() const
{
return (valid);
}

void test_print_keycode_state(struct xkb_state *state,
xkb_keycode_t keycode,
enum xkb_consumed_mode consumed_mode
)
{
struct xkb_keymap *keymap;
const xkb_keysym_t *syms;
int nsyms;
char s[16];
xkb_layout_index_t layout;

keymap = xkb_state_get_keymap(state);
nsyms = xkb_state_key_get_syms(state, keycode, &syms);
if (nsyms <= 0)
{
return;
}
printf("\nkeysyms [ ");
for (int i = 0; i < nsyms; i++)
{
xkb_keysym_get_name(syms[i], s, sizeof(s));
printf("%-*s ", (int) sizeof(s), s);
}
printf("] ");
xkb_state_key_get_utf8(state, keycode, s, sizeof(s));
printf("unicode [ %s ] ", s);
layout = xkb_state_key_get_layout(state, keycode);
printf("layout [ %s (%d) ] ",
xkb_keymap_layout_get_name(keymap, layout), layout);
printf("level [ %d ] ",
xkb_state_key_get_level(state, keycode, layout));
printf("mods [ ");
for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++)
{
if (xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_EFFECTIVE) <= 0)
{
continue;
}
if (xkb_state_mod_index_is_consumed2(state, keycode, mod, consumed_mode))
{
printf("-%s ", xkb_keymap_mod_get_name(keymap, mod));
}
else
{
printf("%s ", xkb_keymap_mod_get_name(keymap, mod));
}
}
printf("] ");
printf("leds [ ");
for (xkb_led_index_t led = 0; led < xkb_keymap_num_leds(keymap); led++)
{
if (xkb_state_led_index_is_active(state, led) <= 0)
{
continue;
}
printf("%s ", xkb_keymap_led_get_name(keymap, led));
}
printf("] ");
printf("\n");
}

void EvdevClient::processEvent(struct keyboard *kbd,
uint16_t type,
uint16_t code,
int32_t value
)
{
xkb_keycode_t keycode;
struct xkb_keymap *keymap;

if (type != EV_KEY)
{
return;
}
keycode = EVDEV_OFFSET + code;
keymap = xkb_state_get_keymap(kbd->state);
if (value == keyState::KEY_STATE_REPEAT && !xkb_keymap_key_repeats(keymap, keycode))
{
return;
}
if (value != keyState::KEY_STATE_RELEASE)
{
test_print_keycode_state(kbd->state,
keycode,
XKB_CONSUMED_MODE_XKB
);
}
if (value == keyState::KEY_STATE_RELEASE)
{
xkb_state_update_key(kbd->state, keycode, XKB_KEY_UP);
}
else
{
xkb_state_update_key(kbd->state, keycode, XKB_KEY_DOWN);
}
}

int EvdevClient::readKeyboard(struct keyboard *kbd)
{
ssize_t len;
struct input_event evs[16];

while ((len = read(kbd->fd, &evs, sizeof(evs))) > 0)
{
const size_t nevs = len / sizeof(struct input_event);

for (size_t i = 0; i < nevs; i++)
{
processEvent(kbd, evs[i].type, evs[i].code, evs[i].value);
}
}
if (len < 0 && errno != EWOULDBLOCK)
{
fprintf(stderr, "Couldn't read %s: %s\n", kbd->path, strerror(errno));
return (1);
}
return (0);
}

void EvdevClient::tick()
{
int ret;
struct keyboard *kbd;
struct epoll_event evs[16];

ret = epoll_wait(fdWrapper.fd, evs, 16, 10);
if (ret < 0)
{
if (errno == EINTR)
{
return;
}
fprintf(stderr, "Couldn't poll for events: %s\n", strerror(errno));
}
for (int i = 0; i < ret; i++)
{
kbd = (struct keyboard *)evs[i].data.ptr;
if (readKeyboard(kbd))
{
return;
}
}
return;
}
63 changes: 63 additions & 0 deletions source/evdev-client/EvdevClient.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

#include <iostream>
#include <memory>
#include <signal.h>
#include <sys/epoll.h>
#include "FileDescriptorWrapper.hpp"
#include "XkbWrapper.hpp"
#include "claws/utils/on_scope_exit.hpp"

#define EVDEV_OFFSET 8

enum toDestroy
{
ALL = 0,
FROM_KEYBOARDS,
FROM_KEYMAP,
ONLY_CONTEXT,
FROM_EPFD,
};

/* The meaning of the input_event 'value' field. */
enum keyState
{
KEY_STATE_RELEASE = 0,
KEY_STATE_PRESS = 1,
KEY_STATE_REPEAT = 2,
};

class EvdevClient
{
// ATTRIBUTES
FileDescriptorWrapper fdWrapper;
XkbWrapper xkbWrapper;
//std::unique_ptr<struct keyboard> kbds;
struct keyboard *kbds;
struct xkb_context *ctx;
struct xkb_keymap *keymap;

const char *rules;
const char *model;
const char *layout;
const char *variant;
const char *options;
const char *keymap_path;
const char *locale;

bool valid;
enum toDestroy destructionFlag;

// FUNCTIONS
void processEvent(struct keyboard *kbd, uint16_t type, uint16_t code, int32_t value);
int readKeyboard(struct keyboard *kbd);

public:
EvdevClient();
~EvdevClient();

bool initClient();
void destroyClient();
bool isValid() const;
void tick();
};
19 changes: 19 additions & 0 deletions source/evdev-client/FileDescriptorWrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "FileDescriptorWrapper.hpp"

FileDescriptorWrapper::FileDescriptorWrapper()
: fd(-1)
{
}

FileDescriptorWrapper::~FileDescriptorWrapper()
{
if (fd > -1)
{
close(fd);
}
}

void FileDescriptorWrapper::init(int fd)
{
this->fd = fd;
}
13 changes: 13 additions & 0 deletions source/evdev-client/FileDescriptorWrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <unistd.h>

struct FileDescriptorWrapper
{
int fd;

FileDescriptorWrapper();
~FileDescriptorWrapper();

void init(int fd);
};
Loading