mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 14:21:04 +08:00
Added support for interfacing with joysticks via DirectInput when it is available.
This commit is contained in:
parent
d972216c57
commit
22f1b85515
117
extlibs/headers/mingw/_mingw_dxhelper.h
vendored
Normal file
117
extlibs/headers/mingw/_mingw_dxhelper.h
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* This file has no copyright assigned and is placed in the Public Domain.
|
||||
* This file is part of the mingw-w64 runtime package.
|
||||
* No warranty is given; refer to the file DISCLAIMER within this package.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS)
|
||||
#define NONAMELESSUNION 1
|
||||
#endif
|
||||
#if defined(NONAMELESSSTRUCT) && \
|
||||
!defined(NONAMELESSUNION)
|
||||
#define NONAMELESSUNION 1
|
||||
#endif
|
||||
#if defined(NONAMELESSUNION) && \
|
||||
!defined(NONAMELESSSTRUCT)
|
||||
#define NONAMELESSSTRUCT 1
|
||||
#endif
|
||||
#if !defined(__GNU_EXTENSION)
|
||||
#if defined(__GNUC__) || defined(__GNUG__)
|
||||
#define __GNU_EXTENSION __extension__
|
||||
#else
|
||||
#define __GNU_EXTENSION
|
||||
#endif
|
||||
#endif /* __extension__ */
|
||||
|
||||
#ifndef __ANONYMOUS_DEFINED
|
||||
#define __ANONYMOUS_DEFINED
|
||||
#if defined(__GNUC__) || defined(__GNUG__)
|
||||
#define _ANONYMOUS_UNION __extension__
|
||||
#define _ANONYMOUS_STRUCT __extension__
|
||||
#else
|
||||
#define _ANONYMOUS_UNION
|
||||
#define _ANONYMOUS_STRUCT
|
||||
#endif
|
||||
#ifndef NONAMELESSUNION
|
||||
#define _UNION_NAME(x)
|
||||
#define _STRUCT_NAME(x)
|
||||
#else /* NONAMELESSUNION */
|
||||
#define _UNION_NAME(x) x
|
||||
#define _STRUCT_NAME(x) x
|
||||
#endif
|
||||
#endif /* __ANONYMOUS_DEFINED */
|
||||
|
||||
#ifndef DUMMYUNIONNAME
|
||||
# ifdef NONAMELESSUNION
|
||||
# define DUMMYUNIONNAME u
|
||||
# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */
|
||||
# define DUMMYUNIONNAME2 u2
|
||||
# define DUMMYUNIONNAME3 u3
|
||||
# define DUMMYUNIONNAME4 u4
|
||||
# define DUMMYUNIONNAME5 u5
|
||||
# define DUMMYUNIONNAME6 u6
|
||||
# define DUMMYUNIONNAME7 u7
|
||||
# define DUMMYUNIONNAME8 u8
|
||||
# define DUMMYUNIONNAME9 u9
|
||||
# else /* NONAMELESSUNION */
|
||||
# define DUMMYUNIONNAME
|
||||
# define DUMMYUNIONNAME1 /* Wine uses this variant */
|
||||
# define DUMMYUNIONNAME2
|
||||
# define DUMMYUNIONNAME3
|
||||
# define DUMMYUNIONNAME4
|
||||
# define DUMMYUNIONNAME5
|
||||
# define DUMMYUNIONNAME6
|
||||
# define DUMMYUNIONNAME7
|
||||
# define DUMMYUNIONNAME8
|
||||
# define DUMMYUNIONNAME9
|
||||
# endif
|
||||
#endif /* DUMMYUNIONNAME */
|
||||
|
||||
#if !defined(DUMMYUNIONNAME1) /* MinGW does not define this one */
|
||||
# ifdef NONAMELESSUNION
|
||||
# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */
|
||||
# else
|
||||
# define DUMMYUNIONNAME1 /* Wine uses this variant */
|
||||
# endif
|
||||
#endif /* DUMMYUNIONNAME1 */
|
||||
|
||||
#ifndef DUMMYSTRUCTNAME
|
||||
# ifdef NONAMELESSUNION
|
||||
# define DUMMYSTRUCTNAME s
|
||||
# define DUMMYSTRUCTNAME1 s1 /* Wine uses this variant */
|
||||
# define DUMMYSTRUCTNAME2 s2
|
||||
# define DUMMYSTRUCTNAME3 s3
|
||||
# define DUMMYSTRUCTNAME4 s4
|
||||
# define DUMMYSTRUCTNAME5 s5
|
||||
# else
|
||||
# define DUMMYSTRUCTNAME
|
||||
# define DUMMYSTRUCTNAME1 /* Wine uses this variant */
|
||||
# define DUMMYSTRUCTNAME2
|
||||
# define DUMMYSTRUCTNAME3
|
||||
# define DUMMYSTRUCTNAME4
|
||||
# define DUMMYSTRUCTNAME5
|
||||
# endif
|
||||
#endif /* DUMMYSTRUCTNAME */
|
||||
|
||||
/* These are for compatibility with the Wine source tree */
|
||||
|
||||
#ifndef WINELIB_NAME_AW
|
||||
# ifdef __MINGW_NAME_AW
|
||||
# define WINELIB_NAME_AW __MINGW_NAME_AW
|
||||
# else
|
||||
# ifdef UNICODE
|
||||
# define WINELIB_NAME_AW(func) func##W
|
||||
# else
|
||||
# define WINELIB_NAME_AW(func) func##A
|
||||
# endif
|
||||
# endif
|
||||
#endif /* WINELIB_NAME_AW */
|
||||
|
||||
#ifndef DECL_WINELIB_TYPE_AW
|
||||
# ifdef __MINGW_TYPEDEF_AW
|
||||
# define DECL_WINELIB_TYPE_AW __MINGW_TYPEDEF_AW
|
||||
# else
|
||||
# define DECL_WINELIB_TYPE_AW(type) typedef WINELIB_NAME_AW(type) type;
|
||||
# endif
|
||||
#endif /* DECL_WINELIB_TYPE_AW */
|
||||
|
2467
extlibs/headers/mingw/dinput.h
vendored
Normal file
2467
extlibs/headers/mingw/dinput.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -245,6 +245,13 @@ if(SFML_OS_LINUX)
|
||||
endif()
|
||||
include_directories(${UDEV_INCLUDE_DIR})
|
||||
endif()
|
||||
if(SFML_OS_WINDOWS AND NOT SFML_COMPILER_MSVC)
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(dinput.h DINPUT_H_FOUND)
|
||||
if(NOT DINPUT_H_FOUND)
|
||||
include_directories("${PROJECT_SOURCE_DIR}/extlibs/headers/mingw")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# build the list of external libraries to link
|
||||
|
@ -33,9 +33,59 @@
|
||||
#include <regstr.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// DirectInput
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef DIDFT_OPTIONAL
|
||||
#define DIDFT_OPTIONAL 0x80000000
|
||||
#endif
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace guids
|
||||
{
|
||||
const GUID IID_IDirectInput8W = {0xbf798031, 0x483a, 0x4da2, {0xaa, 0x99, 0x5d, 0x64, 0xed, 0x36, 0x97, 0x00}};
|
||||
|
||||
const GUID GUID_XAxis = {0xa36d02e0, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
const GUID GUID_YAxis = {0xa36d02e1, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
const GUID GUID_ZAxis = {0xa36d02e2, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
const GUID GUID_RzAxis = {0xa36d02e3, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
const GUID GUID_Slider = {0xa36d02e4, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
|
||||
const GUID GUID_POV = {0xa36d02f2, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
|
||||
const GUID GUID_RxAxis = {0xa36d02f4, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
const GUID GUID_RyAxis = {0xa36d02f5, 0xc9f3, 0x11cf, {0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
|
||||
}
|
||||
|
||||
HMODULE dinput8dll = NULL;
|
||||
IDirectInput8W* directInput = NULL;
|
||||
|
||||
struct JoystickRecord
|
||||
{
|
||||
GUID guid;
|
||||
unsigned int index;
|
||||
bool plugged;
|
||||
};
|
||||
|
||||
typedef std::vector<JoystickRecord> JoystickList;
|
||||
JoystickList joystickList;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Legacy joystick API
|
||||
////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
struct ConnectionCache
|
||||
@ -152,6 +202,12 @@ namespace priv
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::initialize()
|
||||
{
|
||||
// Try to initialize DirectInput
|
||||
initializeDInput();
|
||||
|
||||
if (!directInput)
|
||||
err() << "DirectInput not available, falling back to Windows joystick API" << std::endl;
|
||||
|
||||
// Perform the initial scan and populate the connection cache
|
||||
updateConnections();
|
||||
}
|
||||
@ -160,13 +216,17 @@ void JoystickImpl::initialize()
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::cleanup()
|
||||
{
|
||||
// Nothing to do
|
||||
// Clean up DirectInput
|
||||
cleanupDInput();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::isConnected(unsigned int index)
|
||||
{
|
||||
if (directInput)
|
||||
return isConnectedDInput(index);
|
||||
|
||||
ConnectionCache& cache = connectionCache[index];
|
||||
if (!lazyUpdates && cache.timer.getElapsedTime() > connectionRefreshDelay)
|
||||
{
|
||||
@ -189,6 +249,9 @@ void JoystickImpl::setLazyUpdates(bool status)
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::updateConnections()
|
||||
{
|
||||
if (directInput)
|
||||
return updateConnectionsDInput();
|
||||
|
||||
for (unsigned int i = 0; i < Joystick::Count; ++i)
|
||||
{
|
||||
JOYINFOEX joyInfo;
|
||||
@ -204,6 +267,9 @@ void JoystickImpl::updateConnections()
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::open(unsigned int index)
|
||||
{
|
||||
if (directInput)
|
||||
return openDInput(index);
|
||||
|
||||
// No explicit "open" action is required
|
||||
m_index = JOYSTICKID1 + index;
|
||||
|
||||
@ -224,12 +290,16 @@ bool JoystickImpl::open(unsigned int index)
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::close()
|
||||
{
|
||||
// Nothing to do
|
||||
if (directInput)
|
||||
closeDInput();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickCaps JoystickImpl::getCapabilities() const
|
||||
{
|
||||
if (directInput)
|
||||
return getCapabilitiesDInput();
|
||||
|
||||
JoystickCaps caps;
|
||||
|
||||
caps.buttonCount = m_caps.wNumButtons;
|
||||
@ -259,6 +329,9 @@ Joystick::Identification JoystickImpl::getIdentification() const
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickState JoystickImpl::update()
|
||||
{
|
||||
if (directInput)
|
||||
return updateDInput();
|
||||
|
||||
JoystickState state;
|
||||
|
||||
// Get the current joystick state
|
||||
@ -300,6 +373,548 @@ JoystickState JoystickImpl::update()
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::initializeDInput()
|
||||
{
|
||||
// Try to load dinput8.dll
|
||||
dinput8dll = LoadLibraryA("dinput8.dll");
|
||||
|
||||
if (dinput8dll)
|
||||
{
|
||||
// Try to get the address of the DirectInput8Create entry point
|
||||
typedef HRESULT(WINAPI *DirectInput8CreateFunc)(HINSTANCE, DWORD, REFIID, LPVOID*, LPUNKNOWN);
|
||||
DirectInput8CreateFunc directInput8Create = reinterpret_cast<DirectInput8CreateFunc>(GetProcAddress(dinput8dll, "DirectInput8Create"));
|
||||
|
||||
if (directInput8Create)
|
||||
{
|
||||
// Try to acquire a DirectInput 8.x interface
|
||||
HRESULT result = directInput8Create(GetModuleHandleW(NULL), 0x0800, guids::IID_IDirectInput8W, reinterpret_cast<void**>(&directInput), NULL);
|
||||
|
||||
if (result)
|
||||
{
|
||||
// De-initialize everything
|
||||
directInput = NULL;
|
||||
FreeLibrary(dinput8dll);
|
||||
dinput8dll = NULL;
|
||||
|
||||
err() << "Failed to initialize DirectInput: " << result << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unload dinput8.dll
|
||||
FreeLibrary(dinput8dll);
|
||||
dinput8dll = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::cleanupDInput()
|
||||
{
|
||||
// Release the DirectInput interface
|
||||
if (directInput)
|
||||
{
|
||||
directInput->Release();
|
||||
directInput = NULL;
|
||||
}
|
||||
|
||||
// Unload dinput8.dll
|
||||
if (dinput8dll)
|
||||
FreeLibrary(dinput8dll);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::isConnectedDInput(unsigned int index)
|
||||
{
|
||||
// Check if a joystick with the given index is in the connected list
|
||||
for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end(); ++i)
|
||||
{
|
||||
if (i->index == index)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::updateConnectionsDInput()
|
||||
{
|
||||
// Clear plugged flags so we can determine which devices were added/removed
|
||||
for (std::size_t i = 0; i < joystickList.size(); ++i)
|
||||
joystickList[i].plugged = false;
|
||||
|
||||
// Enumerate devices
|
||||
HRESULT result = directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, &JoystickImpl::deviceEnumerationCallback, NULL, DIEDFL_ALLDEVICES);
|
||||
|
||||
// Remove devices that were not connected during the enumeration
|
||||
for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end();)
|
||||
{
|
||||
if (!i->plugged)
|
||||
i = joystickList.erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
err() << "Failed to enumerate DirectInput devices: " << result << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign unused joystick indices to devices that were newly connected
|
||||
for (unsigned int i = 0; i < Joystick::Count; ++i)
|
||||
{
|
||||
for (std::vector<JoystickRecord>::iterator j = joystickList.begin(); j != joystickList.end(); ++j)
|
||||
{
|
||||
if (j->index == i)
|
||||
break;
|
||||
|
||||
if (j->index == Joystick::Count)
|
||||
{
|
||||
j->index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::openDInput(unsigned int index)
|
||||
{
|
||||
// Initialize DirectInput members
|
||||
m_device = NULL;
|
||||
|
||||
for (int i = 0; i < Joystick::AxisCount; ++i)
|
||||
m_axes[i] = -1;
|
||||
|
||||
for (int i = 0; i < Joystick::ButtonCount; ++i)
|
||||
m_buttons[i] = -1;
|
||||
|
||||
std::memset(&m_deviceCaps, 0, sizeof(DIDEVCAPS));
|
||||
m_deviceCaps.dwSize = sizeof(DIDEVCAPS);
|
||||
|
||||
// Search for a joystick with the given index in the connected list
|
||||
for (std::vector<JoystickRecord>::iterator i = joystickList.begin(); i != joystickList.end(); ++i)
|
||||
{
|
||||
if (i->index == index)
|
||||
{
|
||||
// Create device
|
||||
HRESULT result = directInput->CreateDevice(i->guid, &m_device, NULL);
|
||||
|
||||
if (result)
|
||||
{
|
||||
err() << "Failed to create DirectInput device: " << result << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool formatInitialized = false;
|
||||
static DIDATAFORMAT format;
|
||||
|
||||
if (!formatInitialized)
|
||||
{
|
||||
const DWORD axisType = DIDFT_AXIS | DIDFT_OPTIONAL | DIDFT_ANYINSTANCE;
|
||||
const DWORD povType = DIDFT_POV | DIDFT_OPTIONAL | DIDFT_ANYINSTANCE;
|
||||
const DWORD buttonType = DIDFT_BUTTON | DIDFT_OPTIONAL | DIDFT_ANYINSTANCE;
|
||||
|
||||
static DIOBJECTDATAFORMAT data[8 + 4 + sf::Joystick::ButtonCount];
|
||||
|
||||
data[0].pguid = &guids::GUID_XAxis;
|
||||
data[0].dwOfs = DIJOFS_X;
|
||||
|
||||
data[1].pguid = &guids::GUID_YAxis;
|
||||
data[1].dwOfs = DIJOFS_Y;
|
||||
|
||||
data[2].pguid = &guids::GUID_ZAxis;
|
||||
data[2].dwOfs = DIJOFS_Z;
|
||||
|
||||
data[3].pguid = &guids::GUID_RxAxis;
|
||||
data[3].dwOfs = DIJOFS_RX;
|
||||
|
||||
data[4].pguid = &guids::GUID_RyAxis;
|
||||
data[4].dwOfs = DIJOFS_RY;
|
||||
|
||||
data[5].pguid = &guids::GUID_RzAxis;
|
||||
data[5].dwOfs = DIJOFS_RZ;
|
||||
|
||||
data[6].pguid = &guids::GUID_Slider;
|
||||
data[6].dwOfs = DIJOFS_SLIDER(0);
|
||||
|
||||
data[7].pguid = &guids::GUID_Slider;
|
||||
data[7].dwOfs = DIJOFS_SLIDER(1);
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
data[i].dwType = axisType;
|
||||
data[i].dwFlags = DIDOI_ASPECTPOSITION;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
data[8 + i].pguid = &guids::GUID_POV;
|
||||
data[8 + i].dwOfs = static_cast<DWORD>(DIJOFS_POV(i));
|
||||
data[8 + i].dwType = povType;
|
||||
data[8 + i].dwFlags = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sf::Joystick::ButtonCount; ++i)
|
||||
{
|
||||
data[8 + 4 + i].pguid = NULL;
|
||||
data[8 + 4 + i].dwOfs = static_cast<DWORD>(DIJOFS_BUTTON(i));
|
||||
data[8 + 4 + i].dwType = buttonType;
|
||||
data[8 + 4 + i].dwFlags = 0;
|
||||
}
|
||||
|
||||
format.dwSize = sizeof(DIDATAFORMAT);
|
||||
format.dwObjSize = sizeof(DIOBJECTDATAFORMAT);
|
||||
format.dwFlags = DIDFT_ABSAXIS;
|
||||
format.dwDataSize = sizeof(DIJOYSTATE);
|
||||
format.dwNumObjs = 8 + 4 + sf::Joystick::ButtonCount;
|
||||
format.rgodf = data;
|
||||
|
||||
formatInitialized = true;
|
||||
}
|
||||
|
||||
// Set device data format
|
||||
result = m_device->SetDataFormat(&format);
|
||||
|
||||
if (result)
|
||||
{
|
||||
err() << "Failed to set DirectInput device data format: " << result << std::endl;
|
||||
|
||||
m_device->Release();
|
||||
m_device = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get device capabilities
|
||||
result = m_device->GetCapabilities(&m_deviceCaps);
|
||||
|
||||
if (result)
|
||||
{
|
||||
err() << "Failed to get DirectInput device capabilities: " << result << std::endl;
|
||||
|
||||
m_device->Release();
|
||||
m_device = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set axis mode to absolute
|
||||
DIPROPDWORD property;
|
||||
std::memset(&property, 0, sizeof(property));
|
||||
property.diph.dwSize = sizeof(property);
|
||||
property.diph.dwHeaderSize = sizeof(property.diph);
|
||||
property.diph.dwHow = DIPH_DEVICE;
|
||||
property.dwData = DIPROPAXISMODE_ABS;
|
||||
|
||||
result = m_device->SetProperty(DIPROP_AXISMODE, &property.diph);
|
||||
|
||||
if (result)
|
||||
{
|
||||
err() << "Failed to set DirectInput device axis mode: " << result << std::endl;
|
||||
|
||||
m_device->Release();
|
||||
m_device = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enumerate device objects (axes/povs/buttons)
|
||||
result = m_device->EnumObjects(&JoystickImpl::deviceObjectEnumerationCallback, this, DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV);
|
||||
|
||||
if (result)
|
||||
{
|
||||
err() << "Failed to enumerate DirectInput device objects: " << result << std::endl;
|
||||
|
||||
m_device->Release();
|
||||
m_device = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get friendly product name of the device
|
||||
DIPROPSTRING stringProperty;
|
||||
std::memset(&stringProperty, 0, sizeof(stringProperty));
|
||||
stringProperty.diph.dwSize = sizeof(stringProperty);
|
||||
stringProperty.diph.dwHeaderSize = sizeof(stringProperty.diph);
|
||||
stringProperty.diph.dwHow = DIPH_DEVICE;
|
||||
stringProperty.diph.dwObj = 0;
|
||||
|
||||
if (!m_device->GetProperty(DIPROP_PRODUCTNAME, &stringProperty.diph))
|
||||
{
|
||||
m_identification.name = stringProperty.wsz;
|
||||
}
|
||||
|
||||
// Get vendor and produce id of the device
|
||||
std::memset(&property, 0, sizeof(property));
|
||||
property.diph.dwSize = sizeof(property);
|
||||
property.diph.dwHeaderSize = sizeof(property.diph);
|
||||
property.diph.dwHow = DIPH_DEVICE;
|
||||
|
||||
if (!m_device->GetProperty(DIPROP_VIDPID, &property.diph))
|
||||
{
|
||||
m_identification.productId = HIWORD(property.dwData);
|
||||
m_identification.vendorId = LOWORD(property.dwData);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::closeDInput()
|
||||
{
|
||||
if (m_device)
|
||||
{
|
||||
// Release the device
|
||||
m_device->Release();
|
||||
m_device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickCaps JoystickImpl::getCapabilitiesDInput() const
|
||||
{
|
||||
JoystickCaps caps;
|
||||
|
||||
// Count how many buttons have valid offsets
|
||||
caps.buttonCount = 0;
|
||||
|
||||
for (int i = 0; i < Joystick::ButtonCount; ++i)
|
||||
{
|
||||
if (m_buttons[i] != -1)
|
||||
++caps.buttonCount;
|
||||
}
|
||||
|
||||
// Check which axes have valid offsets
|
||||
for (int i = 0; i < Joystick::AxisCount; ++i)
|
||||
caps.axes[i] = (m_axes[i] != -1);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickState JoystickImpl::updateDInput()
|
||||
{
|
||||
JoystickState state;
|
||||
|
||||
if (m_device)
|
||||
{
|
||||
// Poll the device
|
||||
m_device->Poll();
|
||||
|
||||
DIJOYSTATE joystate;
|
||||
|
||||
// Try to get the device state
|
||||
HRESULT result = m_device->GetDeviceState(sizeof(joystate), &joystate);
|
||||
|
||||
// If we have not acquired or have lost the device, attempt to (re-)acquire it and get the device state again
|
||||
if ((result == DIERR_NOTACQUIRED) || (result == DIERR_INPUTLOST))
|
||||
{
|
||||
m_device->Acquire();
|
||||
m_device->Poll();
|
||||
result = m_device->GetDeviceState(sizeof(joystate), &joystate);
|
||||
}
|
||||
|
||||
// If we still can't get the device state, assume it has been disconnected
|
||||
if ((result == DIERR_NOTACQUIRED) || (result == DIERR_INPUTLOST))
|
||||
{
|
||||
m_device->Release();
|
||||
m_device = NULL;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
err() << "Failed to get DirectInput device state: " << result << std::endl;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// Get the current state of each axis
|
||||
for (int i = 0; i < Joystick::AxisCount; ++i)
|
||||
{
|
||||
if (m_axes[i] != -1)
|
||||
{
|
||||
if (i == Joystick::PovX)
|
||||
{
|
||||
unsigned short value = LOWORD(*reinterpret_cast<const DWORD*>(reinterpret_cast<const char*>(&joystate) + m_axes[i]));
|
||||
|
||||
if (value != 0xFFFF)
|
||||
{
|
||||
float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f;
|
||||
|
||||
state.axes[i] = std::sin(angle) * 100.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.axes[i] = 0;
|
||||
}
|
||||
}
|
||||
else if (i == Joystick::PovY)
|
||||
{
|
||||
unsigned short value = LOWORD(*reinterpret_cast<const DWORD*>(reinterpret_cast<const char*>(&joystate) + m_axes[i]));
|
||||
|
||||
if (value != 0xFFFF)
|
||||
{
|
||||
float angle = (static_cast<float>(value)) * 3.141592654f / DI_DEGREES / 180.f;
|
||||
|
||||
state.axes[i] = std::cos(angle) * 100.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.axes[i] = 0.f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state.axes[i] = (static_cast<float>(*reinterpret_cast<const LONG*>(reinterpret_cast<const char*>(&joystate) + m_axes[i])) + 0.5f) * 100.f / 32767.5f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state.axes[i] = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the current state of each button
|
||||
for (int i = 0; i < Joystick::ButtonCount; ++i)
|
||||
{
|
||||
if (m_buttons[i] != -1)
|
||||
{
|
||||
BYTE value = *reinterpret_cast<const BYTE*>(reinterpret_cast<const char*>(&joystate) + m_buttons[i]);
|
||||
|
||||
state.buttons[i] = ((value & 0x80) != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.buttons[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
state.connected = true;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
BOOL CALLBACK JoystickImpl::deviceEnumerationCallback(const DIDEVICEINSTANCE* deviceInstance, void*)
|
||||
{
|
||||
for (std::size_t i = 0; i < joystickList.size(); ++i)
|
||||
{
|
||||
if (joystickList[i].guid == deviceInstance->guidInstance)
|
||||
{
|
||||
joystickList[i].plugged = true;
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
JoystickRecord record = { deviceInstance->guidInstance, sf::Joystick::Count, true };
|
||||
joystickList.push_back(record);
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
BOOL CALLBACK JoystickImpl::deviceObjectEnumerationCallback(const DIDEVICEOBJECTINSTANCE* deviceObjectInstance, void* userData)
|
||||
{
|
||||
sf::priv::JoystickImpl& joystick = *reinterpret_cast<sf::priv::JoystickImpl*>(userData);
|
||||
|
||||
if (DIDFT_GETTYPE(deviceObjectInstance->dwType) & DIDFT_AXIS)
|
||||
{
|
||||
// Axes
|
||||
if (deviceObjectInstance->guidType == guids::GUID_XAxis)
|
||||
joystick.m_axes[Joystick::X] = DIJOFS_X;
|
||||
else if (deviceObjectInstance->guidType == guids::GUID_YAxis)
|
||||
joystick.m_axes[Joystick::Y] = DIJOFS_Y;
|
||||
else if (deviceObjectInstance->guidType == guids::GUID_ZAxis)
|
||||
joystick.m_axes[Joystick::Z] = DIJOFS_Z;
|
||||
else if (deviceObjectInstance->guidType == guids::GUID_RzAxis)
|
||||
joystick.m_axes[Joystick::R] = DIJOFS_RZ;
|
||||
else if (deviceObjectInstance->guidType == guids::GUID_RxAxis)
|
||||
joystick.m_axes[Joystick::U] = DIJOFS_RX;
|
||||
else if (deviceObjectInstance->guidType == guids::GUID_RyAxis)
|
||||
joystick.m_axes[Joystick::V] = DIJOFS_RY;
|
||||
else if (deviceObjectInstance->guidType == guids::GUID_Slider)
|
||||
{
|
||||
if(joystick.m_axes[Joystick::U] == -1)
|
||||
joystick.m_axes[Joystick::U] = DIJOFS_SLIDER(0);
|
||||
else
|
||||
joystick.m_axes[Joystick::V] = DIJOFS_SLIDER(1);
|
||||
}
|
||||
else
|
||||
return DIENUM_CONTINUE;
|
||||
|
||||
// Set the axis' value range to that of a signed short: [-32768, 32767]
|
||||
DIPROPRANGE propertyRange;
|
||||
|
||||
std::memset(&propertyRange, 0, sizeof(propertyRange));
|
||||
propertyRange.diph.dwSize = sizeof(propertyRange);
|
||||
propertyRange.diph.dwHeaderSize = sizeof(propertyRange.diph);
|
||||
propertyRange.diph.dwObj = deviceObjectInstance->dwType;
|
||||
propertyRange.diph.dwHow = DIPH_BYID;
|
||||
propertyRange.lMin = -32768;
|
||||
propertyRange.lMax = 32767;
|
||||
|
||||
HRESULT result = joystick.m_device->SetProperty(DIPROP_RANGE, &propertyRange.diph);
|
||||
|
||||
if (result)
|
||||
err() << "Failed to set DirectInput device axis property range: " << result << std::endl;
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
else if (DIDFT_GETTYPE(deviceObjectInstance->dwType) & DIDFT_POV)
|
||||
{
|
||||
// POVs
|
||||
if (deviceObjectInstance->guidType == guids::GUID_POV)
|
||||
{
|
||||
if (joystick.m_axes[Joystick::PovX] == -1)
|
||||
{
|
||||
joystick.m_axes[Joystick::PovX] = DIJOFS_POV(0);
|
||||
joystick.m_axes[Joystick::PovY] = DIJOFS_POV(0);
|
||||
}
|
||||
}
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
else if (DIDFT_GETTYPE(deviceObjectInstance->dwType) & DIDFT_BUTTON)
|
||||
{
|
||||
// Buttons
|
||||
for (int i = 0; i < Joystick::ButtonCount; ++i)
|
||||
{
|
||||
if (joystick.m_buttons[i] == -1)
|
||||
{
|
||||
joystick.m_buttons[i] = DIJOFS_BUTTON(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
@ -34,13 +34,15 @@
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINDOWS 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define _WIN32_WINDOWS 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <SFML/Window/Joystick.hpp>
|
||||
#include <SFML/Window/JoystickImpl.hpp>
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <dinput.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -131,14 +133,100 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickState update();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global initialization of the joystick module (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void initializeDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global cleanup of the joystick module (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void cleanupDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a joystick is currently connected (DInput)
|
||||
///
|
||||
/// \param index Index of the joystick to check
|
||||
///
|
||||
/// \return True if the joystick is connected, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isConnectedDInput(unsigned int index);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the connection status of all joysticks (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void updateConnectionsDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Open the joystick (DInput)
|
||||
///
|
||||
/// \param index Index assigned to the joystick
|
||||
///
|
||||
/// \return True on success, false on failure
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool openDInput(unsigned int index);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Close the joystick (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void closeDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the joystick capabilities (DInput)
|
||||
///
|
||||
/// \return Joystick capabilities
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickCaps getCapabilitiesDInput() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the joystick and get its new state (DInput)
|
||||
///
|
||||
/// \return Joystick state
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickState updateDInput();
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Device enumeration callback function passed to EnumDevices in updateConnections
|
||||
///
|
||||
/// \param deviceInstance Device object instance
|
||||
/// \param userData User data (unused)
|
||||
///
|
||||
/// \return DIENUM_CONTINUE to continue enumerating devices or DIENUM_STOP to stop
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static BOOL CALLBACK deviceEnumerationCallback(const DIDEVICEINSTANCE* deviceInstance, void* userData);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Device object enumeration callback function passed to EnumObjects in open
|
||||
///
|
||||
/// \param deviceObjectInstance Device object instance
|
||||
/// \param userData User data (pointer to our JoystickImpl object)
|
||||
///
|
||||
/// \return DIENUM_CONTINUE to continue enumerating objects or DIENUM_STOP to stop
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static BOOL CALLBACK deviceObjectEnumerationCallback(const DIDEVICEOBJECTINSTANCE* deviceObjectInstance, void* userData);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int m_index; ///< Index of the joystick
|
||||
JOYCAPS m_caps; ///< Joystick capabilities
|
||||
Joystick::Identification m_identification; ///< Joystick identification
|
||||
unsigned int m_index; ///< Index of the joystick
|
||||
JOYCAPS m_caps; ///< Joystick capabilities
|
||||
IDirectInputDevice8W* m_device; ///< DirectInput 8.x device
|
||||
DIDEVCAPS m_deviceCaps; ///< DirectInput device capabilities
|
||||
int m_axes[Joystick::AxisCount]; ///< Offsets to the bytes containing the axes states, -1 if not available
|
||||
int m_buttons[Joystick::ButtonCount]; ///< Offsets to the bytes containing the button states, -1 if not available
|
||||
Joystick::Identification m_identification; ///< Joystick identification
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <GL/gl.h>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/Utf.hpp>
|
||||
#include <Dbt.h>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
@ -56,11 +57,6 @@
|
||||
#define MAPVK_VK_TO_VSC (0)
|
||||
#endif
|
||||
|
||||
// Avoid including <Dbt.h> just for one define
|
||||
#ifndef DBT_DEVNODES_CHANGED
|
||||
#define DBT_DEVNODES_CHANGED 0x0007
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
unsigned int windowCount = 0; // Windows owned by SFML
|
||||
@ -216,6 +212,10 @@ m_cursorGrabbed (m_fullscreen)
|
||||
// Create the window
|
||||
m_handle = CreateWindowW(className, title.toWideString().c_str(), win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(NULL), this);
|
||||
|
||||
// Register to receive device interface change notifications (used for joystick connection handling)
|
||||
DEV_BROADCAST_HDR deviceBroadcastHeader = {sizeof(DEV_BROADCAST_HDR), DBT_DEVTYP_DEVICEINTERFACE, 0};
|
||||
RegisterDeviceNotification(m_handle, &deviceBroadcastHeader, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
|
||||
|
||||
// If we're the first window handle, we only need to poll for joysticks when WM_DEVICECHANGE message is received
|
||||
if (m_handle)
|
||||
{
|
||||
@ -983,8 +983,15 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
case WM_DEVICECHANGE:
|
||||
{
|
||||
// Some sort of device change has happened, update joystick connections
|
||||
if (wParam == DBT_DEVNODES_CHANGED)
|
||||
JoystickImpl::updateConnections();
|
||||
if ((wParam == DBT_DEVICEARRIVAL) || (wParam == DBT_DEVICEREMOVECOMPLETE))
|
||||
{
|
||||
// Some sort of device change has happened, update joystick connections if it is a device interface
|
||||
DEV_BROADCAST_HDR* deviceBroadcastHeader = reinterpret_cast<DEV_BROADCAST_HDR*>(lParam);
|
||||
|
||||
if (deviceBroadcastHeader && (deviceBroadcastHeader->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE))
|
||||
JoystickImpl::updateConnections();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user