| /* -*- tab-width: 8; c-basic-offset: 4 -*- */ |
| /* |
| * joystick functions |
| * |
| * Copyright 1997 Andreas Mohr |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library 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 |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * NOTES: |
| * |
| * nearly all joystick functions can be regarded as obsolete, |
| * as Linux (2.1.x) now supports extended joysticks |
| * with a completely new joystick driver interface |
| * new driver's docu says: |
| * "For backward compatibility the old interface is still included, |
| * but will be dropped in the future." |
| * Thus we should implement the new interface and at most keep the old |
| * routines for backward compatibility. |
| */ |
| |
| /* |
| * Wolfgang Schwotzer |
| * |
| * 01/2000 added support for new joystick driver |
| * |
| */ |
| |
| #include "config.h" |
| |
| #ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
| #endif |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #ifdef HAVE_SYS_IOCTL_H |
| #include <sys/ioctl.h> |
| #endif |
| #ifdef HAVE_LINUX_JOYSTICK_H |
| #include <linux/joystick.h> |
| #define JOYDEV "/dev/js%d" |
| #endif |
| #ifdef HAVE_SYS_ERRNO_H |
| #include <sys/errno.h> |
| #endif |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "mmddk.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(joystick); |
| |
| #ifdef HAVE_LINUX_JOYSTICK_H |
| |
| #define MAXJOYSTICK (JOYSTICKID2 + 1) |
| |
| typedef struct tagWINE_JSTCK { |
| int joyIntf; |
| int in_use; |
| } WINE_JSTCK; |
| |
| static WINE_JSTCK JSTCK_Data[MAXJOYSTICK]; |
| |
| /************************************************************************** |
| * JSTCK_drvGet [internal] |
| */ |
| static WINE_JSTCK* JSTCK_drvGet(DWORD dwDevID) |
| { |
| int p; |
| |
| if ((dwDevID - (DWORD)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0) |
| return NULL; |
| p = (dwDevID - (DWORD)JSTCK_Data) / sizeof(JSTCK_Data[0]); |
| if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use) |
| return NULL; |
| |
| return (WINE_JSTCK*)dwDevID; |
| } |
| |
| /************************************************************************** |
| * JSTCK_drvOpen [internal] |
| */ |
| static DWORD JSTCK_drvOpen(LPSTR str, DWORD dwIntf) |
| { |
| if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use) |
| return 0; |
| |
| JSTCK_Data[dwIntf].joyIntf = dwIntf; |
| JSTCK_Data[dwIntf].in_use = 1; |
| return (DWORD)&JSTCK_Data[dwIntf]; |
| } |
| |
| /************************************************************************** |
| * JSTCK_drvClose [internal] |
| */ |
| static DWORD JSTCK_drvClose(DWORD dwDevID) |
| { |
| WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID); |
| |
| if (jstck == NULL) |
| return 0; |
| jstck->in_use = 0; |
| return 1; |
| } |
| |
| struct js_status |
| { |
| int buttons; |
| int x; |
| int y; |
| }; |
| |
| /************************************************************************** |
| * JSTCK_OpenDevice [internal] |
| */ |
| static int JSTCK_OpenDevice(WINE_JSTCK* jstick) |
| { |
| char buf[20]; |
| int flags; |
| |
| sprintf(buf, JOYDEV, jstick->joyIntf); |
| #ifdef HAVE_LINUX_22_JOYSTICK_API |
| flags = O_RDONLY | O_NONBLOCK; |
| #else |
| flags = O_RDONLY; |
| #endif |
| return open(buf, flags); |
| } |
| |
| /************************************************************************** |
| * JoyGetDevCaps [MMSYSTEM.102] |
| */ |
| static LONG JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize) |
| { |
| WINE_JSTCK* jstck; |
| #ifdef HAVE_LINUX_22_JOYSTICK_API |
| int dev; |
| char nrOfAxes; |
| char nrOfButtons; |
| char identString[MAXPNAMELEN]; |
| int driverVersion; |
| #endif |
| |
| if ((jstck = JSTCK_drvGet(dwDevID)) == NULL) |
| return MMSYSERR_NODRIVER; |
| |
| #ifdef HAVE_LINUX_22_JOYSTICK_API |
| |
| if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS; |
| ioctl(dev, JSIOCGAXES, &nrOfAxes); |
| ioctl(dev, JSIOCGBUTTONS, &nrOfButtons); |
| ioctl(dev, JSIOCGVERSION, &driverVersion); |
| ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString); |
| TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n", |
| driverVersion, identString, nrOfAxes, nrOfButtons); |
| lpCaps->wMid = MM_MICROSOFT; |
| lpCaps->wPid = MM_PC_JOYSTICK; |
| strncpy(lpCaps->szPname, identString, MAXPNAMELEN); |
| lpCaps->szPname[MAXPNAMELEN-1] = '\0'; |
| lpCaps->wXmin = 0; |
| lpCaps->wXmax = 0xFFFF; |
| lpCaps->wYmin = 0; |
| lpCaps->wYmax = 0xFFFF; |
| lpCaps->wZmin = 0; |
| lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0; |
| lpCaps->wNumButtons = nrOfButtons; |
| if (dwSize == sizeof(JOYCAPSA)) { |
| /* since we suppose ntOfAxes <= 6 in the following code, do it explicitly */ |
| if (nrOfAxes > 6) nrOfAxes = 6; |
| /* complete 95 structure */ |
| lpCaps->wRmin = 0; |
| lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0; |
| lpCaps->wUmin = 0; |
| lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0; |
| lpCaps->wVmin = 0; |
| lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0; |
| lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */ |
| lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */ |
| lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */ |
| strcpy(lpCaps->szRegKey, ""); |
| strcpy(lpCaps->szOEMVxD, ""); |
| lpCaps->wCaps = 0; |
| switch(nrOfAxes) { |
| case 6: lpCaps->wCaps |= JOYCAPS_HASV; |
| case 5: lpCaps->wCaps |= JOYCAPS_HASU; |
| case 4: lpCaps->wCaps |= JOYCAPS_HASR; |
| case 3: lpCaps->wCaps |= JOYCAPS_HASZ; |
| /* FIXME: don't know how to detect for |
| JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */ |
| } |
| } |
| close(dev); |
| |
| #else |
| lpCaps->wMid = MM_MICROSOFT; |
| lpCaps->wPid = MM_PC_JOYSTICK; |
| strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */ |
| lpCaps->wXmin = 0; |
| lpCaps->wXmax = 0xFFFF; |
| lpCaps->wYmin = 0; |
| lpCaps->wYmax = 0xFFFF; |
| lpCaps->wZmin = 0; |
| lpCaps->wZmax = 0; |
| lpCaps->wNumButtons = 2; |
| if (dwSize == sizeof(JOYCAPSA)) { |
| /* complete 95 structure */ |
| lpCaps->wRmin = 0; |
| lpCaps->wRmax = 0; |
| lpCaps->wUmin = 0; |
| lpCaps->wUmax = 0; |
| lpCaps->wVmin = 0; |
| lpCaps->wVmax = 0; |
| lpCaps->wCaps = 0; |
| lpCaps->wMaxAxes = 2; |
| lpCaps->wNumAxes = 2; |
| lpCaps->wMaxButtons = 4; |
| strcpy(lpCaps->szRegKey,""); |
| strcpy(lpCaps->szOEMVxD,""); |
| } |
| #endif |
| |
| return JOYERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * JSTCK_GetPos [internal] |
| */ |
| static LONG JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo) |
| { |
| WINE_JSTCK* jstck; |
| int dev; |
| #ifdef HAVE_LINUX_22_JOYSTICK_API |
| struct js_event ev; |
| #else |
| struct js_status js; |
| int dev_stat; |
| #endif |
| |
| if ((jstck = JSTCK_drvGet(dwDevID)) == NULL) |
| return MMSYSERR_NODRIVER; |
| |
| if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS; |
| |
| #ifdef HAVE_LINUX_22_JOYSTICK_API |
| /* After opening the device, its state can be |
| read with JS_EVENT_INIT flag */ |
| while ((read(dev, &ev, sizeof(struct js_event))) > 0) { |
| if (ev.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) { |
| switch (ev.number) { |
| case 0: |
| if (lpInfo->dwFlags & JOY_RETURNX) |
| lpInfo->dwXpos = ev.value + 32767; |
| break; |
| case 1: |
| if (lpInfo->dwFlags & JOY_RETURNY) |
| lpInfo->dwYpos = ev.value + 32767; |
| break; |
| case 2: |
| if (lpInfo->dwFlags & JOY_RETURNZ) |
| lpInfo->dwZpos = ev.value + 32767; |
| break; |
| case 3: |
| if (lpInfo->dwFlags & JOY_RETURNR) |
| lpInfo->dwRpos = ev.value + 32767; |
| case 4: |
| if (lpInfo->dwFlags & JOY_RETURNU) |
| lpInfo->dwUpos = ev.value + 32767; |
| case 5: |
| if (lpInfo->dwFlags & JOY_RETURNV) |
| lpInfo->dwVpos = ev.value + 32767; |
| break; |
| default: |
| FIXME("Unknown joystick event '%d'\n", ev.number); |
| } |
| } else if (ev.type == (JS_EVENT_BUTTON | JS_EVENT_INIT)) { |
| if (lpInfo->dwFlags & JOY_RETURNBUTTONS) { |
| if (ev.value) { |
| lpInfo->dwButtons |= (1 << ev.number); |
| /* FIXME: what to do for this field when |
| * multiple buttons are depressed ? |
| */ |
| lpInfo->dwButtonNumber = ev.number + 1; |
| } |
| } |
| } |
| } |
| /* EAGAIN is returned when the queue is empty */ |
| if (errno != EAGAIN) { |
| /* FIXME: error should not be ignored */ |
| ERR("Error while reading joystick state (%s)\n", strerror(errno)); |
| } |
| #else |
| dev_stat = read(dev, &js, sizeof(js)); |
| if (dev_stat != sizeof(js)) { |
| close(dev); |
| return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */ |
| } |
| js.x = js.x<<8; |
| js.y = js.y<<8; |
| if (lpInfo->dwFlags & JOY_RETURNX) |
| lpInfo->dwXpos = js.x; /* FIXME: perhaps multiply it somehow ? */ |
| if (lpInfo->dwFlags & JOY_RETURNY) |
| lpInfo->dwYpos = js.y; |
| if (lpInfo->dwFlags & JOY_RETURNBUTTONS) |
| lpInfo->dwButtons = js.buttons; |
| #endif |
| |
| close(dev); |
| |
| TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n", |
| lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos, |
| lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos, |
| (unsigned int)lpInfo->dwButtons, |
| (unsigned int)lpInfo->dwFlags); |
| |
| return JOYERR_NOERROR; |
| } |
| |
| /************************************************************************** |
| * JSTCK_GetPos [internal] |
| */ |
| static LONG JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo) |
| { |
| JOYINFOEX ji; |
| LONG ret; |
| |
| memset(&ji, 0, sizeof(ji)); |
| |
| ji.dwSize = sizeof(ji); |
| ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS; |
| ret = JSTCK_GetPosEx(dwDevID, &ji); |
| if (ret == JOYERR_NOERROR) { |
| lpInfo->wXpos = ji.dwXpos; |
| lpInfo->wYpos = ji.dwYpos; |
| lpInfo->wZpos = ji.dwZpos; |
| lpInfo->wButtons = ji.dwButtons; |
| } |
| |
| return ret; |
| } |
| |
| /************************************************************************** |
| * DriverProc (JOYSTICK.@) |
| */ |
| LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, |
| DWORD dwParam1, DWORD dwParam2) |
| { |
| /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */ |
| /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */ |
| |
| switch(wMsg) { |
| case DRV_LOAD: return 1; |
| case DRV_FREE: return 1; |
| case DRV_OPEN: return JSTCK_drvOpen((LPSTR)dwParam1, dwParam2); |
| case DRV_CLOSE: return JSTCK_drvClose(dwDevID); |
| case DRV_ENABLE: return 1; |
| case DRV_DISABLE: return 1; |
| case DRV_QUERYCONFIGURE: return 1; |
| case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1; |
| case DRV_INSTALL: return DRVCNF_RESTART; |
| case DRV_REMOVE: return DRVCNF_RESTART; |
| |
| case JDD_GETNUMDEVS: return 1; |
| case JDD_GETDEVCAPS: return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2); |
| case JDD_GETPOS: return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1); |
| case JDD_SETCALIBRATION: |
| case JDD_CONFIGCHANGED: return JOYERR_NOCANDO; |
| case JDD_GETPOSEX: return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1); |
| default: |
| return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); |
| } |
| } |
| |
| #else |
| |
| /************************************************************************** |
| * DriverProc (JOYSTICK.@) |
| */ |
| LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, |
| DWORD dwParam1, DWORD dwParam2) |
| { |
| /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */ |
| /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */ |
| |
| switch(wMsg) { |
| case DRV_LOAD: |
| case DRV_FREE: |
| case DRV_OPEN: |
| case DRV_CLOSE: |
| case DRV_ENABLE: |
| case DRV_DISABLE: |
| case DRV_QUERYCONFIGURE: return 0; |
| case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1; |
| case DRV_INSTALL: return DRVCNF_RESTART; |
| case DRV_REMOVE: return DRVCNF_RESTART; |
| default: |
| return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); |
| } |
| } |
| |
| #endif |