Rewrite kobo color inputs
This commit is contained in:
parent
27f18d0a45
commit
83ba5981cc
6 changed files with 287 additions and 9 deletions
|
@ -2,5 +2,5 @@ project('kobo-color-inputdev', 'c',
|
|||
version : '0.1',
|
||||
default_options : ['warning_level=3'])
|
||||
|
||||
exe = executable('kobo-color-inputdev', 'src/main.c',
|
||||
main = executable('kobo-color-inputdev', ['src/main.c', './src/device.c'],
|
||||
install : true)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{ pkgs ? import <nixpkgs> { } }:
|
||||
pkgs.mkShell {
|
||||
packages = with pkgs; [ libevent clang-tools ];
|
||||
packages = with pkgs; [ libinput evtest clang-tools ];
|
||||
inputsFrom = [ (pkgs.callPackage ./default.nix { }) ];
|
||||
}
|
||||
|
|
102
src/device.c
Normal file
102
src/device.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include "logger.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct uinput_abs_setup ABS_SETUP_X = {.code = ABS_X,
|
||||
.absinfo = {
|
||||
0,
|
||||
.maximum = 1680,
|
||||
.resolution = 6,
|
||||
}};
|
||||
|
||||
struct uinput_abs_setup ABS_SETUP_Y = {.code = ABS_Y,
|
||||
.absinfo = {
|
||||
0,
|
||||
.maximum = 1264,
|
||||
.resolution = 8,
|
||||
}};
|
||||
|
||||
struct uinput_abs_setup ABS_SETUP_PRESSURE = {.code = ABS_PRESSURE,
|
||||
.absinfo = {
|
||||
0,
|
||||
.maximum = 4095,
|
||||
}};
|
||||
|
||||
struct uinput_abs_setup ABS_SETUP_TILT_X = {.code = ABS_TILT_X,
|
||||
.absinfo = {
|
||||
0,
|
||||
.minimum = -60,
|
||||
.maximum = 60,
|
||||
}};
|
||||
|
||||
struct uinput_abs_setup ABS_SETUP_TILT_Y = {.code = ABS_TILT_Y,
|
||||
.absinfo = {
|
||||
0,
|
||||
.minimum = -60,
|
||||
.maximum = 60,
|
||||
}};
|
||||
|
||||
struct uinput_abs_setup ABS_SETUP_DISTANCE = {.code = ABS_DISTANCE,
|
||||
.absinfo = {
|
||||
0,
|
||||
.maximum = 0xf,
|
||||
}};
|
||||
|
||||
int setup(FILE **device) {
|
||||
struct uinput_setup usetup;
|
||||
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
char *error = strerror(errno);
|
||||
logf("Error opening /dev/uinput: %s", error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The ioctls below will enable the device that is about to be
|
||||
* created, to pass key events, in this case the space key.
|
||||
*/
|
||||
ioctl(fd, UI_SET_EVBIT, EV_SYN);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_ABS);
|
||||
|
||||
ioctl(fd, UI_ABS_SETUP, &ABS_SETUP_X);
|
||||
ioctl(fd, UI_ABS_SETUP, &ABS_SETUP_Y);
|
||||
ioctl(fd, UI_ABS_SETUP, &ABS_SETUP_PRESSURE);
|
||||
ioctl(fd, UI_ABS_SETUP, &ABS_SETUP_TILT_X);
|
||||
ioctl(fd, UI_ABS_SETUP, &ABS_SETUP_TILT_Y);
|
||||
ioctl(fd, UI_ABS_SETUP, &ABS_SETUP_DISTANCE);
|
||||
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS2);
|
||||
|
||||
memset(&usetup, 0, sizeof(usetup));
|
||||
usetup.id.bustype = BUS_VIRTUAL;
|
||||
usetup.id.vendor = 0x1234; /* sample vendor */
|
||||
usetup.id.product = 0x5678; /* sample product */
|
||||
strcpy(usetup.name, "Elan Touchscreen");
|
||||
|
||||
ioctl(fd, UI_DEV_SETUP, &usetup);
|
||||
ioctl(fd, UI_DEV_CREATE);
|
||||
|
||||
FILE *file = fdopen(fd, "w");
|
||||
*device = file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup(FILE *device) {
|
||||
fflush(device);
|
||||
|
||||
ioctl(fileno(device), UI_DEV_DESTROY);
|
||||
|
||||
fclose(device);
|
||||
}
|
5
src/device.h
Normal file
5
src/device.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
#include <stdio.h>
|
||||
|
||||
int setup(FILE **dev);
|
||||
int cleanup(FILE *dev);
|
17
src/logger.h
Normal file
17
src/logger.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#define BLK "\x1B[0;30m"
|
||||
#define RED "\x1B[0;31m"
|
||||
#define GRN "\x1B[0;32m"
|
||||
#define YEL "\x1B[0;33m"
|
||||
#define BLU "\x1B[0;34m"
|
||||
#define MAG "\x1B[0;35m"
|
||||
#define CYN "\x1B[0;36m"
|
||||
#define WHT "\x1B[0;37m"
|
||||
#define RESET "\x1B[0m"
|
||||
|
||||
#define logf(x, ...) \
|
||||
fprintf(stderr, "%s%s%s:%s%d%s: " x "\n", BLU, __FILE_NAME__, WHT, RED, \
|
||||
__LINE__, RESET, __VA_ARGS__);
|
||||
|
||||
#define log(x) logf("%s", x)
|
164
src/main.c
164
src/main.c
|
@ -1,12 +1,166 @@
|
|||
#include "device.h"
|
||||
#include "logger.h"
|
||||
#include <assert.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PROJECT_NAME "kobo-color-inputdev"
|
||||
int read_input_event(struct input_event *ie) {
|
||||
if (fread(ie, sizeof(struct input_event), 1, stdin) != 1) {
|
||||
if (feof(stdin)) {
|
||||
return EOF;
|
||||
} else {
|
||||
char *err = strerror(ferror(stdin));
|
||||
logf("Error reading input event! %s", err);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if(argc != 1) {
|
||||
printf("%s takes no arguments.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
printf("This is project %s.\n", PROJECT_NAME);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_to_match(struct input_event *ie, int type, int code, int value) {
|
||||
int res;
|
||||
while (!(res = read_input_event(ie) && (type == ie->type) &&
|
||||
(code == -1 || code == ie->code) &&
|
||||
(value == -1 || value == ie->value))) {
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
int forward_event(FILE *dev, struct input_event *ie) {
|
||||
if (fwrite(ie, sizeof(struct input_event), 1, dev) != 1) {
|
||||
if (feof(dev)) {
|
||||
return EOF;
|
||||
} else {
|
||||
char *err = strerror(ferror(dev));
|
||||
logf("Error writing input event(type: %x, code: %x, value: %x)! %s",
|
||||
ie->type, ie->code, ie->value, err);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (ie->type == EV_SYN) {
|
||||
fflush(dev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool rewrite_abs_pen_event(struct input_event *ie) {
|
||||
assert(ie->type == EV_ABS);
|
||||
|
||||
switch (ie->code) {
|
||||
// Rewrite the event codes
|
||||
case ABS_MT_POSITION_X:
|
||||
ie->code = ABS_X;
|
||||
break;
|
||||
case ABS_MT_POSITION_Y:
|
||||
ie->code = ABS_Y;
|
||||
break;
|
||||
case ABS_MT_PRESSURE:
|
||||
ie->code = ABS_PRESSURE;
|
||||
break;
|
||||
case ABS_MT_DISTANCE:
|
||||
ie->code = ABS_DISTANCE;
|
||||
// Passthrough events:
|
||||
case ABS_TILT_X:
|
||||
case ABS_TILT_Y:
|
||||
break;
|
||||
// Ignore events without logging
|
||||
case ABS_MT_TRACKING_ID:
|
||||
case ABS_MT_TOOL_TYPE:
|
||||
case ABS_MT_TOUCH_MAJOR:
|
||||
case ABS_MT_TOUCH_MINOR:
|
||||
// Custom kobo event codes, extracted from headers at:
|
||||
// https://github.com/kobolabs/Kobo-Reader/blob/master/hw/mt8113-libraC_vision7/
|
||||
// ABS_AZIMUTH
|
||||
case 0x1d:
|
||||
// ABS_TIP_MIN
|
||||
case 0x2a:
|
||||
// ABS_TIP_MAX
|
||||
case 0x29:
|
||||
return false;
|
||||
default:
|
||||
logf("Unknown EV_ABS! code: %x, value: %x", ie->code, ie->value);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int rewrite_key_pen_event(struct input_event *ie) {
|
||||
assert(ie->type == EV_KEY);
|
||||
switch (ie->code) {
|
||||
case BTN_TOUCH:
|
||||
case BTN_STYLUS:
|
||||
case BTN_STYLUS2:
|
||||
return true;
|
||||
// Known events we don't want to forward
|
||||
case KEY_BATTERY:
|
||||
return false;
|
||||
// Uknown events
|
||||
default:
|
||||
logf("Unknown EV_KEY! code: %x, value: %x", ie->code, ie->value);
|
||||
return false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rewrite_syn_pen_event(struct input_event *ie) {
|
||||
assert(ie->type == EV_SYN);
|
||||
if (ie->code == SYN_MT_REPORT)
|
||||
ie->code = SYN_REPORT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rewrite_pen_event(struct input_event *ie) {
|
||||
switch (ie->type) {
|
||||
case EV_ABS:
|
||||
return rewrite_abs_pen_event(ie);
|
||||
case EV_KEY:
|
||||
return rewrite_key_pen_event(ie);
|
||||
case EV_SYN:
|
||||
return rewrite_syn_pen_event(ie);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int process_events(FILE *dev) {
|
||||
while (true) {
|
||||
int res;
|
||||
struct input_event ie;
|
||||
while ((!(res = read_input_event(&ie))) &&
|
||||
(ie.type != EV_ABS && (ie.code != ABS_MT_TOOL_TYPE) &&
|
||||
(ie.value != MT_TOOL_PEN))) {
|
||||
}
|
||||
if (res == EOF)
|
||||
return EXIT_SUCCESS;
|
||||
if (res != 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while (!(res = read_input_event(&ie) && (ie.type == EV_ABS) &&
|
||||
(ie.code == ABS_MT_TOOL_TYPE) &&
|
||||
(ie.value != MT_TOOL_PEN))) {
|
||||
if (rewrite_pen_event(&ie))
|
||||
forward_event(dev, &ie);
|
||||
};
|
||||
if (res != 0)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
FILE *dev;
|
||||
int res = setup(&dev);
|
||||
if (res) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
res = process_events(dev);
|
||||
cleanup(dev);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue