Made the source tree a little nicer, added some info for Fedora users.
[umd.git] / src / umd_linux.c
blob7988ce75fe1fdf21d487228317651604b28e17d1
1 /*************************************************************************
2 Copyright (C) 2009 Matthew Thompson <chameleonator@gmail.com>
4 This file is part of libumd.
6 libumd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 libumd 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 libumd. If not, see <http://www.gnu.org/licenses/>.
18 *************************************************************************/
20 #include "umd.h"
21 #include "umd_private.h"
23 #if defined(__linux) || defined(linux)
25 #include <time.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <linux/input.h>
31 #include <linux/uinput.h>
32 #include <unistd.h>
34 static int fd = -1;
35 static struct uinput_user_dev uidev;
36 static struct input_event event;
38 static char *dev_filename[] = {"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput", 0};
40 int UMD_Init()
42 int i;
43 unsigned int events[] = { EV_SYN, EV_KEY, EV_ABS, EV_REL, EV_MAX };
44 unsigned int keys[] = { BTN_MOUSE, BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, KEY_MAX };
45 unsigned int mouseabs[] = { ABS_X, ABS_Y, ABS_MAX };
46 unsigned int mouserel[] = { REL_X, REL_Y, REL_MAX };
48 for (i=0; dev_filename[i] != 0; i++) {
49 if ((fd = open(dev_filename[i], O_WRONLY)) >= 0)
50 break;
53 if (fd <= 0) {
54 switch (errno) {
55 case EACCES: case EROFS:
56 SET_ERROR("Could not open uinput device due to permissions");
57 break;
58 case ENODEV: case ENXIO: case ENOTDIR:
59 SET_ERROR("Could not find uinput device to open");
60 break;
61 default:
62 SET_ERROR("Could not open uinput device");
64 return -1;
67 memset(&event, 0, sizeof event);
69 memset(&uidev, 0, sizeof uidev);
70 snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "UMD Virtual Mouse (userspace driver)");
72 if (write(fd, &uidev, sizeof uidev) != sizeof uidev) {
73 SET_ERROR("Could not write to uinput device");
76 for (i=0; events[i] != EV_MAX; i++) {
77 if (ioctl(fd, UI_SET_EVBIT, events[i]) < 0) {
78 SET_ERROR("Could not set up uinput device");
79 close(fd);
83 for (i=0; keys[i] != KEY_MAX; i++) {
84 if (ioctl(fd, UI_SET_KEYBIT, keys[i]) < 0) {
85 SET_ERROR("Could not set up uinput device");
86 close(fd);
90 for (i=0; mouseabs[i] != ABS_MAX; i++) {
91 if (ioctl(fd, UI_SET_ABSBIT, mouseabs[i]) < 0) {
92 SET_ERROR("Could not set up uinput device");
93 close(fd);
97 for (i=0; mouserel[i] != REL_MAX; i++) {
98 if (ioctl(fd, UI_SET_RELBIT, mouserel[i]) < 0) {
99 SET_ERROR("Could not set up uinput device");
100 close(fd);
104 if (ioctl(fd, UI_DEV_CREATE, 0) < 0) {
105 SET_ERROR("Could not create uinput device");
106 close(fd);
107 return -1;
110 usleep(500 * 1000); // TODO: replace this with something more sensible
112 return 0;
115 int UMD_Quit()
117 if (fd <= 0) {
118 SET_ERROR("Could not quit, umd was not initialized");
119 return -1;
122 if (ioctl(fd, UI_DEV_DESTROY) != 0) {
123 SET_ERROR("Could not destroy virtual mouse device");
124 close(fd);
125 return -1;
128 close(fd);
130 return 0;
133 static int motion_event(unsigned int type, int x, int y)
135 unsigned int code_x, code_y;
136 if (type == EV_ABS) {
137 code_x = ABS_X;
138 code_y = ABS_Y;
140 else {
141 code_x = REL_X;
142 code_y = REL_Y;
145 gettimeofday(&event.time, NULL);
147 event.type = type;
148 event.code = code_x;
149 event.value = x;
150 if (write(fd, &event, sizeof event) != sizeof event)
151 return -1;
153 event.type = type;
154 event.code = code_y;
155 event.value = y;
156 if (write(fd, &event, sizeof event) != sizeof event)
157 return -1;
159 event.type = EV_SYN;
160 event.code = SYN_REPORT;
161 event.value = 0;
162 if (write(fd, &event, sizeof event) != sizeof event)
163 return -1;
165 return 0;
168 int UMD_Warp(int x, int y)
170 if (fd < 0) {
171 SET_ERROR("Could not warp mouse, umd was not initialized");
172 return -1;
175 if (motion_event(EV_ABS, x, y) < 0) {
176 SET_ERROR("Could not warp mouse");
177 return -1;
180 return 0;
183 int UMD_Move(int x, int y)
185 if (fd < 0) {
186 SET_ERROR("Could not move mouse, umd was not initialized");
187 return -1;
190 if (motion_event(EV_REL, x, y) < 0) {
191 SET_ERROR("Could not move mouse");
192 return -1;
195 return 0;
198 int UMD_Click(int button, int state)
200 unsigned int code;
202 switch(button) {
203 case UMD_LEFT:
204 code = BTN_LEFT;
205 break;
206 case UMD_RIGHT:
207 code = BTN_RIGHT;
208 break;
209 case UMD_MIDDLE:
210 code = BTN_MIDDLE;
211 break;
212 default:
213 SET_ERROR("Unrecognized mouse button in click");
214 return -1;
217 gettimeofday(&event.time, NULL);
219 event.type = EV_KEY;
220 event.code = code;
221 event.value = 1;
222 if (write(fd, &event, sizeof event) != sizeof event)
223 return -1;
225 event.type = EV_SYN;
226 event.code = SYN_REPORT;
227 event.value = state?1:0;
228 if (write(fd, &event, sizeof event) != sizeof event)
229 return -1;
231 return 0;
233 write_error:
234 SET_ERROR("Could not set position of virtual device");
235 close(fd);
236 return -1;
239 int UMD_ClickAt(int button, int state, int x, int y)
241 if (UMD_Warp(x, y) < 0)
242 return -1;
244 if (UMD_Click(button, state) < 0)
245 return -1;
247 return 0;
250 int UMD_SingleClick(int button)
252 if (UMD_Click(button, 1) < 0)
253 return -1;
255 if (UMD_Click(button, 0) < 0)
256 return -1;
258 return 0;
261 int UMD_SingleClickAt(int button, int x, int y)
263 if (UMD_ClickAt(button, 1, x, y) < 0)
264 return -1;
266 if (UMD_Click(button, 0) < 0)
267 return -1;
269 return 0;
272 #endif