d3d11: Implement private data methods for ID3D11Texture3D.
[wine.git] / dlls / winejoystick.drv / joystick_linux.c
blobb8fda4f75294a46adf43eb6963860d9bf31507fe
1 /*
2 * joystick functions
4 * Copyright 1997 Andreas Mohr
5 * Copyright 2000 Wolfgang Schwotzer
6 * Copyright 2002 David Hagood
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * NOTES:
24 * - nearly all joystick functions can be regarded as obsolete,
25 * as Linux (2.1.x) now supports extended joysticks with a completely
26 * new joystick driver interface
27 * New driver's documentation says:
28 * "For backward compatibility the old interface is still included,
29 * but will be dropped in the future."
30 * Thus we should implement the new interface and at most keep the old
31 * routines for backward compatibility.
32 * - better support of enhanced joysticks (Linux 2.2 interface is available)
33 * - support more joystick drivers (like the XInput extension)
34 * - should load joystick DLL as any other driver (instead of hardcoding)
35 * the driver's name, and load it as any low lever driver.
38 #include "config.h"
39 #include "wine/port.h"
41 #ifdef HAVE_LINUX_JOYSTICK_H
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <fcntl.h>
50 #ifdef HAVE_SYS_IOCTL_H
51 #include <sys/ioctl.h>
52 #endif
53 #ifdef HAVE_LINUX_IOCTL_H
54 #include <linux/ioctl.h>
55 #endif
56 #include <linux/joystick.h>
57 #ifdef SW_MAX
58 #undef SW_MAX
59 #endif
60 #define JOYDEV_NEW "/dev/input/js%d"
61 #define JOYDEV_OLD "/dev/js%d"
62 #include <errno.h>
64 #include "joystick.h"
66 #include "wingdi.h"
67 #include "winnls.h"
68 #include "wine/debug.h"
70 #include "wine/unicode.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(joystick);
74 #define MAXJOYSTICK (JOYSTICKID2 + 30)
76 typedef struct tagWINE_JSTCK {
77 int joyIntf;
78 BOOL in_use;
79 /* Some extra info we need to make this actually work under the
80 Linux 2.2 event api.
81 First of all, we cannot keep closing and reopening the device file -
82 that blows away the state of the stick device, and we lose events. So, we
83 need to open the low-level device once, and close it when we are done.
85 Secondly, the event API only gives us what's changed. However, Windows apps
86 want the whole state every time, so we have to cache the data.
89 int dev; /* Linux level device file descriptor */
90 int x;
91 int y;
92 int z;
93 int r;
94 int u;
95 int v;
96 int pov_x;
97 int pov_y;
98 int buttons;
99 char axesMap[ABS_MAX + 1];
100 } WINE_JSTCK;
102 static WINE_JSTCK JSTCK_Data[MAXJOYSTICK];
104 /**************************************************************************
105 * JSTCK_drvGet [internal]
107 static WINE_JSTCK *JSTCK_drvGet(DWORD_PTR dwDevID)
109 int p;
111 if ((dwDevID - (DWORD_PTR)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0)
112 return NULL;
113 p = (dwDevID - (DWORD_PTR)JSTCK_Data) / sizeof(JSTCK_Data[0]);
114 if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use)
115 return NULL;
117 return (WINE_JSTCK*)dwDevID;
120 /**************************************************************************
121 * driver_open
123 LRESULT driver_open(LPSTR str, DWORD dwIntf)
125 if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use)
126 return 0;
128 JSTCK_Data[dwIntf].joyIntf = dwIntf;
129 JSTCK_Data[dwIntf].in_use = TRUE;
130 return (LRESULT)&JSTCK_Data[dwIntf];
133 /**************************************************************************
134 * driver_close
136 LRESULT driver_close(DWORD_PTR dwDevID)
138 WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID);
140 if (jstck == NULL)
141 return 0;
142 jstck->in_use = FALSE;
143 if (jstck->dev > 0)
145 close(jstck->dev);
146 jstck->dev = 0;
148 return 1;
151 struct js_status
153 int buttons;
154 int x;
155 int y;
158 /**************************************************************************
159 * JSTCK_OpenDevice [internal]
161 static int JSTCK_OpenDevice(WINE_JSTCK* jstick)
163 char buf[20];
164 int flags;
166 if (jstick->dev > 0)
167 return jstick->dev;
169 sprintf(buf, JOYDEV_NEW, jstick->joyIntf);
170 #ifdef HAVE_LINUX_22_JOYSTICK_API
171 flags = O_RDONLY | O_NONBLOCK;
172 #else
173 flags = O_RDONLY;
174 #endif
175 if ((jstick->dev = open(buf, flags)) < 0) {
176 sprintf(buf, JOYDEV_OLD, jstick->joyIntf);
177 if ((jstick->dev = open(buf, flags)) < 0)
178 return jstick->dev;
180 #ifdef HAVE_LINUX_22_JOYSTICK_API
181 ioctl(jstick->dev, JSIOCGAXMAP, jstick->axesMap);
182 #endif
183 return jstick->dev;
187 /**************************************************************************
188 * JoyGetDevCaps [MMSYSTEM.102]
190 LRESULT driver_joyGetDevCaps(DWORD_PTR dwDevID, LPJOYCAPSW lpCaps, DWORD dwSize)
192 WINE_JSTCK* jstck;
193 #ifdef HAVE_LINUX_22_JOYSTICK_API
194 int dev;
195 char nrOfAxes;
196 char nrOfButtons;
197 char identString[MAXPNAMELEN];
198 int i;
199 int driverVersion;
200 #else
201 static const WCHAR ini[] = {'W','i','n','e',' ','J','o','y','s','t','i','c','k',' ','D','r','i','v','e','r',0};
202 #endif
204 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
205 return MMSYSERR_NODRIVER;
207 #ifdef HAVE_LINUX_22_JOYSTICK_API
208 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
209 ioctl(dev, JSIOCGAXES, &nrOfAxes);
210 ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
211 ioctl(dev, JSIOCGVERSION, &driverVersion);
212 ioctl(dev, JSIOCGNAME(sizeof(identString)), identString);
213 TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
214 driverVersion, identString, nrOfAxes, nrOfButtons);
215 lpCaps->wMid = MM_MICROSOFT;
216 lpCaps->wPid = MM_PC_JOYSTICK;
217 MultiByteToWideChar(CP_UNIXCP, 0, identString, -1, lpCaps->szPname, MAXPNAMELEN);
218 lpCaps->szPname[MAXPNAMELEN-1] = '\0';
219 lpCaps->wXmin = 0;
220 lpCaps->wXmax = 0xFFFF;
221 lpCaps->wYmin = 0;
222 lpCaps->wYmax = 0xFFFF;
223 lpCaps->wZmin = 0;
224 lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
225 #ifdef BODGE_THE_HAT
226 /* Half-Life won't allow you to map an axis event to things like
227 "next weapon" and "use". Linux reports the hat on my stick as
228 axis U and V. So, IFF BODGE_THE_HAT is defined, lie through our
229 teeth and say we have 32 buttons, and we will map the axes to
230 the high buttons. Really, perhaps this should be a registry entry,
231 or even a parameter to the Linux joystick driver (which would completely
232 remove the need for this.)
234 lpCaps->wNumButtons = 32;
235 #else
236 lpCaps->wNumButtons = nrOfButtons;
237 #endif
238 if (dwSize == sizeof(JOYCAPSW)) {
239 /* complete 95 structure */
240 lpCaps->wRmin = 0;
241 lpCaps->wRmax = 0xFFFF;
242 lpCaps->wUmin = 0;
243 lpCaps->wUmax = 0xFFFF;
244 lpCaps->wVmin = 0;
245 lpCaps->wVmax = 0xFFFF;
246 lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
247 lpCaps->wNumAxes = 0; /* nr of axes in use */
248 lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
249 lpCaps->szRegKey[0] = 0;
250 lpCaps->szOEMVxD[0] = 0;
251 lpCaps->wCaps = 0;
252 for (i = 0; i < nrOfAxes; i++) {
253 switch (jstck->axesMap[i]) {
254 case 0: /* X */
255 case 1: /* Y */
256 lpCaps->wNumAxes++;
257 break;
258 case 2: /* Z */
259 case 6: /* Throttle */
260 lpCaps->wNumAxes++;
261 lpCaps->wCaps |= JOYCAPS_HASZ;
262 break;
263 case 5: /* Rz */
264 case 7: /* Rudder */
265 lpCaps->wNumAxes++;
266 lpCaps->wCaps |= JOYCAPS_HASR;
267 break;
268 case 3: /* Rx */
269 lpCaps->wNumAxes++;
270 lpCaps->wCaps |= JOYCAPS_HASU;
271 break;
272 case 4: /* Ry */
273 lpCaps->wNumAxes++;
274 lpCaps->wCaps |= JOYCAPS_HASV;
275 break;
276 case 16: /* Hat 0 X */
277 case 17: /* Hat 0 Y */
278 lpCaps->wCaps |= JOYCAPS_HASPOV | JOYCAPS_POV4DIR;
279 /* TODO: JOYCAPS_POVCTS handling */
280 break;
281 default:
282 WARN("Unknown axis %hhu(%u). Skipped.\n", jstck->axesMap[i], i);
286 #else
287 lpCaps->wMid = MM_MICROSOFT;
288 lpCaps->wPid = MM_PC_JOYSTICK;
289 strcpyW(lpCaps->szPname, ini); /* joystick product name */
290 lpCaps->wXmin = 0;
291 lpCaps->wXmax = 0xFFFF;
292 lpCaps->wYmin = 0;
293 lpCaps->wYmax = 0xFFFF;
294 lpCaps->wZmin = 0;
295 lpCaps->wZmax = 0;
296 lpCaps->wNumButtons = 2;
297 if (dwSize == sizeof(JOYCAPSW)) {
298 /* complete 95 structure */
299 lpCaps->wRmin = 0;
300 lpCaps->wRmax = 0;
301 lpCaps->wUmin = 0;
302 lpCaps->wUmax = 0;
303 lpCaps->wVmin = 0;
304 lpCaps->wVmax = 0;
305 lpCaps->wCaps = 0;
306 lpCaps->wMaxAxes = 2;
307 lpCaps->wNumAxes = 2;
308 lpCaps->wMaxButtons = 4;
309 lpCaps->szRegKey[0] = 0;
310 lpCaps->szOEMVxD[0] = 0;
312 #endif
314 return JOYERR_NOERROR;
317 /**************************************************************************
318 * driver_joyGetPos
320 LRESULT driver_joyGetPosEx(DWORD_PTR dwDevID, LPJOYINFOEX lpInfo)
322 WINE_JSTCK* jstck;
323 int dev;
324 #ifdef HAVE_LINUX_22_JOYSTICK_API
325 struct js_event ev;
326 #else
327 struct js_status js;
328 int dev_stat;
329 #endif
331 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
332 return MMSYSERR_NODRIVER;
334 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
336 #ifdef HAVE_LINUX_22_JOYSTICK_API
337 while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
338 if (ev.type == (JS_EVENT_AXIS)) {
339 switch (jstck->axesMap[ev.number]) {
340 case 0: /* X */
341 jstck->x = ev.value;
342 break;
343 case 1: /* Y */
344 jstck->y = ev.value;
345 break;
346 case 2: /* Z */
347 case 6: /* Throttle */
348 jstck->z = ev.value;
349 break;
350 case 5: /* Rz */
351 case 7: /* Rudder */
352 jstck->r = ev.value;
353 break;
354 case 3: /* Rx */
355 jstck->u = ev.value;
356 break;
357 case 4: /* Ry */
358 jstck->v = ev.value;
359 break;
360 case 16: /* Hat 0 X */
361 jstck->pov_x = ev.value;
362 break;
363 case 17: /* Hat 0 Y */
364 jstck->pov_y = ev.value;
365 break;
366 default:
367 FIXME("Unknown joystick event '%d'\n", ev.number);
369 } else if (ev.type == (JS_EVENT_BUTTON)) {
370 if (ev.value) {
371 jstck->buttons |= (1 << ev.number);
372 /* FIXME: what to do for this field when
373 * multiple buttons are depressed ?
375 if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
376 lpInfo->dwButtonNumber = ev.number + 1;
378 else
379 jstck->buttons &= ~(1 << ev.number);
382 /* EAGAIN is returned when the queue is empty */
383 if (errno != EAGAIN) {
384 /* FIXME: error should not be ignored */
385 ERR("Error while reading joystick state (%s)\n", strerror(errno));
387 /* Now, copy the cached values into Window's structure... */
388 if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
389 lpInfo->dwButtons = jstck->buttons;
390 if (lpInfo->dwFlags & JOY_RETURNX)
391 lpInfo->dwXpos = jstck->x + 32767;
392 if (lpInfo->dwFlags & JOY_RETURNY)
393 lpInfo->dwYpos = jstck->y + 32767;
394 if (lpInfo->dwFlags & JOY_RETURNZ)
395 lpInfo->dwZpos = jstck->z + 32767;
396 if (lpInfo->dwFlags & JOY_RETURNR)
397 lpInfo->dwRpos = jstck->r + 32767;
398 # ifdef BODGE_THE_HAT
399 else if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
401 if (jstck->r > 0)
402 lpInfo->dwButtons |= 1<<7;
403 else if (jstck->r < 0)
404 lpInfo->dwButtons |= 1<<8;
406 # endif
407 if (lpInfo->dwFlags & JOY_RETURNU)
408 lpInfo->dwUpos = jstck->u + 32767;
409 # ifdef BODGE_THE_HAT
410 else if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
412 if (jstck->u > 0)
413 lpInfo->dwButtons |= 1<<9;
414 else if (jstck->u < 0)
415 lpInfo->dwButtons |= 1<<10;
417 # endif
418 if (lpInfo->dwFlags & JOY_RETURNV)
419 lpInfo->dwVpos = jstck->v + 32767;
420 if (lpInfo->dwFlags & JOY_RETURNPOV) {
421 if (jstck->pov_y > 0) {
422 if (jstck->pov_x < 0)
423 lpInfo->dwPOV = 22500; /* SW */
424 else if (jstck->pov_x > 0)
425 lpInfo->dwPOV = 13500; /* SE */
426 else
427 lpInfo->dwPOV = 18000; /* S, JOY_POVBACKWARD */
428 } else if (jstck->pov_y < 0) {
429 if (jstck->pov_x < 0)
430 lpInfo->dwPOV = 31500; /* NW */
431 else if (jstck->pov_x > 0)
432 lpInfo->dwPOV = 4500; /* NE */
433 else
434 lpInfo->dwPOV = 0; /* N, JOY_POVFORWARD */
435 } else if (jstck->pov_x < 0)
436 lpInfo->dwPOV = 27000; /* W, JOY_POVLEFT */
437 else if (jstck->pov_x > 0)
438 lpInfo->dwPOV = 9000; /* E, JOY_POVRIGHT */
439 else
440 lpInfo->dwPOV = JOY_POVCENTERED; /* Center */
443 #else
444 dev_stat = read(dev, &js, sizeof(js));
445 if (dev_stat != sizeof(js)) {
446 return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
448 js.x = js.x<<8;
449 js.y = js.y<<8;
450 if (lpInfo->dwFlags & JOY_RETURNX)
451 lpInfo->dwXpos = js.x; /* FIXME: perhaps multiply it somehow ? */
452 if (lpInfo->dwFlags & JOY_RETURNY)
453 lpInfo->dwYpos = js.y;
454 if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
455 lpInfo->dwButtons = js.buttons;
456 #endif
458 TRACE("x: %d, y: %d, z: %d, r: %d, u: %d, v: %d, buttons: 0x%04x, flags: 0x%04x (fd %d)\n",
459 lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
460 lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
461 lpInfo->dwButtons, lpInfo->dwFlags, dev
464 return JOYERR_NOERROR;
467 /**************************************************************************
468 * driver_joyGetPos
470 LRESULT driver_joyGetPos(DWORD_PTR dwDevID, LPJOYINFO lpInfo)
472 JOYINFOEX ji;
473 LONG ret;
475 memset(&ji, 0, sizeof(ji));
477 ji.dwSize = sizeof(ji);
478 ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
479 ret = driver_joyGetPosEx(dwDevID, &ji);
480 if (ret == JOYERR_NOERROR) {
481 lpInfo->wXpos = ji.dwXpos;
482 lpInfo->wYpos = ji.dwYpos;
483 lpInfo->wZpos = ji.dwZpos;
484 lpInfo->wButtons = ji.dwButtons;
487 return ret;
490 #endif /* HAVE_LINUX_JOYSTICK_H */