mirror of
https://github.com/glfw/glfw.git
synced 2024-11-22 13:04:35 +00:00
parent
3aebb0bfe3
commit
7cbdae1bed
@ -101,6 +101,7 @@ does not find Doxygen, the documentation will not be generated.
|
||||
- Removed `_GLFW_USE_OPENGL`, `_GLFW_USE_GLESV1` and `_GLFW_USE_GLESV2`
|
||||
configuration macros
|
||||
- [Win32] Added support for Windows 8.1 per-monitor DPI
|
||||
- [Win32] Replaced winmm with XInput and DirectInput for joystick input
|
||||
- [Win32] Bugfix: Window creation would segfault if video mode setting required
|
||||
the system to be restarted
|
||||
- [Win32] Bugfix: MinGW import library lacked the `lib` prefix
|
||||
|
@ -86,6 +86,13 @@ static GLFWbool loadLibraries(void)
|
||||
_glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
|
||||
|
||||
_glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
{
|
||||
_glfw.win32.dinput8.DirectInput8Create = (DIRECTINPUT8CREATE_T)
|
||||
GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create");
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
const char* names[] =
|
||||
@ -139,6 +146,9 @@ static void freeLibraries(void)
|
||||
if (_glfw.win32.xinput.instance)
|
||||
FreeLibrary(_glfw.win32.xinput.instance);
|
||||
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
FreeLibrary(_glfw.win32.dinput8.instance);
|
||||
|
||||
if (_glfw.win32.winmm.instance)
|
||||
FreeLibrary(_glfw.win32.winmm.instance);
|
||||
|
||||
|
@ -29,9 +29,104 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define _GLFW_UPDATE_BUTTONS 1
|
||||
#define _GLFW_UPDATE_AXES 2
|
||||
#include <initguid.h>
|
||||
|
||||
#define _GLFW_PRESENCE_ONLY 1
|
||||
#define _GLFW_UPDATE_STATE 2
|
||||
|
||||
#define _GLFW_TYPE_AXIS 0
|
||||
#define _GLFW_TYPE_SLIDER 1
|
||||
#define _GLFW_TYPE_BUTTON 2
|
||||
#define _GLFW_TYPE_POV 3
|
||||
|
||||
// Data produced with DirectInput device object enumeration
|
||||
//
|
||||
typedef struct _GLFWobjenumWin32
|
||||
{
|
||||
IDirectInputDevice8W* device;
|
||||
_GLFWjoyobjectWin32* objects;
|
||||
int objectCount;
|
||||
int axisCount;
|
||||
int sliderCount;
|
||||
int buttonCount;
|
||||
int povCount;
|
||||
} _GLFWobjenumWin32;
|
||||
|
||||
// Define only the necessary GUIDs (it's bad enough that we're exporting these)
|
||||
//
|
||||
DEFINE_GUID(IID_IDirectInput8W,0xbf798031,0x483a,0x4da2,0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00);
|
||||
DEFINE_GUID(GUID_XAxis,0xa36d02e0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_YAxis,0xa36d02e1,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_ZAxis,0xa36d02e2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_RxAxis,0xa36d02f4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_RyAxis,0xa36d02f5,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_RzAxis,0xa36d02e3,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_Slider,0xa36d02e4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_Button,0xa36d02f0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
DEFINE_GUID(GUID_POV,0xa36d02f2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||
|
||||
// Object data array for our clone of c_dfDIJoystick
|
||||
// Generated with https://github.com/elmindreda/c_dfDIJoystick2
|
||||
//
|
||||
static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
|
||||
{
|
||||
{ &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
};
|
||||
|
||||
// Our clone of c_dfDIJoystick
|
||||
//
|
||||
static const DIDATAFORMAT _glfwDataFormat =
|
||||
{
|
||||
sizeof(DIDATAFORMAT),
|
||||
sizeof(DIOBJECTDATAFORMAT),
|
||||
DIDFT_ABSAXIS,
|
||||
sizeof(DIJOYSTATE),
|
||||
sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
|
||||
_glfwObjectDataFormats
|
||||
};
|
||||
|
||||
// Returns a description fitting the specified XInput capabilities
|
||||
//
|
||||
@ -63,10 +158,294 @@ static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
|
||||
return "Unknown XInput Device";
|
||||
}
|
||||
|
||||
// Lexically compare device objects
|
||||
//
|
||||
static int compareJoystickObjects(const void* first, const void* second)
|
||||
{
|
||||
const _GLFWjoyobjectWin32* fo = first;
|
||||
const _GLFWjoyobjectWin32* so = second;
|
||||
|
||||
if (fo->type != so->type)
|
||||
return fo->type - so->type;
|
||||
|
||||
return fo->offset - so->offset;
|
||||
}
|
||||
|
||||
// Checks whether the specified device supports XInput
|
||||
// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
|
||||
//
|
||||
static GLFWbool supportsXInput(const GUID* guid)
|
||||
{
|
||||
UINT i, count;
|
||||
RAWINPUTDEVICELIST* ridl;
|
||||
GLFWbool result = GLFW_FALSE;
|
||||
|
||||
if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||
return GLFW_FALSE;
|
||||
|
||||
ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
|
||||
|
||||
if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == -1)
|
||||
{
|
||||
free(ridl);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
RID_DEVICE_INFO rdi;
|
||||
char name[256];
|
||||
UINT size;
|
||||
|
||||
if (ridl[i].dwType != RIM_TYPEHID)
|
||||
continue;
|
||||
|
||||
ZeroMemory(&rdi, sizeof(rdi));
|
||||
rdi.cbSize = sizeof(rdi);
|
||||
size = sizeof(rdi);
|
||||
|
||||
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
|
||||
RIDI_DEVICEINFO,
|
||||
&rdi, &size) == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != guid->Data1)
|
||||
continue;
|
||||
|
||||
memset(name, 0, sizeof(name));
|
||||
size = sizeof(name);
|
||||
|
||||
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
|
||||
RIDI_DEVICENAME,
|
||||
name, &size) == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
if (strstr(name, "IG_"))
|
||||
{
|
||||
result = GLFW_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(ridl);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Frees all resources associated with the specified joystick
|
||||
//
|
||||
static void closeJoystick(_GLFWjoystickWin32* js)
|
||||
{
|
||||
if (js->device)
|
||||
{
|
||||
IDirectInputDevice8_Unacquire(js->device);
|
||||
IDirectInputDevice8_Release(js->device);
|
||||
}
|
||||
|
||||
free(js->name);
|
||||
free(js->axes);
|
||||
free(js->buttons);
|
||||
free(js->objects);
|
||||
memset(js, 0, sizeof(_GLFWjoystickWin32));
|
||||
|
||||
_glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED);
|
||||
}
|
||||
|
||||
// DirectInput device object enumeration callback
|
||||
// Insights gleaned from SDL2
|
||||
//
|
||||
static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
|
||||
void* user)
|
||||
{
|
||||
_GLFWobjenumWin32* data = user;
|
||||
_GLFWjoyobjectWin32* object = data->objects + data->objectCount;
|
||||
|
||||
if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
|
||||
{
|
||||
DIPROPRANGE dipr;
|
||||
|
||||
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_SLIDER(data->sliderCount);
|
||||
else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_X;
|
||||
else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_Y;
|
||||
else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_Z;
|
||||
else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_RX;
|
||||
else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_RY;
|
||||
else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_RZ;
|
||||
else
|
||||
return DIENUM_CONTINUE;
|
||||
|
||||
ZeroMemory(&dipr, sizeof(dipr));
|
||||
dipr.diph.dwSize = sizeof(dipr);
|
||||
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
|
||||
dipr.diph.dwObj = doi->dwType;
|
||||
dipr.diph.dwHow = DIPH_BYID;
|
||||
dipr.lMin = -32768;
|
||||
dipr.lMax = 32767;
|
||||
|
||||
if (FAILED(IDirectInputDevice8_SetProperty(data->device,
|
||||
DIPROP_RANGE,
|
||||
&dipr.diph)))
|
||||
{
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
|
||||
{
|
||||
object->type = _GLFW_TYPE_SLIDER;
|
||||
data->sliderCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
object->type = _GLFW_TYPE_AXIS;
|
||||
data->axisCount++;
|
||||
}
|
||||
}
|
||||
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
|
||||
{
|
||||
object->offset = DIJOFS_BUTTON(data->buttonCount);
|
||||
object->type = _GLFW_TYPE_BUTTON;
|
||||
data->buttonCount++;
|
||||
}
|
||||
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
|
||||
{
|
||||
object->offset = DIJOFS_POV(data->povCount);
|
||||
object->type = _GLFW_TYPE_POV;
|
||||
data->povCount++;
|
||||
}
|
||||
|
||||
data->objectCount++;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
// DirectInput device enumeration callback
|
||||
//
|
||||
static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
|
||||
{
|
||||
int joy = 0;
|
||||
DIDEVCAPS dc;
|
||||
DIPROPDWORD dipd;
|
||||
IDirectInputDevice8* device;
|
||||
_GLFWobjenumWin32 data;
|
||||
_GLFWjoystickWin32* js;
|
||||
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
{
|
||||
if (memcmp(&_glfw.win32_js[joy].guid, &di->guidInstance, sizeof(GUID)) == 0)
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
{
|
||||
if (!_glfw.win32_js[joy].present)
|
||||
break;
|
||||
}
|
||||
|
||||
if (joy > GLFW_JOYSTICK_LAST)
|
||||
return DIENUM_STOP;
|
||||
|
||||
if (supportsXInput(&di->guidProduct))
|
||||
return DIENUM_CONTINUE;
|
||||
|
||||
if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
|
||||
&di->guidInstance,
|
||||
&device,
|
||||
NULL)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "DI: Failed to create device");
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"DI: Failed to set device data format");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dc, sizeof(dc));
|
||||
dc.dwSize = sizeof(dc);
|
||||
|
||||
if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"DI: Failed to query device capabilities");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dipd, sizeof(dipd));
|
||||
dipd.diph.dwSize = sizeof(dipd);
|
||||
dipd.diph.dwHeaderSize = sizeof(dipd.diph);
|
||||
dipd.diph.dwHow = DIPH_DEVICE;
|
||||
dipd.dwData = DIPROPAXISMODE_ABS;
|
||||
|
||||
if (FAILED(IDirectInputDevice8_SetProperty(device,
|
||||
DIPROP_AXISMODE,
|
||||
&dipd.diph)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"DI: Failed to set device axis mode");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.device = device;
|
||||
data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs,
|
||||
sizeof(_GLFWjoyobjectWin32));
|
||||
|
||||
if (FAILED(IDirectInputDevice8_EnumObjects(device,
|
||||
deviceObjectCallback,
|
||||
&data,
|
||||
DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"DI: Failed to enumerate device objects");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
free(data.objects);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
qsort(data.objects, data.objectCount,
|
||||
sizeof(_GLFWjoyobjectWin32),
|
||||
compareJoystickObjects);
|
||||
|
||||
js = _glfw.win32_js + joy;
|
||||
js->device = device;
|
||||
js->guid = di->guidInstance;
|
||||
js->axisCount = data.axisCount + data.sliderCount;
|
||||
js->axes = calloc(js->axisCount, sizeof(float));
|
||||
js->buttonCount += data.buttonCount + data.povCount * 4;
|
||||
js->buttons = calloc(js->buttonCount, 1);
|
||||
js->objects = data.objects;
|
||||
js->objectCount = data.objectCount;
|
||||
js->name = _glfwCreateUTF8FromWideStringWin32(di->tszInstanceName);
|
||||
js->present = GLFW_TRUE;
|
||||
|
||||
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
// Attempt to open the specified joystick device
|
||||
// TODO: Pack state arrays for non-gamepad devices
|
||||
//
|
||||
static GLFWbool openJoystickDevice(DWORD index)
|
||||
static GLFWbool openXinputDevice(DWORD index)
|
||||
{
|
||||
int joy;
|
||||
XINPUT_CAPABILITIES xic;
|
||||
@ -74,8 +453,12 @@ static GLFWbool openJoystickDevice(DWORD index)
|
||||
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
{
|
||||
if (_glfw.win32_js[joy].present && _glfw.win32_js[joy].index == index)
|
||||
if (_glfw.win32_js[joy].present &&
|
||||
_glfw.win32_js[joy].device == NULL &&
|
||||
_glfw.win32_js[joy].index == index)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
@ -92,7 +475,9 @@ static GLFWbool openJoystickDevice(DWORD index)
|
||||
|
||||
js = _glfw.win32_js + joy;
|
||||
js->axisCount = 6;
|
||||
js->axes = calloc(js->axisCount, sizeof(float));
|
||||
js->buttonCount = 14;
|
||||
js->buttons = calloc(js->buttonCount, 1);
|
||||
js->present = GLFW_TRUE;
|
||||
js->name = strdup(getDeviceDescription(&xic));
|
||||
js->index = index;
|
||||
@ -104,32 +489,120 @@ static GLFWbool openJoystickDevice(DWORD index)
|
||||
|
||||
// Polls for and processes events the specified joystick
|
||||
//
|
||||
static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags)
|
||||
static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode)
|
||||
{
|
||||
XINPUT_STATE xis;
|
||||
DWORD result;
|
||||
|
||||
if (!_glfw.win32.xinput.instance)
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!js->present)
|
||||
return GLFW_FALSE;
|
||||
|
||||
result = _glfw_XInputGetState(js->index, &xis);
|
||||
if (result != ERROR_SUCCESS)
|
||||
if (js->device)
|
||||
{
|
||||
if (result == ERROR_DEVICE_NOT_CONNECTED)
|
||||
int i, j, ai = 0, bi = 0;
|
||||
HRESULT result;
|
||||
DIJOYSTATE state;
|
||||
|
||||
IDirectInputDevice8_Poll(js->device);
|
||||
result = IDirectInputDevice8_GetDeviceState(js->device,
|
||||
sizeof(state),
|
||||
&state);
|
||||
if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
|
||||
{
|
||||
free(js->name);
|
||||
memset(js, 0, sizeof(_GLFWjoystickWin32));
|
||||
_glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED);
|
||||
IDirectInputDevice8_Acquire(js->device);
|
||||
IDirectInputDevice8_Poll(js->device);
|
||||
result = IDirectInputDevice8_GetDeviceState(js->device,
|
||||
sizeof(state),
|
||||
&state);
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
if (FAILED(result))
|
||||
{
|
||||
closeJoystick(js);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (flags & _GLFW_UPDATE_AXES)
|
||||
if (mode == _GLFW_PRESENCE_ONLY)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; i < js->objectCount; i++)
|
||||
{
|
||||
const void* data = (char*) &state + js->objects[i].offset;
|
||||
|
||||
switch (js->objects[i].type)
|
||||
{
|
||||
case _GLFW_TYPE_AXIS:
|
||||
case _GLFW_TYPE_SLIDER:
|
||||
{
|
||||
js->axes[ai++] = (*((LONG*) data) + 0.5f) / 32767.5f;
|
||||
break;
|
||||
}
|
||||
|
||||
case _GLFW_TYPE_BUTTON:
|
||||
{
|
||||
if (*((BYTE*) data) & 0x80)
|
||||
js->buttons[bi++] = GLFW_PRESS;
|
||||
else
|
||||
js->buttons[bi++] = GLFW_RELEASE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case _GLFW_TYPE_POV:
|
||||
{
|
||||
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
|
||||
// Screams of horror are appropriate at this point
|
||||
int value = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
|
||||
if (value < 0 || value > 8)
|
||||
value = 8;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
if (directions[value] & (1 << j))
|
||||
js->buttons[bi++] = GLFW_PRESS;
|
||||
else
|
||||
js->buttons[bi++] = GLFW_RELEASE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
DWORD result;
|
||||
XINPUT_STATE xis;
|
||||
const WORD buttons[14] =
|
||||
{
|
||||
XINPUT_GAMEPAD_A,
|
||||
XINPUT_GAMEPAD_B,
|
||||
XINPUT_GAMEPAD_X,
|
||||
XINPUT_GAMEPAD_Y,
|
||||
XINPUT_GAMEPAD_LEFT_SHOULDER,
|
||||
XINPUT_GAMEPAD_RIGHT_SHOULDER,
|
||||
XINPUT_GAMEPAD_BACK,
|
||||
XINPUT_GAMEPAD_START,
|
||||
XINPUT_GAMEPAD_LEFT_THUMB,
|
||||
XINPUT_GAMEPAD_RIGHT_THUMB,
|
||||
XINPUT_GAMEPAD_DPAD_UP,
|
||||
XINPUT_GAMEPAD_DPAD_RIGHT,
|
||||
XINPUT_GAMEPAD_DPAD_DOWN,
|
||||
XINPUT_GAMEPAD_DPAD_LEFT
|
||||
};
|
||||
|
||||
result = _glfw_XInputGetState(js->index, &xis);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
if (result == ERROR_DEVICE_NOT_CONNECTED)
|
||||
closeJoystick(js);
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (mode == _GLFW_PRESENCE_ONLY)
|
||||
return GLFW_TRUE;
|
||||
|
||||
if (sqrtf((float) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX +
|
||||
xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY)) >
|
||||
(float) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
|
||||
@ -165,34 +638,12 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags)
|
||||
js->axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f;
|
||||
else
|
||||
js->axes[5] = -1.f;
|
||||
}
|
||||
|
||||
if (flags & _GLFW_UPDATE_BUTTONS)
|
||||
{
|
||||
int i;
|
||||
const WORD buttons[14] =
|
||||
{
|
||||
XINPUT_GAMEPAD_A,
|
||||
XINPUT_GAMEPAD_B,
|
||||
XINPUT_GAMEPAD_X,
|
||||
XINPUT_GAMEPAD_Y,
|
||||
XINPUT_GAMEPAD_LEFT_SHOULDER,
|
||||
XINPUT_GAMEPAD_RIGHT_SHOULDER,
|
||||
XINPUT_GAMEPAD_BACK,
|
||||
XINPUT_GAMEPAD_START,
|
||||
XINPUT_GAMEPAD_LEFT_THUMB,
|
||||
XINPUT_GAMEPAD_RIGHT_THUMB,
|
||||
XINPUT_GAMEPAD_DPAD_UP,
|
||||
XINPUT_GAMEPAD_DPAD_RIGHT,
|
||||
XINPUT_GAMEPAD_DPAD_DOWN,
|
||||
XINPUT_GAMEPAD_DPAD_LEFT
|
||||
};
|
||||
|
||||
for (i = 0; i < 14; i++)
|
||||
js->buttons[i] = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -204,6 +655,19 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickWin32* js, int flags)
|
||||
//
|
||||
void _glfwInitJoysticksWin32(void)
|
||||
{
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
{
|
||||
if (FAILED(_glfw_DirectInput8Create(GetModuleHandle(NULL),
|
||||
DIRECTINPUT_VERSION,
|
||||
&IID_IDirectInput8W,
|
||||
(void**) &_glfw.win32.dinput8.api,
|
||||
NULL)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"DI: Failed to create interface");
|
||||
}
|
||||
}
|
||||
|
||||
_glfwDetectJoystickConnectionWin32();
|
||||
}
|
||||
|
||||
@ -214,33 +678,47 @@ void _glfwTerminateJoysticksWin32(void)
|
||||
int joy;
|
||||
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
free(_glfw.win32_js[joy].name);
|
||||
closeJoystick(_glfw.win32_js + joy);
|
||||
|
||||
if (_glfw.win32.dinput8.api)
|
||||
IDirectInput8_Release(_glfw.win32.dinput8.api);
|
||||
}
|
||||
|
||||
// Looks for new joysticks
|
||||
// Checks for new joysticks after DBT_DEVICEARRIVAL
|
||||
//
|
||||
void _glfwDetectJoystickConnectionWin32(void)
|
||||
{
|
||||
DWORD i;
|
||||
if (_glfw.win32.xinput.instance)
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
if (!_glfw.win32.xinput.instance)
|
||||
return;
|
||||
for (i = 0; i < XUSER_MAX_COUNT; i++)
|
||||
openXinputDevice(i);
|
||||
}
|
||||
|
||||
for (i = 0; i < XUSER_MAX_COUNT; i++)
|
||||
openJoystickDevice(i);
|
||||
if (_glfw.win32.dinput8.api)
|
||||
{
|
||||
if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
|
||||
DI8DEVCLASS_GAMECTRL,
|
||||
deviceCallback,
|
||||
NULL,
|
||||
DIEDFL_ALLDEVICES)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Failed to enumerate DirectInput8 devices");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if any current joystick has been disconnected
|
||||
// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
|
||||
//
|
||||
void _glfwDetectJoystickDisconnectionWin32(void)
|
||||
{
|
||||
DWORD i;
|
||||
int joy;
|
||||
|
||||
if (!_glfw.win32.xinput.instance)
|
||||
return;
|
||||
|
||||
for (i = 0; i < XUSER_MAX_COUNT; i++)
|
||||
pollJoystickEvents(_glfw.win32_js + i, 0);
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
pollJoystickState(_glfw.win32_js + joy, _GLFW_PRESENCE_ONLY);
|
||||
}
|
||||
|
||||
|
||||
@ -251,13 +729,13 @@ void _glfwDetectJoystickDisconnectionWin32(void)
|
||||
int _glfwPlatformJoystickPresent(int joy)
|
||||
{
|
||||
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||
return pollJoystickEvents(js, 0);
|
||||
return pollJoystickState(js, _GLFW_PRESENCE_ONLY);
|
||||
}
|
||||
|
||||
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||
{
|
||||
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||
if (!pollJoystickEvents(js, _GLFW_UPDATE_AXES))
|
||||
if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
|
||||
return NULL;
|
||||
|
||||
*count = js->axisCount;
|
||||
@ -267,7 +745,7 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
||||
{
|
||||
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||
if (!pollJoystickEvents(js, _GLFW_UPDATE_BUTTONS))
|
||||
if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
|
||||
return NULL;
|
||||
|
||||
*count = js->buttonCount;
|
||||
@ -277,7 +755,7 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
||||
const char* _glfwPlatformGetJoystickName(int joy)
|
||||
{
|
||||
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||
if (!pollJoystickEvents(js, 0))
|
||||
if (!pollJoystickState(js, _GLFW_PRESENCE_ONLY))
|
||||
return NULL;
|
||||
|
||||
return js->name;
|
||||
|
@ -30,17 +30,29 @@
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
|
||||
_GLFWjoystickWin32 win32_js[GLFW_JOYSTICK_LAST + 1]
|
||||
|
||||
// Spoo
|
||||
//
|
||||
typedef struct _GLFWjoyobjectWin32
|
||||
{
|
||||
int offset;
|
||||
int type;
|
||||
} _GLFWjoyobjectWin32;
|
||||
|
||||
// Win32-specific per-joystick data
|
||||
//
|
||||
typedef struct _GLFWjoystickWin32
|
||||
{
|
||||
GLFWbool present;
|
||||
float axes[6];
|
||||
int axisCount;
|
||||
unsigned char buttons[14];
|
||||
int buttonCount;
|
||||
char* name;
|
||||
DWORD index;
|
||||
GLFWbool present;
|
||||
float* axes;
|
||||
int axisCount;
|
||||
unsigned char* buttons;
|
||||
int buttonCount;
|
||||
_GLFWjoyobjectWin32* objects;
|
||||
int objectCount;
|
||||
char* name;
|
||||
IDirectInputDevice8W* device;
|
||||
DWORD index;
|
||||
GUID guid;
|
||||
} _GLFWjoystickWin32;
|
||||
|
||||
|
||||
|
@ -61,8 +61,12 @@
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
// GLFW uses DirectInput8 interfaces
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <dinput.h>
|
||||
#include <xinput.h>
|
||||
#include <dbt.h>
|
||||
|
||||
@ -71,7 +75,7 @@
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
|
||||
// HACK: Define macros that some older windows.h variants don't
|
||||
// HACK: Define macros that some windows.h variants don't
|
||||
#ifndef WM_MOUSEHWHEEL
|
||||
#define WM_MOUSEHWHEEL 0x020E
|
||||
#endif
|
||||
@ -121,7 +125,7 @@ typedef enum PROCESS_DPI_AWARENESS
|
||||
} PROCESS_DPI_AWARENESS;
|
||||
#endif /*DPI_ENUMS_DECLARED*/
|
||||
|
||||
// HACK: Define macros that some older xinput.h variants don't
|
||||
// HACK: Define macros that some xinput.h variants don't
|
||||
#ifndef XINPUT_CAPS_WIRELESS
|
||||
#define XINPUT_CAPS_WIRELESS 0x0002
|
||||
#endif
|
||||
@ -147,6 +151,11 @@ typedef enum PROCESS_DPI_AWARENESS
|
||||
#define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13
|
||||
#endif
|
||||
|
||||
// HACK: Define macros that some dinput.h variants don't
|
||||
#ifndef DIDFT_OPTIONAL
|
||||
#define DIDFT_OPTIONAL 0x80000000
|
||||
#endif
|
||||
|
||||
// winmm.dll function pointer typedefs
|
||||
typedef DWORD (WINAPI * TIMEGETTIME_T)(void);
|
||||
#define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime
|
||||
@ -157,6 +166,10 @@ typedef DWORD (WINAPI * XINPUTGETSTATE_T)(DWORD,XINPUT_STATE*);
|
||||
#define _glfw_XInputGetCapabilities _glfw.win32.xinput.XInputGetCapabilities
|
||||
#define _glfw_XInputGetState _glfw.win32.xinput.XInputGetState
|
||||
|
||||
// dinput8.dll function pointer typedefs
|
||||
typedef HRESULT (WINAPI * DIRECTINPUT8CREATE_T)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
|
||||
#define _glfw_DirectInput8Create _glfw.win32.dinput8.DirectInput8Create
|
||||
|
||||
// user32.dll function pointer typedefs
|
||||
typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void);
|
||||
typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT);
|
||||
@ -241,13 +254,17 @@ typedef struct _GLFWlibraryWin32
|
||||
short int publicKeys[512];
|
||||
short int nativeKeys[GLFW_KEY_LAST + 1];
|
||||
|
||||
// winmm.dll
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
TIMEGETTIME_T timeGetTime;
|
||||
} winmm;
|
||||
|
||||
// user32.dll
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
DIRECTINPUT8CREATE_T DirectInput8Create;
|
||||
IDirectInput8W* api;
|
||||
} dinput8;
|
||||
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
XINPUTGETCAPABILITIES_T XInputGetCapabilities;
|
||||
@ -260,14 +277,12 @@ typedef struct _GLFWlibraryWin32
|
||||
CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx;
|
||||
} user32;
|
||||
|
||||
// dwmapi.dll
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled;
|
||||
DWMFLUSH_T DwmFlush;
|
||||
} dwmapi;
|
||||
|
||||
// shcore.dll
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
SETPROCESSDPIAWARENESS_T SetProcessDpiAwareness;
|
||||
|
Loading…
Reference in New Issue
Block a user