Implemented Win32 backend.
[umd.git] / src / umd.c
blob48069e77164da9aab02b3d22bf17f21352170e60
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 <string.h>
22 #include <stdio.h>
24 /*************************************
25 * LINUX HEADERS
26 *************************************/
27 #if defined(__linux) || defined(linux)
29 #include <time.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <linux/input.h>
35 #include <linux/uinput.h>
36 #include <unistd.h>
38 /*************************************
39 * WIN32 HEADERS
40 *************************************/
41 #elif defined(_WIN32) || defined(__WIN32__)
43 #define _WIN32_WINNT 0x0500
44 #include <windows.h>
46 /*************************************
47 * OSX HEADERS
48 *************************************/
49 #elif defined(__MACOSX__) || defined(__APPLE__)
51 #else
52 # error This library does not support your platform!
53 #endif
55 #define ERROR_LEN 256
56 static char error_buff[ERROR_LEN] = "";
58 #define SET_ERROR(message) \
59 { snprintf(error_buff, ERROR_LEN, "libumd error (%s:%d)\n\t%s", \
60 __FILE__, __LINE__ -1, message); }
62 const char *UMD_GetError()
64 return error_buff;
67 /*************************************
68 * LINUX DRIVER
69 *************************************/
70 #if defined(__linux) || defined(linux)
72 static int fd = -1;
73 static struct uinput_user_dev uidev;
74 static struct input_event event;
76 static char *dev_filename[] = {"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput", 0};
78 int UMD_Init()
80 int i;
81 unsigned int events[] = { EV_SYN, EV_KEY, EV_ABS, EV_REL, EV_MAX };
82 unsigned int keys[] = { BTN_MOUSE, BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, KEY_MAX };
83 unsigned int mouseabs[] = { ABS_X, ABS_Y, ABS_MAX };
84 unsigned int mouserel[] = { REL_X, REL_Y, REL_MAX };
86 for (i=0; dev_filename[i] != 0; i++) {
87 if ((fd = open(dev_filename[i], O_WRONLY)) >= 0)
88 break;
91 if (fd <= 0) {
92 switch (errno) {
93 case EACCES: case EROFS:
94 SET_ERROR("Could not open uinput device due to permissions");
95 break;
96 case ENODEV: case ENXIO: case ENOTDIR:
97 SET_ERROR("Could not find uinput device to open");
98 break;
99 default:
100 SET_ERROR("Could not open uinput device");
102 return -1;
105 memset(&event, 0, sizeof event);
107 memset(&uidev, 0, sizeof uidev);
108 snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "UMD Virtual Mouse (userspace driver)");
110 if (write(fd, &uidev, sizeof uidev) != sizeof uidev) {
111 SET_ERROR("Could not write to uinput device");
114 for (i=0; events[i] != EV_MAX; i++) {
115 if (ioctl(fd, UI_SET_EVBIT, events[i]) < 0) {
116 SET_ERROR("Could not set up uinput device");
117 close(fd);
121 for (i=0; keys[i] != KEY_MAX; i++) {
122 if (ioctl(fd, UI_SET_KEYBIT, keys[i]) < 0) {
123 SET_ERROR("Could not set up uinput device");
124 close(fd);
128 for (i=0; mouseabs[i] != ABS_MAX; i++) {
129 if (ioctl(fd, UI_SET_ABSBIT, mouseabs[i]) < 0) {
130 SET_ERROR("Could not set up uinput device");
131 close(fd);
135 for (i=0; mouserel[i] != REL_MAX; i++) {
136 if (ioctl(fd, UI_SET_RELBIT, mouserel[i]) < 0) {
137 SET_ERROR("Could not set up uinput device");
138 close(fd);
142 if (ioctl(fd, UI_DEV_CREATE, 0) < 0) {
143 SET_ERROR("Could not create uinput device");
144 close(fd);
145 return -1;
148 usleep(500 * 1000); // TODO: replace this with something more sensible
150 return 0;
153 int UMD_Quit()
155 if (fd <= 0) {
156 SET_ERROR("Could not quit, umd was not initialized");
157 return -1;
160 if (ioctl(fd, UI_DEV_DESTROY) != 0) {
161 SET_ERROR("Could not destroy virtual mouse device");
162 close(fd);
163 return -1;
166 close(fd);
168 return 0;
171 static int motion_event(unsigned int type, int x, int y)
173 unsigned int code_x, code_y;
174 if (type == EV_ABS) {
175 code_x = ABS_X;
176 code_y = ABS_Y;
178 else {
179 code_x = REL_X;
180 code_y = REL_Y;
183 gettimeofday(&event.time, NULL);
185 event.type = type;
186 event.code = code_x;
187 event.value = x;
188 if (write(fd, &event, sizeof event) != sizeof event)
189 return -1;
191 event.type = type;
192 event.code = code_y;
193 event.value = y;
194 if (write(fd, &event, sizeof event) != sizeof event)
195 return -1;
197 event.type = EV_SYN;
198 event.code = SYN_REPORT;
199 event.value = 0;
200 if (write(fd, &event, sizeof event) != sizeof event)
201 return -1;
203 return 0;
206 int UMD_Warp(int x, int y)
208 if (fd < 0) {
209 SET_ERROR("Could not warp mouse, umd was not initialized");
210 return -1;
213 if (motion_event(EV_ABS, x, y) < 0) {
214 SET_ERROR("Could not warp mouse");
215 return -1;
218 return 0;
221 int UMD_Move(int x, int y)
223 if (fd < 0) {
224 SET_ERROR("Could not move mouse, umd was not initialized");
225 return -1;
228 if (motion_event(EV_REL, x, y) < 0) {
229 SET_ERROR("Could not move mouse");
230 return -1;
233 return 0;
236 int UMD_Click(int button, int state)
238 unsigned int code;
240 switch(button) {
241 case UMD_LEFT:
242 code = BTN_LEFT;
243 break;
244 case UMD_RIGHT:
245 code = BTN_RIGHT;
246 break;
247 case UMD_MIDDLE:
248 code = BTN_MIDDLE;
249 break;
250 default:
251 SET_ERROR("Unrecognized mouse button in click");
252 return -1;
255 gettimeofday(&event.time, NULL);
257 event.type = EV_KEY;
258 event.code = code;
259 event.value = 1;
260 if (write(fd, &event, sizeof event) != sizeof event)
261 return -1;
263 event.type = EV_SYN;
264 event.code = SYN_REPORT;
265 event.value = state?1:0;
266 if (write(fd, &event, sizeof event) != sizeof event)
267 return -1;
269 return 0;
271 write_error:
272 SET_ERROR("Could not set position of virtual device");
273 close(fd);
274 return -1;
277 int UMD_ClickAt(int button, int state, int x, int y)
279 if (UMD_Warp(x, y) < 0)
280 return -1;
282 if (UMD_Click(button, state) < 0)
283 return -1;
285 return 0;
288 int UMD_SingleClick(int button)
290 if (UMD_Click(button, 1) < 0)
291 return -1;
293 if (UMD_Click(button, 0) < 0)
294 return -1;
296 return 0;
299 int UMD_SingleClickAt(int button, int x, int y)
301 if (UMD_ClickAt(button, 1, x, y) < 0)
302 return -1;
304 if (UMD_Click(button, 0) < 0)
305 return -1;
307 return 0;
310 /*************************************
311 * WIN32 DRIVER
312 *************************************/
313 #elif defined(_WIN32) || defined(__WIN32__)
315 int UMD_Init()
317 return 0;
320 int UMD_Quit()
322 return 0;
325 int UMD_Warp(int x, int y)
327 SetCursorPos(x, y);
329 return 0;
332 int UMD_Move(int x, int y)
334 POINT point;
336 if (GetCursorPos(&point) == 0) {
337 SET_ERROR("Could not get current cursor position to move");
338 return -1;
341 SetCursorPos(point.x + x, point.y + y);
343 return 0;
346 static int get_flags(int button, int state)
348 int flags = 0;
350 switch(button) {
351 case UMD_LEFT:
352 flags = state? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
353 break;
354 case UMD_RIGHT:
355 flags = state? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
356 break;
357 case UMD_MIDDLE:
358 flags = state? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
359 break;
360 default:
361 SET_ERROR("Unrecognized mouse button in click");
362 return 0;
365 return flags;
368 int UMD_Click(int button, int state)
370 INPUT input;
371 int flags = get_flags(button, state);
373 if (flags == 0)
374 return -1;
376 memset(&input, 0, sizeof input);
377 input.type = INPUT_MOUSE;
378 input.mi.dwFlags = flags;
380 if (SendInput(1, &input, sizeof input) != 1) {
381 SET_ERROR("Could not send click event");
382 return -1;
385 return 0;
388 int UMD_ClickAt(int button, int state, int x, int y)
390 INPUT input;
391 int flags = get_flags(button, state);
393 if (flags == 0)
394 return -1;
396 memset(&input, 0, sizeof input);
397 input.type = INPUT_MOUSE;
398 input.mi.dwFlags = flags | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
399 input.mi.dx = x;
400 input.mi.dy = y;
402 if (SendInput(1, &input, sizeof input) != 1) {
403 SET_ERROR("Could not send click at event");
404 return -1;
407 return 0;
410 int UMD_SingleClick(int button)
412 if (UMD_Click(button, 1) < 0)
413 return -1;
415 if (UMD_Click(button, 0) < 0)
416 return -1;
418 return 0;
421 int UMD_SingleClickAt(int button, int x, int y)
423 if (UMD_ClickAt(button, 1, x, y) < 0)
424 return -1;
426 if (UMD_Click(button, 0) < 0)
427 return -1;
429 return 0;
432 /*************************************
433 * OSX DRIVER
434 *************************************/
435 #elif defined(__MACOSX__) || defined(__APPLE__)
437 #endif