diff options
Diffstat (limited to 'docs/release/src/osd/winui/dijoystick.cpp')
-rw-r--r-- | docs/release/src/osd/winui/dijoystick.cpp | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/docs/release/src/osd/winui/dijoystick.cpp b/docs/release/src/osd/winui/dijoystick.cpp new file mode 100644 index 00000000000..1136c7f0179 --- /dev/null +++ b/docs/release/src/osd/winui/dijoystick.cpp @@ -0,0 +1,629 @@ +// For licensing and usage information, read docs/winui_license.txt +//**************************************************************************** + +/*************************************************************************** + + dijoystick.c + + ***************************************************************************/ + +// standard windows headers +#include <windows.h> + +// standard C headers +#include <stdio.h> +#include <math.h> +#include <tchar.h> + +// MAMEUI headers +#include "winui.h" +#include "directinput.h" +#include "dijoystick.h" +#include "mui_util.h" // For ErrorMsg +#include "dxdecode.h" // for DirectXDecodeError + +/*************************************************************************** + function prototypes + ***************************************************************************/ + +static int DIJoystick_init(void); +static void DIJoystick_exit(void); +static void DIJoystick_poll_joysticks(void); +static int DIJoystick_is_joy_pressed(int joycode); +static BOOL DIJoystick_Available(void); + +static BOOL CALLBACK DIJoystick_EnumDeviceProc(LPDIDEVICEINSTANCE pdidi, LPVOID pv); + +/*************************************************************************** + External variables + ***************************************************************************/ + +const struct OSDJoystick DIJoystick = +{ + DIJoystick_init, /* init */ + DIJoystick_exit, /* exit */ + DIJoystick_is_joy_pressed, /* joy_pressed */ + DIJoystick_poll_joysticks, /* poll_joysticks */ + DIJoystick_Available, /* Available */ +}; + +/*************************************************************************** + Internal structures + ***************************************************************************/ + +#define MAX_PHYSICAL_JOYSTICKS 20 +#define MAX_AXES 20 + +typedef struct +{ + GUID guid; + TCHAR *name; + + int offset; /* offset in dijoystate */ +} axis_type; + +typedef struct +{ + BOOL use_joystick; + + GUID guidDevice; + TCHAR *name; + + BOOL is_light_gun; + + LPDIRECTINPUTDEVICE2 did; + + DWORD num_axes; + axis_type axes[MAX_AXES]; + + DWORD num_pov; + DWORD num_buttons; + + DIJOYSTATE dijs; + +} joystick_type; + +struct tDIJoystick_private +{ + int use_count; /* the gui and game can both init/exit us, so keep track */ + BOOL m_bCoinSlot; + + DWORD num_joysticks; + joystick_type joysticks[MAX_PHYSICAL_JOYSTICKS]; /* actual joystick data! */ +}; + +/* internal functions needing our declarations */ +static BOOL CALLBACK DIJoystick_EnumAxisObjectsProc(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); +static BOOL CALLBACK DIJoystick_EnumPOVObjectsProc(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); +static BOOL CALLBACK DIJoystick_EnumButtonObjectsProc(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); +static void ClearJoyState(DIJOYSTATE *pdijs); + +static void InitJoystick(joystick_type *joystick); +static void ExitJoystick(joystick_type *joystick); + +/*************************************************************************** + Internal variables + ***************************************************************************/ + +static struct tDIJoystick_private This; + +static const GUID guidNULL = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; + +/*************************************************************************** + External OSD functions + ***************************************************************************/ +/* + put here anything you need to do when the program is started. Return 0 if + initialization was successful, nonzero otherwise. +*/ +static int DIJoystick_init(void) +{ + DWORD i = 0; + HRESULT hr; + LPDIRECTINPUT di = GetDirectInput(); + + This.use_count++; + + This.num_joysticks = 0; + + if (di == NULL) + { + ErrorMsg("DirectInput not initialized"); + return 0; + } + + /* enumerate for joystick devices */ + hr = IDirectInput_EnumDevices(di, DIDEVTYPE_JOYSTICK, + (LPDIENUMDEVICESCALLBACK)DIJoystick_EnumDeviceProc, + NULL, + DIEDFL_ATTACHEDONLY ); + if (FAILED(hr)) + { + ErrorMsg("DirectInput EnumDevices() failed: %s", DirectXDecodeError(hr)); + return 0; + } + + /* create each joystick device, enumerate each joystick for axes, etc */ + for (i = 0; i < This.num_joysticks; i++) + { + InitJoystick(&This.joysticks[i]); + } + + /* Are there any joysticks attached? */ + if (This.num_joysticks < 1) + { + /*ErrorMsg("DirectInput EnumDevices didn't find any joysticks");*/ + return 0; + } + + return 0; +} + +/* + put here cleanup routines to be executed when the program is terminated. +*/ +static void DIJoystick_exit(void) +{ + DWORD i = 0; + + This.use_count--; + + if (This.use_count > 0) + return; + + for (i = 0; i < This.num_joysticks; i++) + ExitJoystick(&This.joysticks[i]); + + This.num_joysticks = 0; +} + +static void DIJoystick_poll_joysticks(void) +{ + HRESULT hr; + DWORD i = 0; + + This.m_bCoinSlot = 0; + + for (i = 0; i < This.num_joysticks; i++) + { + /* start by clearing the structure, then fill it in if possible */ + + ClearJoyState(&This.joysticks[i].dijs); + + if (This.joysticks[i].did == NULL) + continue; + + if (This.joysticks[i].use_joystick == FALSE) + continue; + + hr = IDirectInputDevice2_Poll(This.joysticks[i].did); + + hr = IDirectInputDevice2_GetDeviceState(This.joysticks[i].did,sizeof(DIJOYSTATE), &This.joysticks[i].dijs); + if (FAILED(hr)) + { + if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) + { + hr = IDirectInputDevice2_Acquire(This.joysticks[i].did); + } + continue; + } + } +} + +/* + check if the DIJoystick is moved in the specified direction, defined in + osdepend.h. Return 0 if it is not pressed, nonzero otherwise. +*/ + +static int DIJoystick_is_joy_pressed(int joycode) +{ + int joy_num = 0; + int stick = 0; + int axis = 0; + int dir = 0; + + DIJOYSTATE dijs; + + int value = 0; + int dz = 60; + + joy_num = GET_JOYCODE_JOY(joycode); + + /* do we have as many sticks? */ + if (joy_num == 0 || This.num_joysticks < joy_num) + return 0; + joy_num--; + + if (This.joysticks[joy_num].use_joystick == FALSE) + return 0; + + dijs = This.joysticks[joy_num].dijs; + + stick = GET_JOYCODE_STICK(joycode); + + if (stick == JOYCODE_STICK_BTN) + { + /* buttons */ + int button; + + button = GET_JOYCODE_BUTTON(joycode); + button--; + + if (button >= This.joysticks[joy_num].num_buttons + || GET_JOYCODE_DIR(joycode) != JOYCODE_DIR_BTN) + return 0; + + return dijs.rgbButtons[button] != 0; + } + + if (stick == JOYCODE_STICK_POV) + { + /* POV */ + int pov_value = 0; + int angle = 0; + int axis_value = 0; + + int num_pov = GET_JOYCODE_BUTTON(joycode) / 4; + int code = GET_JOYCODE_BUTTON(joycode) % 4; + axis = code / 2; + dir = code % 2; + + if (num_pov >= This.joysticks[joy_num].num_pov) + return 0; + + pov_value = dijs.rgdwPOV[num_pov]; + if (LOWORD(pov_value) == 0xffff) + return 0; + + angle = (pov_value + 27000) % 36000; + angle = (36000 - angle) % 36000; + angle /= 100; + + /* angle is now in degrees counterclockwise from x axis*/ + if (axis == 1) + axis_value = 128 + (int)(127 * cos(2 * M_PI * angle / 360.0)); /* x */ + else + axis_value = 128 + (int)(127 * sin(2 * M_PI * angle / 360.0)); /* y */ + + if (dir == 1) + return axis_value <= (128 - 128 * dz / 100); + else + return axis_value >= (128 + 128 * dz / 100); + } + + /* sticks */ + + axis = GET_JOYCODE_AXIS(joycode); + dir = GET_JOYCODE_DIR(joycode); + + if (axis == 0 || This.joysticks[joy_num].num_axes < axis) + return 0; + axis--; + + value = *(int *)(((byte *)&dijs) + This.joysticks[joy_num].axes[axis].offset); + + if (dir == JOYCODE_DIR_NEG) + return value <= (128 - 128 * dz / 100); + else + return value >= (128 + 128 * dz / 100); +} + +static BOOL DIJoystick_Available(void) +{ + static BOOL bBeenHere = FALSE; + static BOOL bAvailable = FALSE; + HRESULT hr; + GUID guidDevice = guidNULL; + LPDIRECTINPUTDEVICE didTemp; + LPDIRECTINPUTDEVICE didJoystick; + LPDIRECTINPUT di = GetDirectInput(); + + if (di == NULL) + { + return FALSE; + } + + if (bBeenHere == FALSE) + bBeenHere = TRUE; + else + return bAvailable; + + /* enumerate for joystick devices */ + hr = IDirectInput_EnumDevices(di, DIDEVTYPE_JOYSTICK, inputEnumDeviceProc, &guidDevice, DIEDFL_ATTACHEDONLY); + if (FAILED(hr)) + { + return FALSE; + } + + /* Are there any joysticks attached? */ + if (IsEqualGUID(guidDevice, guidNULL)) + { + return FALSE; + } + + hr = IDirectInput_CreateDevice(di, guidDevice, &didTemp, NULL); + if (FAILED(hr)) + { + return FALSE; + } + + /* Determine if DX5 is available by a QI for a DX5 interface. */ + hr = IDirectInputDevice_QueryInterface(didTemp, IID_IDirectInputDevice2, (void**)&didJoystick); + if (FAILED(hr)) + { + bAvailable = FALSE; + } + else + { + bAvailable = TRUE; + IDirectInputDevice_Release(didJoystick); + } + + /* dispose of the temp interface */ + IDirectInputDevice_Release(didTemp); + + return bAvailable; +} + +int DIJoystick_GetNumPhysicalJoysticks() +{ + return This.num_joysticks; +} + +TCHAR* DIJoystick_GetPhysicalJoystickName(int num_joystick) +{ + return This.joysticks[num_joystick].name; +} + +int DIJoystick_GetNumPhysicalJoystickAxes(int num_joystick) +{ + return This.joysticks[num_joystick].num_axes; +} + +TCHAR* DIJoystick_GetPhysicalJoystickAxisName(int num_joystick, int num_axis) +{ + return This.joysticks[num_joystick].axes[num_axis].name; +} + +/*************************************************************************** + Internal functions + ***************************************************************************/ + +BOOL CALLBACK DIJoystick_EnumDeviceProc(LPDIDEVICEINSTANCE pdidi, LPVOID pv) +{ + TCHAR buffer[5000]; + + This.joysticks[This.num_joysticks].guidDevice = pdidi->guidInstance; + + _stprintf(buffer, TEXT("%s (%s)"), pdidi->tszProductName, pdidi->tszInstanceName); + This.joysticks[This.num_joysticks].name = (TCHAR *)malloc((_tcslen(buffer) + 1) * sizeof(TCHAR)); + _tcscpy(This.joysticks[This.num_joysticks].name, buffer); + + This.num_joysticks++; + + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK DIJoystick_EnumAxisObjectsProc(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) +{ + joystick_type* joystick = (joystick_type*)pvRef; + DIPROPRANGE diprg; + HRESULT hr; + + joystick->axes[joystick->num_axes].guid = lpddoi->guidType; + + joystick->axes[joystick->num_axes].name = (TCHAR *)malloc((_tcslen(lpddoi->tszName) + 1) * sizeof(TCHAR)); + _tcscpy(joystick->axes[joystick->num_axes].name, lpddoi->tszName); + + joystick->axes[joystick->num_axes].offset = lpddoi->dwOfs; + + /*ErrorMsg("got axis %s, offset %i",lpddoi->tszName, lpddoi->dwOfs);*/ + + diprg.diph.dwSize = sizeof(diprg); + diprg.diph.dwHeaderSize = sizeof(diprg.diph); + diprg.diph.dwObj = lpddoi->dwOfs; + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.lMin = 0; + diprg.lMax = 255; + + hr = IDirectInputDevice2_SetProperty(joystick->did, DIPROP_RANGE, &diprg.diph); + if (FAILED(hr)) /* if this fails, don't use this axis */ + { + free(joystick->axes[joystick->num_axes].name); + joystick->axes[joystick->num_axes].name = NULL; + return DIENUM_CONTINUE; + } + +#ifdef JOY_DEBUG + if (FAILED(hr)) + { + ErrorMsg("DirectInput SetProperty() joystick axis %s failed - %s\n", + joystick->axes[joystick->num_axes].name, DirectXDecodeError(hr)); + } +#endif + + /* Set axis dead zone to 0; we need accurate #'s for analog joystick reading. */ + + hr = SetDIDwordProperty(joystick->did, DIPROP_DEADZONE, lpddoi->dwOfs, DIPH_BYOFFSET, 0); + +#ifdef JOY_DEBUG + if (FAILED(hr)) + { + ErrorMsg("DirectInput SetProperty() joystick axis %s dead zone failed - %s\n", + joystick->axes[joystick->num_axes].name, DirectXDecodeError(hr)); + } +#endif + + joystick->num_axes++; + + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK DIJoystick_EnumPOVObjectsProc(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) +{ + joystick_type* joystick = (joystick_type*)pvRef; + joystick->num_pov++; + + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK DIJoystick_EnumButtonObjectsProc(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) +{ + joystick_type* joystick = (joystick_type*)pvRef; + joystick->num_buttons++; + + return DIENUM_CONTINUE; +} + +static void ClearJoyState(DIJOYSTATE *pdijs) +{ + memset(pdijs, 0, sizeof(DIJOYSTATE)); + pdijs->lX = 128; + pdijs->lY = 128; + pdijs->lZ = 128; + pdijs->lRx = 128; + pdijs->lRy = 128; + pdijs->lRz = 128; + pdijs->rglSlider[0] = 128; + pdijs->rglSlider[1] = 128; + pdijs->rgdwPOV[0] = -1; + pdijs->rgdwPOV[1] = -1; + pdijs->rgdwPOV[2] = -1; + pdijs->rgdwPOV[3] = -1; +} + +static void InitJoystick(joystick_type *joystick) +{ + LPDIRECTINPUTDEVICE didTemp; + HRESULT hr; + LPDIRECTINPUT di = GetDirectInput(); + + joystick->use_joystick = FALSE; + + joystick->did = NULL; + joystick->num_axes = 0; + + joystick->is_light_gun = (_tcscmp(joystick->name, TEXT("ACT LABS GS (ACT LABS GS)")) == 0); + + /* get a did1 interface first... */ + hr = IDirectInput_CreateDevice(di, joystick->guidDevice, &didTemp, NULL); + if (FAILED(hr)) + { + ErrorMsg("DirectInput CreateDevice() joystick failed: %s\n", DirectXDecodeError(hr)); + return; + } + + /* get a did2 interface to work with polling (most) joysticks */ + hr = IDirectInputDevice_QueryInterface(didTemp, IID_IDirectInputDevice2, (void**)&joystick->did); + + /* dispose of the temp interface */ + IDirectInputDevice_Release(didTemp); + + /* check result of getting the did2 */ + if (FAILED(hr)) + { + /* no error message because this happens in dx3 */ + /* ErrorMsg("DirectInput QueryInterface joystick failed\n"); */ + joystick->did = NULL; + return; + } + + + hr = IDirectInputDevice2_SetCooperativeLevel(joystick->did, GetMainWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + if (FAILED(hr)) + { + ErrorMsg("DirectInput SetCooperativeLevel() joystick failed: %s\n", DirectXDecodeError(hr)); + return; + } + + + hr = IDirectInputDevice2_SetDataFormat(joystick->did, &c_dfDIJoystick); + if (FAILED(hr)) + { + ErrorMsg("DirectInput SetDataFormat() joystick failed: %s\n", DirectXDecodeError(hr)); + return; + } + + if (joystick->is_light_gun) + { + /* setup light gun to report raw screen pixel data */ + + DIPROPDWORD diprop; + memset(&diprop, 0, sizeof(diprop)); + diprop.diph.dwSize = sizeof(DIPROPDWORD); + diprop.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprop.diph.dwObj = 0; + diprop.diph.dwHow = DIPH_DEVICE; + diprop.dwData = DIPROPCALIBRATIONMODE_RAW; + + IDirectInputDevice2_SetProperty(joystick->did, DIPROP_CALIBRATIONMODE, &diprop.diph); + } + else + { + /* enumerate our axes */ + hr = IDirectInputDevice_EnumObjects(joystick->did, DIJoystick_EnumAxisObjectsProc, joystick, DIDFT_AXIS); + if (FAILED(hr)) + { + ErrorMsg("DirectInput EnumObjects() Axes failed: %s\n", DirectXDecodeError(hr)); + return; + } + + /* enumerate our POV hats */ + joystick->num_pov = 0; + hr = IDirectInputDevice_EnumObjects(joystick->did, DIJoystick_EnumPOVObjectsProc, joystick, DIDFT_POV); + if (FAILED(hr)) + { + ErrorMsg("DirectInput EnumObjects() POVs failed: %s\n", DirectXDecodeError(hr)); + return; + } + } + + /* enumerate our buttons */ + + joystick->num_buttons = 0; + hr = IDirectInputDevice_EnumObjects(joystick->did, DIJoystick_EnumButtonObjectsProc, joystick, DIDFT_BUTTON); + if (FAILED(hr)) + { + ErrorMsg("DirectInput EnumObjects() Buttons failed: %s\n", DirectXDecodeError(hr)); + return; + } + + hr = IDirectInputDevice2_Acquire(joystick->did); + if (FAILED(hr)) + { + ErrorMsg("DirectInputDevice Acquire joystick failed!\n"); + return; + } + + /* start by clearing the structures */ + + ClearJoyState(&joystick->dijs); + + joystick->use_joystick = TRUE; +} + +static void ExitJoystick(joystick_type *joystick) +{ + DWORD i = 0; + + if (joystick->did != NULL) + { + IDirectInputDevice_Unacquire(joystick->did); + IDirectInputDevice_Release(joystick->did); + joystick->did = NULL; + } + + for (i = 0; i < joystick->num_axes; i++) + { + if (joystick->axes[i].name) + free(joystick->axes[i].name); + joystick->axes[i].name = NULL; + } + + if (joystick->name != NULL) + { + free(joystick->name); + joystick->name = NULL; + } +} + |