Rewrite kobo color inputs

This commit is contained in:
mae 2024-11-10 00:08:01 +01:00
parent 27f18d0a45
commit 83ba5981cc
6 changed files with 287 additions and 9 deletions

View file

@ -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)

View file

@ -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
View 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
View file

@ -0,0 +1,5 @@
#pragma once
#include <stdio.h>
int setup(FILE **dev);
int cleanup(FILE *dev);

17
src/logger.h Normal file
View 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)

View file

@ -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;
}