1 /*****************************************************************************
4 ** Copyright (C) 2011 Stefan Seidel
6 ** This program is free software; you can redistribute it and/or
7 ** modify it under the terms of the GNU General Public License
8 ** as published by the Free Software Foundation; either version 2
9 ** of the License, or (at your option) any later version.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 ** Code inspired by wacdump.c from http://linuxwacom.sourceforge.net and
22 ** uniput-sample.c from http://thiemonge.org/getting-started-with-uinput
26 ** 0.1 - 2011-03-29 - initial support for "tpc" device
27 ** 0.2 - 2011-04-13 - support command-line options for device type, node, pressure
29 ****************************************************************************/
31 #include "wactablet.h"
32 #include "wacserial.h"
44 #include <linux/input.h>
45 #include <linux/uinput.h>
47 #define die(str, args...) do { \
48 perror(str, ## args); \
53 WACOMENGINE hEngine = NULL;
54 WACOMTABLET hTablet = NULL;
56 void wacom_report_event(__u16 type, __u16 code, __s32 value) {
57 struct input_event ev;
61 memset(&ev, 0, sizeof(struct input_event));
65 if (write(fd, &ev, sizeof(struct input_event)) < 0)
66 perror("error: write");
69 static void signal_handler(int signo) {
70 if (ioctl(fd, UI_DEV_DESTROY) < 0) {
71 die("error: cannot destroy uinput device\n");
74 WacomCloseTablet(hTablet);
75 WacomTermEngine(hEngine);
79 int main(int argc, char** argv) {
81 const char* devName = "tpc";
82 const char* devNode = "/dev/ttyS0";
83 struct uinput_user_dev uidev;
84 WACOMSTATE state = WACOMSTATE_INIT;
85 WACOMMODEL model = { 0 };
86 unsigned char uchBuf[64];
97 if (strcmp(arg, "-h") == 0) {
100 "Usage: wacom-input [-t DeviceType] [-d DeviceNode] [-p PressureThreshold]\n\t-t defaults to \"tpc\"\n\t-d defaults to \"/dev/ttyS0\"\n\t-p defaults to 40\n");
103 } else if (strcmp(arg, "-t") == 0) {
105 if (arg == NULL || arg[0] == '-') {
106 die("Missing device type");
110 } else if (strcmp(arg, "-d") == 0) {
112 if (arg == NULL || arg[0] == '-') {
113 die("Missing device node");
117 } else if (strcmp(arg, "-p") == 0) {
119 if (arg == NULL || (minPress = atoi(arg)) == 0) {
120 die("Wrong pressure threshold");
125 // end parse arguments
127 if (signal(SIGINT, signal_handler) == SIG_ERR) {
128 die("error registering signal handler\n");
131 // connect to wacom device
132 hEngine = WacomInitEngine();
135 die("failed to open tablet engine");
139 model.uClass = WACOMCLASS_SERIAL;
140 model.uDevice = WacomGetDeviceFromName(devName, model.uClass);
141 hTablet = WacomOpenTablet(hEngine, devNode, &model);
144 WacomTermEngine(hEngine);
145 die ("WacomOpenTablet");
147 WacomGetState(hTablet, &state);
148 // wacom device is set up properly
151 fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
153 fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK);
157 die("error: opening /dev/[input/]uinput failed");
159 // report that we have TOUCH events ...
160 if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
162 if (ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH) < 0)
165 // and absolute x, y, pressure data
166 if (ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0)
168 if (ioctl(fd, UI_SET_ABSBIT, ABS_X) < 0)
170 if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) < 0)
172 if (ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE) < 0)
175 // this is for simulated mouse middle/right button
176 // if(ioctl(fd, UI_SET_KEYBIT, BTN_MOUSE) < 0)
177 // die("error: ioctl");
178 // if(ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT) < 0)
179 // die("error: ioctl");
180 // if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
181 // die("error: ioctl");
183 // register uinput device
184 memset(&uidev, 0, sizeof(uidev));
185 uidev.absmin[ABS_X] = state.values[WACOMFIELD_POSITION_X].nMin;
186 uidev.absmax[ABS_X] = state.values[WACOMFIELD_POSITION_X].nMax;
187 uidev.absmin[ABS_Y] = state.values[WACOMFIELD_POSITION_Y].nMin;
188 uidev.absmax[ABS_Y] = state.values[WACOMFIELD_POSITION_Y].nMax;
189 uidev.absmin[ABS_PRESSURE] = state.values[WACOMFIELD_PRESSURE].nMin;
190 uidev.absmax[ABS_PRESSURE] = state.values[WACOMFIELD_PRESSURE].nMax;
191 // this could be more detailed, but in the end, who cares?
192 snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "wacom-input");
193 uidev.id.bustype = BUS_RS232;
194 uidev.id.vendor = 0x056a;
195 uidev.id.product = 0xffff;
196 uidev.id.version = 1;
198 if (write(fd, &uidev, sizeof(uidev)) < 0)
199 die("error: set virtual device info 1");
201 if (ioctl(fd, UI_DEV_CREATE) < 0)
202 die("error: create uinput device 1");
206 if ((nLength = WacomReadRaw(hTablet, uchBuf, sizeof(uchBuf))) < 0) {
209 if (WacomParseData(hTablet, uchBuf, nLength, &state)) {
212 if (!state.values[WACOMFIELD_PROXIMITY].nValue) {
213 // no tool in proximity
214 wacom_report_event(EV_ABS, ABS_PRESSURE, 0);
215 wacom_report_event(EV_KEY, BTN_TOUCH, 0);
216 // wacom_report_event(EV_KEY, BTN_RIGHT, 0);
217 // wacom_report_event(EV_KEY, BTN_MIDDLE, 0);
218 wacom_report_event(EV_SYN, SYN_REPORT, 0);
222 wacom_report_event(EV_ABS, ABS_X,
223 state.values[WACOMFIELD_POSITION_X].nValue);
224 wacom_report_event(EV_ABS, ABS_Y,
225 state.values[WACOMFIELD_POSITION_Y].nValue);
226 wacom_report_event(EV_ABS, ABS_PRESSURE,
227 state.values[WACOMFIELD_PRESSURE].nValue);
228 wacom_report_event(EV_KEY, BTN_TOUCH,
229 state.values[WACOMFIELD_PRESSURE].nValue > minPress);
230 // wacom_report_event(EV_KEY, BTN_RIGHT, state.values[WACOMFIELD_BUTTONS].nValue == WACOMBUTTON_STYLUS);
231 // wacom_report_event(EV_KEY, BTN_MIDDLE, state.values[WACOMFIELD_TOOLTYPE].nValue == WACOMTOOLTYPE_ERASER);
232 wacom_report_event(EV_SYN, SYN_REPORT, 0);
235 if (ioctl(fd, UI_DEV_DESTROY) < 0)