-
Notifications
You must be signed in to change notification settings - Fork 0
/
vg_uinput.c
128 lines (109 loc) · 4.13 KB
/
vg_uinput.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
* rubusd - A deamon for communicating with Joy-Con devices
* Copyright (C) 2020 TechnoElf
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "vg_uinput.h"
#include "util.h"
#include <linux/uinput.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
struct input_event ui_event = {0};
#define VG_UI_CREATE_IOCTL(d, n, v) { if (ioctl(d->dev, n, v) < 0) { free(d); return VG_ERR; } }
VGUIDevice* vg_ui_create(uint16_t vid, uint16_t pid, const char* name) {
VGUIDevice* vg_ui = calloc(1, sizeof(VGUIDevice));
vg_ui->dev = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (vg_ui->dev < 0) {
free(vg_ui);
return VG_ERR;
}
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_EVBIT, EV_KEY);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_EVBIT, EV_ABS);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_EVBIT, EV_SYN);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_A);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_B);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_X);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_Y);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_LEFT);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_RIGHT);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_FORWARD);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_BACK);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_TL);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_TR);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_TL2);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_TR2);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_START);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_SELECT);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_MODE);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_EXTRA);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_THUMBL);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_KEYBIT, BTN_THUMBR);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_ABSBIT, ABS_HAT0X);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_ABSBIT, ABS_HAT0Y);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_ABSBIT, ABS_HAT1X);
VG_UI_CREATE_IOCTL(vg_ui, UI_SET_ABSBIT, ABS_HAT1Y);
struct uinput_abs_setup abs_config = {0};
abs_config.code = ABS_HAT0X;
abs_config.absinfo.minimum = INT8_MIN + 1;
abs_config.absinfo.maximum = INT8_MAX;
abs_config.absinfo.fuzz = 8;
abs_config.absinfo.flat = 16;
VG_UI_CREATE_IOCTL(vg_ui, UI_ABS_SETUP, &abs_config);
abs_config.code = ABS_HAT0Y;
VG_UI_CREATE_IOCTL(vg_ui, UI_ABS_SETUP, &abs_config);
abs_config.code = ABS_HAT1X;
VG_UI_CREATE_IOCTL(vg_ui, UI_ABS_SETUP, &abs_config);
abs_config.code = ABS_HAT1Y;
VG_UI_CREATE_IOCTL(vg_ui, UI_ABS_SETUP, &abs_config);
struct uinput_setup uinput_config = {0};
snprintf(uinput_config.name, UINPUT_MAX_NAME_SIZE, name);
uinput_config.id.bustype = BUS_BLUETOOTH;
uinput_config.id.vendor = vid;
uinput_config.id.product = pid;
uinput_config.id.version = 1;
VG_UI_CREATE_IOCTL(vg_ui, UI_DEV_SETUP, &uinput_config);
if (ioctl(vg_ui->dev, UI_DEV_CREATE) < 0) {
free(vg_ui);
return VG_ERR;
}
return vg_ui;
}
VG_RESULT vg_ui_destroy(VGUIDevice* vg_ui) {
VG_UI_TRY(ioctl(vg_ui->dev, UI_DEV_DESTROY));
free(vg_ui);
return VG_OK;
}
VG_RESULT vg_ui_button(uint16_t code, uint8_t val, VGUIDevice* vg_ui) {
ui_event.type = EV_KEY;
ui_event.code = code;
ui_event.value = val;
VG_UI_TRY(write(vg_ui->dev, &ui_event, sizeof(ui_event)));
return VG_OK;
}
VG_RESULT vg_ui_axis(uint16_t code, int8_t val, VGUIDevice* vg_ui) {
ui_event.type = EV_ABS;
ui_event.code = code;
ui_event.value = val;
VG_UI_TRY(write(vg_ui->dev, &ui_event, sizeof(ui_event)));
return VG_OK;
}
VG_RESULT vg_ui_flush(VGUIDevice* vg_ui) {
ui_event.type = EV_SYN;
ui_event.code = 0;
ui_event.value = 0;
VG_UI_TRY(write(vg_ui->dev, &ui_event, sizeof(ui_event)));
return VG_OK;
}