⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 joystick_linux.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 4 页
字号:
/*		DirectInput Joystick device
 *
 * Copyright 1998 Marcus Meissner
 * Copyright 1998,1999 Lionel Ulmer
 * Copyright 2000-2001 TransGaming Technologies Inc.
 *
 * 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
 */

/*
 * To Do:
 *	dead zone
 *	force feedback
 */

#include "config.h"
#include "wine/port.h"

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/fcntl.h>
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#include <errno.h>
#ifdef HAVE_SYS_ERRNO_H
# include <sys/errno.h>
#endif
#ifdef HAVE_LINUX_IOCTL_H
# include <linux/ioctl.h>
#endif
#ifdef HAVE_LINUX_JOYSTICK_H
# include <linux/joystick.h>
#endif

#include "wine/debug.h"
#include "wine/unicode.h"
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
#include "dinput.h"

#include "dinput_private.h"
#include "device_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(dinput);

#ifdef HAVE_LINUX_22_JOYSTICK_API

#define JOYDEV "/dev/js"

typedef struct {
    LONG lMin;
    LONG lMax;
    LONG lDeadZone;
    LONG lSaturation;
} ObjProps;

typedef struct {
    LONG lX;
    LONG lY;
} POV;

typedef struct JoystickImpl JoystickImpl;
static const IDirectInputDevice8AVtbl JoystickAvt;
static const IDirectInputDevice8WVtbl JoystickWvt;
struct JoystickImpl
{
        const void                     *lpVtbl;
        LONG                            ref;
        GUID                            guid;
	char				dev[32];

	/* The 'parent' DInput */
	IDirectInputImpl               *dinput;

	/* joystick private */
	int				joyfd;
	DIJOYSTATE2			js;		/* wine data */
	LPDIDATAFORMAT			user_df;	/* user defined format */
	DataFormat			*transform;	/* wine to user format converter */
	int				*offsets;	/* object offsets */
	ObjProps			*props;
        HANDLE				hEvent;
        LPDIDEVICEOBJECTDATA 		data_queue;
        int				queue_head, queue_tail, queue_len;
	BOOL				acquired;
	char				*name;
	DIDEVCAPS			devcaps;
	LONG				deadzone;
	int				*axis_map;
	int				axes;
	int				buttons;
	POV				povs[4];
	CRITICAL_SECTION		crit;
	BOOL				overflow;
};

static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
  0x9e573ed9,
  0x7734,
  0x11d2,
  {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
};

static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps)
{
    TRACE("dwSize: %ld\n", lpDIDevCaps->dwSize);
    TRACE("dwFlags: %08lx\n",lpDIDevCaps->dwFlags);
    TRACE("dwDevType: %08lx %s\n", lpDIDevCaps->dwDevType,
          lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" :
          lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" :
          lpDIDevCaps->dwDevType == DIDEVTYPE_MOUSE ? "DIDEVTYPE_MOUSE" :
          lpDIDevCaps->dwDevType == DIDEVTYPE_KEYBOARD ? "DIDEVTYPE_KEYBOARD" :
          lpDIDevCaps->dwDevType == DIDEVTYPE_JOYSTICK ? "DIDEVTYPE_JOYSTICK" :
          lpDIDevCaps->dwDevType == DIDEVTYPE_HID ? "DIDEVTYPE_HID" : "UNKNOWN");
    TRACE("dwAxes: %ld\n",lpDIDevCaps->dwAxes);
    TRACE("dwButtons: %ld\n",lpDIDevCaps->dwButtons);
    TRACE("dwPOVs: %ld\n",lpDIDevCaps->dwPOVs);
    if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) {
        TRACE("dwFFSamplePeriod: %ld\n",lpDIDevCaps->dwFFSamplePeriod);
        TRACE("dwFFMinTimeResolution: %ld\n",lpDIDevCaps->dwFFMinTimeResolution);
        TRACE("dwFirmwareRevision: %ld\n",lpDIDevCaps->dwFirmwareRevision);
        TRACE("dwHardwareRevision: %ld\n",lpDIDevCaps->dwHardwareRevision);
        TRACE("dwFFDriverVersion: %ld\n",lpDIDevCaps->dwFFDriverVersion);
    }
}

