1
0
Fork 0
mirror of https://github.com/rfc2822/GfxTablet synced 2025-10-03 09:39:16 +02:00
GfxTablet/driver-uinput/networktablet.cxx
Thomas Castleman a0e9f07203 several additions
* added new make rules
   * debug : for debugging versions
   * uninstall : to uninstall for the user
   * portable : make a more portable, 64-bit version

* added support for a sort of "buffer" so less pressure is needed to register a click
2019-09-03 23:51:06 -04:00

230 lines
6.4 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <arpa/inet.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <stdint.h>
#include <sstream>
#include "protocol.h"
#define die(str, args...) { \
perror(str); \
exit(EXIT_FAILURE); \
}
using namespace std;
int udp_socket;
void init_device(int fd)
{
// enable synchronization
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0)
die("error: ioctl UI_SET_EVBIT EV_SYN");
// enable 1 button
if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
die("error: ioctl UI_SET_EVBIT EV_KEY");
if (ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH) < 0)
die("error: ioctl UI_SET_KEYBIT");
if (ioctl(fd, UI_SET_KEYBIT, BTN_TOOL_PEN) < 0)
die("error: ioctl UI_SET_KEYBIT");
if (ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS) < 0)
die("error: ioctl UI_SET_KEYBIT");
if (ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS2) < 0)
die("error: ioctl UI_SET_KEYBIT");
// enable 2 main axes + pressure (absolute positioning)
if (ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0)
die("error: ioctl UI_SET_EVBIT EV_ABS");
if (ioctl(fd, UI_SET_ABSBIT, ABS_X) < 0)
die("error: ioctl UI_SETEVBIT ABS_X");
if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) < 0)
die("error: ioctl UI_SETEVBIT ABS_Y");
if (ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE) < 0)
die("error: ioctl UI_SETEVBIT ABS_PRESSURE");
{
struct uinput_abs_setup abs_setup;
struct uinput_setup setup;
memset(&abs_setup, 0, sizeof(abs_setup));
abs_setup.code = ABS_X;
abs_setup.absinfo.value = 0;
abs_setup.absinfo.minimum = 0;
abs_setup.absinfo.maximum = UINT16_MAX;
abs_setup.absinfo.fuzz = 0;
abs_setup.absinfo.flat = 0;
abs_setup.absinfo.resolution = 400;
if (ioctl(fd, UI_ABS_SETUP, &abs_setup) < 0)
die("error: UI_ABS_SETUP ABS_X");
memset(&abs_setup, 0, sizeof(abs_setup));
abs_setup.code = ABS_Y;
abs_setup.absinfo.value = 0;
abs_setup.absinfo.minimum = 0;
abs_setup.absinfo.maximum = UINT16_MAX;
abs_setup.absinfo.fuzz = 0;
abs_setup.absinfo.flat = 0;
abs_setup.absinfo.resolution = 400;
if (ioctl(fd, UI_ABS_SETUP, &abs_setup) < 0)
die("error: UI_ABS_SETUP ABS_Y");
memset(&abs_setup, 0, sizeof(abs_setup));
abs_setup.code = ABS_PRESSURE;
abs_setup.absinfo.value = 0;
abs_setup.absinfo.minimum = 0;
abs_setup.absinfo.maximum = INT16_MAX;
abs_setup.absinfo.fuzz = 0;
abs_setup.absinfo.flat = 0;
abs_setup.absinfo.resolution = 0;
if (ioctl(fd, UI_ABS_SETUP, &abs_setup) < 0)
die("error: UI_ABS_SETUP ABS_PRESSURE");
memset(&setup, 0, sizeof(setup));
snprintf(setup.name, UINPUT_MAX_NAME_SIZE, "Network Tablet");
setup.id.bustype = BUS_VIRTUAL;
setup.id.vendor = 0x1;
setup.id.product = 0x1;
setup.id.version = 2;
setup.ff_effects_max = 0;
if (ioctl(fd, UI_DEV_SETUP, &setup) < 0)
die("error: UI_DEV_SETUP");
if (ioctl(fd, UI_DEV_CREATE) < 0)
die("error: ioctl");
}
}
int prepare_socket()
{
int s;
struct sockaddr_in addr;
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("error: prepare_socket()");
bzero(&addr, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(GFXTABLET_PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
die("error: prepare_socket()");
return s;
}
void send_event(int device, int type, int code, int value)
{
struct input_event ev;
ev.type = type;
ev.code = code;
ev.value = value;
if (write(device, &ev, sizeof(ev)) < 0)
die("error: write()");
}
void quit(int signal) {
close(udp_socket);
}
int ConvertToInt(string &convert)
{
stringstream sti(convert);
int output;
sti >> output;
return output;
}
int main(int argc, char **argv)
{
int device;
struct event_packet ev_pkt;
//add a sort of "cushion" so that less pressure is required to register as
//a click and drag
string cushion_string = "";
int cushion = 0;
if (argc == 2)
{
cushion_string = argv[1];
cushion = ConvertToInt(cushion_string);
}
if ((device = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0)
die("error: open");
init_device(device);
udp_socket = prepare_socket();
printf("GfxTablet driver (protocol version %u) is ready and listening on 0.0.0.0:%u (UDP)\n"
"Hint: Make sure that this port is not blocked by your firewall.\n", PROTOCOL_VERSION, GFXTABLET_PORT);
signal(SIGINT, quit);
signal(SIGTERM, quit);
while (recv(udp_socket, &ev_pkt, sizeof(ev_pkt), 0) >= 9) { // every packet has at least 9 bytes
printf("."); fflush(0);
if (memcmp(ev_pkt.signature, "GfxTablet", 9) != 0) {
fprintf(stderr, "\nGot unknown packet on port %i, ignoring\n", GFXTABLET_PORT);
continue;
}
ev_pkt.version = ntohs(ev_pkt.version);
if (ev_pkt.version != PROTOCOL_VERSION) {
fprintf(stderr, "\nGfxTablet app speaks protocol version %i but driver speaks version %i, please update\n",
ev_pkt.version, PROTOCOL_VERSION);
break;
}
ev_pkt.x = ntohs(ev_pkt.x);
ev_pkt.y = ntohs(ev_pkt.y);
ev_pkt.pressure = ntohs(ev_pkt.pressure) + cushion;
printf("x: %hu, y: %hu, pressure: %hu\n", ev_pkt.x, ev_pkt.y, ev_pkt.pressure);
send_event(device, EV_ABS, ABS_X, ev_pkt.x);
send_event(device, EV_ABS, ABS_Y, ev_pkt.y);
send_event(device, EV_ABS, ABS_PRESSURE, ev_pkt.pressure);
switch (ev_pkt.type) {
case EVENT_TYPE_MOTION:
send_event(device, EV_SYN, SYN_REPORT, 1);
break;
case EVENT_TYPE_BUTTON:
// stylus hovering
if (ev_pkt.button == -1)
send_event(device, EV_KEY, BTN_TOOL_PEN, ev_pkt.down);
// stylus touching
if (ev_pkt.button == 0)
send_event(device, EV_KEY, BTN_TOUCH, ev_pkt.down);
// button 1
if (ev_pkt.button == 1)
send_event(device, EV_KEY, BTN_STYLUS, ev_pkt.down);
// button 2
if (ev_pkt.button == 2)
send_event(device, EV_KEY, BTN_STYLUS2, ev_pkt.down);
printf("sent button: %hhi, %hhu\n", ev_pkt.button, ev_pkt.down);
send_event(device, EV_SYN, SYN_REPORT, 1);
break;
}
}
close(udp_socket);
printf("Removing network tablet from device list\n");
ioctl(device, UI_DEV_DESTROY);
close(device);
printf("GfxTablet driver shut down gracefully\n");
return 0;
}