Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
m1k1o
GitHub Repository: m1k1o/neko
Path: blob/master/utils/xorg-deps/xf86-input-neko/src/neko.c
1007 views
1
/*
2
* (c) 2017 Martin Kepplinger <[email protected]>
3
* (c) 2007 Clement Chauplannaz, Thales e-Transactions <[email protected]>
4
* (c) 2006 Sascha Hauer, Pengutronix <[email protected]>
5
* (c) 2023 Miroslav Sedivy
6
*
7
* derived from the xf86-input-void driver
8
* Copyright 1999 by Frederic Lepied, France. <[email protected]>
9
*
10
* Permission to use, copy, modify, distribute, and sell this software and its
11
* documentation for any purpose is hereby granted without fee, provided that
12
* the above copyright notice appear in all copies and that both that
13
* copyright notice and this permission notice appear in supporting
14
* documentation, and that the name of Frederic Lepied not be used in
15
* advertising or publicity pertaining to distribution of the software without
16
* specific, written prior permission. Frederic Lepied makes no
17
* representations about the suitability of this software for any purpose. It
18
* is provided "as is" without express or implied warranty.
19
*
20
* FREDERIC LEPIED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22
* EVENT SHALL FREDERIC LEPIED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
24
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
25
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26
* PERFORMANCE OF THIS SOFTWARE.
27
*
28
* SPDX-License-Identifier: MIT
29
* License-Filename: COPYING
30
*/
31
32
/* neko input driver */
33
// https://www.x.org/releases/X11R7.7/doc/xorg-server/Xinput.html
34
35
#ifdef HAVE_CONFIG_H
36
#include "config.h"
37
#endif
38
39
#define DEF_SOCKET_NAME "/tmp/xf86-input-neko.sock"
40
#define BUFFER_SIZE 12
41
42
#include <stdio.h>
43
#include <stdio.h>
44
#include <sys/socket.h>
45
#include <sys/un.h>
46
#include <misc.h>
47
#include <xf86.h>
48
#if !defined(DGUX)
49
#include <xisb.h>
50
#endif
51
#include <xf86_OSproc.h>
52
#include <xf86Xinput.h>
53
#include <exevents.h> /* Needed for InitValuator/Proximity stuff */
54
#include <X11/keysym.h>
55
#include <mipointer.h>
56
#include <xserver-properties.h>
57
#include <pthread.h>
58
59
#define MAX_USED_VALUATORS 3 /* x, y, pressure */
60
#define TOUCH_MAX_SLOTS 10 /* max number of simultaneous touches */
61
62
struct neko_message
63
{
64
uint16_t type;
65
uint32_t touchId;
66
int32_t x;
67
int32_t y;
68
uint8_t pressure;
69
};
70
71
struct neko_priv
72
{
73
pthread_t thread;
74
/* config */
75
int height;
76
int width;
77
int pmax;
78
ValuatorMask *valuators;
79
uint16_t slots;
80
/* socket */
81
struct sockaddr_un addr;
82
int listen_socket;
83
char *socket_name;
84
};
85
86
// from binary representation to struct
87
static void
88
UnpackNekoMessage(struct neko_message *msg, unsigned char *buffer)
89
{
90
msg->type = buffer[0]; // TODO: use full 16bit type
91
msg->touchId = buffer[1] | (buffer[2] << 8); // TODO: use full 32bit touchId
92
msg->x = buffer[3] | (buffer[4] << 8) | (buffer[5] << 16) | (buffer[6] << 24);
93
msg->y = buffer[7] | (buffer[8] << 8) | (buffer[9] << 16) | (buffer[10] << 24);
94
msg->pressure = buffer[11];
95
}
96
97
static void
98
ReadInput(InputInfoPtr pInfo)
99
{
100
struct neko_priv *priv = (struct neko_priv *) (pInfo->private);
101
struct neko_message msg;
102
int ret;
103
104
int data_socket;
105
unsigned char buffer[BUFFER_SIZE];
106
107
for (;;)
108
{
109
/* Wait for incoming connection. */
110
data_socket = accept(priv->listen_socket, NULL, NULL);
111
112
/* Handle error conditions. */
113
if (data_socket == -1)
114
{
115
xf86IDrvMsg(pInfo, X_ERROR, "unable to accept connection\n");
116
break;
117
}
118
119
xf86IDrvMsg(pInfo, X_INFO, "accepted connection\n");
120
121
for(;;)
122
{
123
/* Wait for next data packet. */
124
ret = read(data_socket, buffer, BUFFER_SIZE);
125
126
/* Handle error conditions. */
127
if (ret == -1)
128
{
129
xf86IDrvMsg(pInfo, X_ERROR, "unable to read data\n");
130
break;
131
}
132
133
/* Connection closed by client. */
134
if (ret == 0)
135
{
136
xf86IDrvMsg(pInfo, X_INFO, "connection closed\n");
137
break;
138
}
139
140
/* Ensure message is long enough. */
141
if (ret != BUFFER_SIZE)
142
{
143
xf86IDrvMsg(pInfo, X_ERROR, "invalid message size\n");
144
break;
145
}
146
147
UnpackNekoMessage(&msg, buffer);
148
149
ValuatorMask *m = priv->valuators;
150
valuator_mask_zero(m);
151
152
// do not send valuators if x and y are -1
153
if (msg.x != -1 && msg.y != -1)
154
{
155
valuator_mask_set_double(m, 0, msg.x);
156
valuator_mask_set_double(m, 1, msg.y);
157
valuator_mask_set_double(m, 2, msg.pressure);
158
}
159
160
// TODO: extend to other types, such as keyboard and mouse
161
xf86PostTouchEvent(pInfo->dev, msg.touchId, msg.type, 0, m);
162
}
163
164
/* Close socket. */
165
close(data_socket);
166
167
xf86IDrvMsg(pInfo, X_INFO, "closed connection\n");
168
}
169
}
170
171
static void
172
PointerCtrl(__attribute__ ((unused)) DeviceIntPtr device,
173
__attribute__ ((unused)) PtrCtrl *ctrl)
174
{
175
}
176
177
static int
178
InitTouch(InputInfoPtr pInfo)
179
{
180
// custom private data
181
struct neko_priv *priv = pInfo->private;
182
183
const int nbtns = 11;
184
const int naxes = 3;
185
186
unsigned char map[nbtns + 1];
187
Atom btn_labels[nbtns];
188
Atom axis_labels[naxes];
189
190
// init button map
191
memset(map, 0, sizeof(map));
192
for (int i = 0; i < nbtns; i++)
193
{
194
map[i + 1] = i + 1;
195
}
196
197
// init btn_labels
198
memset(btn_labels, 0, ARRAY_SIZE(btn_labels) * sizeof(Atom));
199
btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
200
btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
201
btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
202
btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
203
btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
204
btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
205
btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
206
btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_SIDE);
207
btn_labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_EXTRA);
208
btn_labels[9] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD);
209
btn_labels[10] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK);
210
211
// init axis labels
212
memset(axis_labels, 0, ARRAY_SIZE(axis_labels) * sizeof(Atom));
213
axis_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_X);
214
axis_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y);
215
axis_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_PRESSURE);
216
217
/* initialize mouse emulation valuators */
218
if (InitPointerDeviceStruct((DevicePtr)pInfo->dev,
219
map,
220
nbtns, btn_labels,
221
PointerCtrl,
222
GetMotionHistorySize(),
223
naxes, axis_labels) == FALSE)
224
{
225
xf86IDrvMsg(pInfo, X_ERROR,
226
"unable to allocate PointerDeviceStruct\n");
227
return !Success;
228
}
229
230
/*
231
This function is provided to initialize an XAxisInfoRec, and should be
232
called for core and extension devices that have valuators. The space
233
for the XAxisInfoRec is allocated by the InitValuatorClassDeviceStruct
234
function, but is not initialized.
235
236
InitValuatorAxisStruct should be called once for each axis of motion
237
reported by the device. Each invocation should be passed the axis
238
number (starting with 0), the minimum value for that axis, the maximum
239
value for that axis, and the resolution of the device in counts per meter.
240
If the device reports relative motion, 0 should be reported as the
241
minimum and maximum values.
242
243
InitValuatorAxisStruct(dev, axnum, minval, maxval, resolution)
244
DeviceIntPtr dev;
245
int axnum;
246
int minval;
247
int maxval;
248
int resolution;
249
*/
250
xf86InitValuatorAxisStruct(pInfo->dev, 0,
251
XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_X),
252
0, /* min val */
253
priv->width - 1, /* max val */
254
priv->width, /* resolution */
255
0, /* min_res */
256
priv->width, /* max_res */
257
Absolute);
258
259
xf86InitValuatorAxisStruct(pInfo->dev, 1,
260
XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y),
261
0, /* min val */
262
priv->height - 1, /* max val */
263
priv->height, /* resolution */
264
0, /* min_res */
265
priv->height, /* max_res */
266
Absolute);
267
268
xf86InitValuatorAxisStruct(pInfo->dev, 2,
269
XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_PRESSURE),
270
0, /* min val */
271
priv->pmax, /* max val */
272
priv->pmax + 1, /* resolution */
273
0, /* min_res */
274
priv->pmax + 1, /* max_res */
275
Absolute);
276
277
/*
278
The mode field is either XIDirectTouch for direct−input touch devices
279
such as touchscreens or XIDependentTouch for indirect input devices such
280
as touchpads. For XIDirectTouch devices, touch events are sent to window
281
at the position the touch occured. For XIDependentTouch devices, touch
282
events are sent to the window at the position of the device's sprite.
283
284
The num_touches field defines the maximum number of simultaneous touches
285
the device supports. A num_touches of 0 means the maximum number of
286
simultaneous touches is undefined or unspecified. This field should be
287
used as a guide only, devices will lie about their capabilities.
288
*/
289
if (InitTouchClassDeviceStruct(pInfo->dev,
290
priv->slots,
291
XIDirectTouch,
292
naxes) == FALSE)
293
{
294
xf86IDrvMsg(pInfo, X_ERROR,
295
"unable to allocate TouchClassDeviceStruct\n");
296
return !Success;
297
}
298
299
return Success;
300
}
301
302
static int
303
DeviceControl(DeviceIntPtr device, int what)
304
{
305
// device pInfo
306
InputInfoPtr pInfo = device->public.devicePrivate;
307
// custom private data
308
struct neko_priv *priv = pInfo->private;
309
310
switch (what) {
311
case DEVICE_INIT:
312
device->public.on = FALSE;
313
314
if (InitTouch(pInfo) != Success)
315
{
316
xf86IDrvMsg(pInfo, X_ERROR, "unable to init touch\n");
317
return !Success;
318
}
319
break;
320
321
case DEVICE_ON:
322
xf86IDrvMsg(pInfo, X_INFO, "DEVICE ON\n");
323
device->public.on = TRUE;
324
325
if (priv->thread == 0)
326
{
327
/* start thread */
328
pthread_create(&priv->thread, NULL, (void *)ReadInput, pInfo);
329
}
330
break;
331
332
case DEVICE_OFF:
333
case DEVICE_CLOSE:
334
xf86IDrvMsg(pInfo, X_INFO, "DEVICE OFF\n");
335
device->public.on = FALSE;
336
break;
337
}
338
339
return Success;
340
}
341
342
static int
343
PreInit(__attribute__ ((unused)) InputDriverPtr drv,
344
InputInfoPtr pInfo,
345
__attribute__ ((unused)) int flags)
346
{
347
struct neko_priv *priv;
348
int ret;
349
350
priv = calloc(1, sizeof (struct neko_priv));
351
if (!priv)
352
{
353
xf86IDrvMsg(pInfo, X_ERROR, "%s: out of memory\n", __FUNCTION__);
354
return BadValue;
355
}
356
357
pInfo->type_name = (char*)XI_TOUCHSCREEN;
358
pInfo->device_control = DeviceControl;
359
pInfo->read_input = NULL;
360
pInfo->control_proc = NULL;
361
pInfo->switch_mode = NULL; /* Only support Absolute mode */
362
pInfo->private = priv;
363
pInfo->fd = -1;
364
365
/* get socket name from config */
366
priv->socket_name = xf86SetStrOption(pInfo->options, "SocketName", DEF_SOCKET_NAME);
367
368
/*
369
* In case the program exited inadvertently on the last run,
370
* remove the socket.
371
*/
372
373
unlink(priv->socket_name);
374
375
/* Create local socket. */
376
priv->listen_socket = socket(AF_UNIX, SOCK_STREAM, 0);
377
if (priv->listen_socket == -1)
378
{
379
xf86IDrvMsg(pInfo, X_ERROR, "unable to create socket\n");
380
return BadValue;
381
}
382
383
/*
384
* For portability clear the whole structure, since some
385
* implementations have additional (nonstandard) fields in
386
* the structure.
387
*/
388
389
memset(&priv->addr, 0, sizeof(struct sockaddr_un));
390
391
/* Bind socket to socket name. */
392
393
priv->addr.sun_family = AF_UNIX;
394
strncpy(priv->addr.sun_path, priv->socket_name, sizeof(priv->addr.sun_path) - 1);
395
396
ret = bind(priv->listen_socket, (const struct sockaddr *) &priv->addr, sizeof(struct sockaddr_un));
397
if (ret == -1)
398
{
399
xf86IDrvMsg(pInfo, X_ERROR, "unable to bind socket\n");
400
return BadValue;
401
}
402
403
/*
404
* Prepare for accepting connections. The backlog size is set
405
* to 5. So while one request is being processed other requests
406
* can be waiting.
407
*/
408
409
ret = listen(priv->listen_socket, 5);
410
if (ret == -1)
411
{
412
xf86IDrvMsg(pInfo, X_ERROR, "unable to listen on socket\n");
413
return BadValue;
414
}
415
416
/* process generic options */
417
xf86CollectInputOptions(pInfo, NULL);
418
xf86ProcessCommonOptions(pInfo, pInfo->options);
419
420
/* create valuators */
421
priv->valuators = valuator_mask_new(MAX_USED_VALUATORS);
422
if (!priv->valuators)
423
{
424
xf86IDrvMsg(pInfo, X_ERROR, "%s: out of memory\n", __FUNCTION__);
425
return BadValue;
426
}
427
428
priv->slots = TOUCH_MAX_SLOTS;
429
priv->width = 0xffff;
430
priv->height = 0xffff;
431
priv->pmax = 255;
432
priv->thread = 0;
433
434
/* Return the configured device */
435
return Success;
436
}
437
438
static void
439
UnInit(__attribute__ ((unused)) InputDriverPtr drv,
440
InputInfoPtr pInfo,
441
__attribute__ ((unused)) int flags)
442
{
443
struct neko_priv *priv = (struct neko_priv *)(pInfo->private);
444
445
/* close socket */
446
close(priv->listen_socket);
447
/* remove socket file */
448
unlink(priv->socket_name);
449
450
if (priv->thread)
451
{
452
/* cancel thread */
453
pthread_cancel(priv->thread);
454
/* wait for thread to finish */
455
pthread_join(priv->thread, NULL);
456
/* ensure thread is not cancelled again */
457
priv->thread = 0;
458
}
459
460
/* free valuators */
461
valuator_mask_free(&priv->valuators);
462
463
free(pInfo->private);
464
pInfo->private = NULL;
465
xf86DeleteInput(pInfo, 0);
466
}
467
468
/**
469
* X module information and plug / unplug routines
470
*/
471
472
_X_EXPORT InputDriverRec NEKO =
473
{
474
.driverVersion = 1,
475
.driverName = "neko",
476
.Identify = NULL,
477
.PreInit = PreInit,
478
.UnInit = UnInit,
479
.module = NULL
480
};
481
482
static pointer
483
Plug(pointer module,
484
__attribute__ ((unused)) pointer options,
485
__attribute__ ((unused)) int *errmaj,
486
__attribute__ ((unused)) int *errmin)
487
{
488
xf86AddInputDriver(&NEKO, module, 0);
489
return module;
490
}
491
492
static void
493
Unplug(__attribute__ ((unused)) pointer module)
494
{
495
}
496
497
static XF86ModuleVersionInfo versionRec =
498
{
499
.modname = "neko",
500
.vendor = MODULEVENDORSTRING,
501
._modinfo1_ = MODINFOSTRING1,
502
._modinfo2_ = MODINFOSTRING2,
503
.xf86version = XORG_VERSION_CURRENT,
504
.majorversion = PACKAGE_VERSION_MAJOR,
505
.minorversion = PACKAGE_VERSION_MINOR,
506
.patchlevel = PACKAGE_VERSION_PATCHLEVEL,
507
.abiclass = ABI_CLASS_XINPUT,
508
.abiversion = ABI_XINPUT_VERSION,
509
.moduleclass = MOD_CLASS_XINPUT,
510
.checksum = {0, 0, 0, 0} /* signature, to be patched into the file by a tool */
511
};
512
513
_X_EXPORT XF86ModuleData nekoModuleData =
514
{
515
.vers = &versionRec,
516
.setup = Plug,
517
.teardown = Unplug
518
};
519
520