static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
{
    int fd = -1;
    char dev[32];

    if (dwFlags & DIEDFL_FORCEFEEDBACK) {
        WARN("force feedback not supported\n");
        return FALSE;
    }

    if ((dwDevType == 0) ||
	((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
	(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
        /* check whether we have a joystick */
        sprintf(dev, "%s%d", JOYDEV, id);
        if ((fd = open(dev,O_RDONLY)) < 0) {
            WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno));
            return FALSE;
        }

        /* Return joystick */
        lpddi->guidInstance = DInput_Wine_Joystick_GUID;
        lpddi->guidInstance.Data3 = id;
        lpddi->guidProduct = DInput_Wine_Joystick_GUID;
        /* we only support traditional joysticks for now */
        if (version >= 0x0800)
            lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
        else
            lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
        sprintf(lpddi->tszInstanceName, "Joystick %d", id);
#if defined(JSIOCGNAME)
        if (ioctl(fd,JSIOCGNAME(sizeof(lpddi->tszProductName)),lpddi->tszProductName) < 0) {
            WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno));
            strcpy(lpddi->tszProductName, "Wine Joystick");
        }
#else
        strcpy(lpddi->tszProductName, "Wine Joystick");
#endif

        lpddi->guidFFDriver = GUID_NULL;
        close(fd);
        TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev, lpddi->tszProductName);
        return TRUE;
    }

    return FALSE;
}

static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
{
    int fd = -1;
    char name[MAX_PATH];
    char dev[32];
    char friendly[32];

    if (dwFlags & DIEDFL_FORCEFEEDBACK) {
        WARN("force feedback not supported\n");
        return FALSE;
    }

    if ((dwDevType == 0) ||
	((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
	(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
        /* check whether we have a joystick */
        sprintf(dev, "%s%d", JOYDEV, id);
        if ((fd = open(dev,O_RDONLY)) < 0) {
            WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno));
            return FALSE;
        }

        /* Return joystick */
        lpddi->guidInstance = DInput_Wine_Joystick_GUID;
        lpddi->guidInstance.Data3 = id;
        lpddi->guidProduct = DInput_Wine_Joystick_GUID;
        /* we only support traditional joysticks for now */
        if (version >= 0x0800)
            lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
        else
            lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
        sprintf(friendly, "Joystick %d", id);
        MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
#if defined(JSIOCGNAME)
        if (ioctl(fd,JSIOCGNAME(sizeof(name)),name) < 0) {
            WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno));
            strcpy(name, "Wine Joystick");
        }
#else
        strcpy(name, "Wine Joystick");
#endif
        MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
        lpddi->guidFFDriver = GUID_NULL;
        close(fd);
        TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev,name);
        return TRUE;
    }

    return FALSE;
}

/*
 * Get a config key from either the app-specific or the default config
 */

inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
                                    char *buffer, DWORD size )
{
    if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size ))
        return 0;

    if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size ))
        return 0;

    return ERROR_FILE_NOT_FOUND;
}

/*
 * Setup the dinput options.
 */

static HRESULT setup_dinput_options(JoystickImpl * device)
{
    char buffer[MAX_PATH+16];
    HKEY hkey, appkey = 0;
    DWORD len;

    buffer[MAX_PATH]='\0';

    /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
    if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\DirectInput", &hkey)) hkey = 0;

    len = GetModuleFileNameA( 0, buffer, MAX_PATH );
    if (len && len < MAX_PATH) {
        HKEY tmpkey;
        /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
        if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
        {
            char *p, *appname = buffer;
            if ((p = strrchr( appname, '/' ))) appname = p + 1;
            if ((p = strrchr( appname, '\\' ))) appname = p + 1;
            strcat( appname, "\\DirectInput" );
            if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
            RegCloseKey( tmpkey );
        }
    }

    /* get options */

    if (!get_config_key( hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH )) {
        device->deadzone = atoi(buffer);
        TRACE("setting default deadzone to: \"%s\" %ld\n", buffer, device->deadzone);
    }

    if (!get_config_key( hkey, appkey, device->name, buffer, MAX_PATH )) {
        int tokens = 0;
        int axis = 0;
        int pov = 0;
        const char *delim = ",";
        char * ptr;
        TRACE("\"%s\" = \"%s\"\n", device->name, buffer);

        device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int));
        if (device->axis_map == 0)
            return DIERR_OUTOFMEMORY;

        if ((ptr = strtok(buffer, delim)) != NULL) {
            do {
                if (strcmp(ptr, "X") == 0) {
                    device->axis_map[tokens] = 0;
                    axis++;
                } else if (strcmp(ptr, "Y") == 0) {
                    device->axis_map[tokens] = 1;
                    axis++;
                } else if (strcmp(ptr, "Z") == 0) {
                    device->axis_map[tokens] = 2;
                    axis++;
                } else if (strcmp(ptr, "Rx") == 0) {
                    device->axis_map[tokens] = 3;
                    axis++;
                } else if (strcmp(ptr, "Ry") == 0) {
                    device->axis_map[tokens] = 4;
                    axis++;
                } else if (strcmp(ptr, "Rz") == 0) {
                    device->axis_map[tokens] = 5;
                    axis++;
                } else if (strcmp(ptr, "Slider1") == 0) {
                    device->axis_map[tokens] = 6;
                    axis++;
                } else if (strcmp(ptr, "Slider2") == 0) {
                    device->axis_map[tokens] = 7;
                    axis++;
                } else if (strcmp(ptr, "POV1") == 0) {
                    device->axis_map[tokens++] = 8;
                    device->axis_map[tokens] = 8;
                    pov++;
                } else if (strcmp(ptr, "POV2") == 0) {
                    device->axis_map[tokens++] = 9;
                    device->axis_map[tokens] = 9;
                    pov++;
                } else if (strcmp(ptr, "POV3") == 0) {
                    device->axis_map[tokens++] = 10;
                    device->axis_map[tokens] = 10;
                    pov++;
                } else if (strcmp(ptr, "POV4") == 0) {
                    device->axis_map[tokens++] = 11;
                    device->axis_map[tokens] = 11;
                    pov++;
                } else {
                    ERR("invalid joystick axis type: %s\n", ptr);
                    device->axis_map[tokens] = tokens;
                    axis++;
                }

                tokens++;
            } while ((ptr = strtok(NULL, delim)) != NULL);

            if (tokens != device->devcaps.dwAxes) {
                ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device->axes, axis, pov,tokens);
                while (tokens < device->axes) {
                    device->axis_map[tokens] = tokens;
                    tokens++;
                }
            }
        }

        device->devcaps.dwAxes = axis;
        device->devcaps.dwPOVs = pov;
    }

    if (appkey)
        RegCloseKey( appkey );

    if (hkey)
        RegCloseKey( hkey );

    return DI_OK;
}

static void calculate_ids(JoystickImpl* device)
{
    int i;
    int axis = 0;
    int button = 0;
    int pov = 0;
    int axis_base;
    int pov_base;
    int button_base;

    /* Make two passes over the format. The first counts the number
     * for each type and the second sets the id */
    for (i = 0; i < device->user_df->dwNumObjs; i++) {
        if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS)
            axis++;
        else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV)
            pov++;
        else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON)
            button++;
    }

    axis_base = 0;
    pov_base = axis;
    button_base = axis + pov;

    axis = 0;
    button = 0;
    pov = 0;

    for (i = 0; i < device->user_df->dwNumObjs; i++) {
        DWORD type = 0;
        if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) {
            axis++;
            type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) |
                DIDFT_MAKEINSTANCE(axis + axis_base);
            TRACE("axis type = 0x%08lx\n", type);
        } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) {
            pov++;
            type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) |
                DIDFT_MAKEINSTANCE(pov + pov_base);
            TRACE("POV type = 0x%08lx\n", type);
        } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) {
            button++;
            type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) |
                DIDFT_MAKEINSTANCE(button + button_base);
            TRACE("button type = 0x%08lx\n", type);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -