summaryrefslogtreecommitdiff
path: root/platform/windows
diff options
context:
space:
mode:
authorAndreas Haas <liu.gam3@gmail.com>2016-06-15 14:40:57 +0200
committerAndreas Haas <liu.gam3@gmail.com>2016-06-15 14:40:57 +0200
commit0e8b8600488971e5d452ad681bb41153ed8d34ad (patch)
tree6b2b981bb281d05d664595beefa74465a9f1d59c /platform/windows
parentf38f5c9e16c37e799fdcd2b71bbe7f9e66705a78 (diff)
Windows: Support gamepad vibration using XInput.
Diffstat (limited to 'platform/windows')
-rw-r--r--platform/windows/joystick.cpp55
-rw-r--r--platform/windows/joystick.h14
2 files changed, 64 insertions, 5 deletions
diff --git a/platform/windows/joystick.cpp b/platform/windows/joystick.cpp
index f8526b5ec1..663bbe3b9b 100644
--- a/platform/windows/joystick.cpp
+++ b/platform/windows/joystick.cpp
@@ -37,6 +37,7 @@
#endif
DWORD WINAPI _xinput_get_state(DWORD dwUserIndex, XINPUT_STATE* pState) { return ERROR_DEVICE_NOT_CONNECTED; }
+DWORD WINAPI _xinput_set_state(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration) { return ERROR_DEVICE_NOT_CONNECTED; }
joystick_windows::joystick_windows() {
@@ -50,6 +51,7 @@ joystick_windows::joystick_windows(InputDefault* _input, HWND* hwnd) {
dinput = NULL;
xinput_dll = NULL;
xinput_get_state = NULL;
+ xinput_set_state = NULL;
load_xinput();
@@ -300,6 +302,9 @@ void joystick_windows::probe_joysticks() {
x_joysticks[i].attached = true;
x_joysticks[i].id = id;
+ x_joysticks[i].ff_timestamp = 0;
+ x_joysticks[i].ff_end_timestamp = 0;
+ x_joysticks[i].vibrating = false;
attached_joysticks[id] = true;
input->joy_connection_changed(id, true, "XInput Gamepad","__XINPUT_DEVICE__");
}
@@ -358,6 +363,20 @@ unsigned int joystick_windows::process_joysticks(unsigned int p_last_id) {
p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_5, axis_correct(joy.state.Gamepad.bRightTrigger, true, true));
joy.last_packet = joy.state.dwPacketNumber;
}
+ uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id);
+ if (timestamp > joy.ff_timestamp) {
+ Vector2 strength = input->get_joy_vibration_strength(joy.id);
+ float duration = input->get_joy_vibration_duration(joy.id);
+ if (strength.x == 0 && strength.y == 0) {
+ joystick_vibration_stop_xinput(i, timestamp);
+ } else {
+ joystick_vibration_start_xinput(i, strength.x, strength.y, duration, timestamp);
+ }
+ } else if (joy.vibrating && joy.ff_end_timestamp != 0) {
+ uint64_t current_time = OS::get_singleton()->get_ticks_usec();
+ if (current_time >= joy.ff_end_timestamp)
+ joystick_vibration_stop_xinput(i, current_time);
+ }
}
for (int i = 0; i < JOYSTICKS_MAX; i++) {
@@ -401,7 +420,7 @@ unsigned int joystick_windows::process_joysticks(unsigned int p_last_id) {
}
}
- // on mingw, these constants are not constants
+ // on mingw, these constants are not constants
int count = 6;
int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ };
int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz };
@@ -500,9 +519,38 @@ InputDefault::JoyAxis joystick_windows::axis_correct(int p_val, bool p_xinput, b
return jx;
}
+void joystick_windows::joystick_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) {
+ xinput_gamepad &joy = x_joysticks[p_device];
+ if (joy.attached) {
+ XINPUT_VIBRATION effect;
+ effect.wLeftMotorSpeed = (65535 * p_strong_magnitude);
+ effect.wRightMotorSpeed = (65535 * p_weak_magnitude);
+ if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) {
+ joy.ff_timestamp = p_timestamp;
+ joy.ff_end_timestamp = p_duration == 0 ? 0 : p_timestamp + (uint64_t)(p_duration * 1000000.0);
+ joy.vibrating = true;
+ }
+ }
+}
+
+void joystick_windows::joystick_vibration_stop_xinput(int p_device, uint64_t p_timestamp) {
+ xinput_gamepad &joy = x_joysticks[p_device];
+ if (joy.attached) {
+ XINPUT_VIBRATION effect;
+ effect.wLeftMotorSpeed = 0;
+ effect.wRightMotorSpeed = 0;
+ if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) {
+ joy.ff_timestamp = p_timestamp;
+ joy.vibrating = false;
+ }
+ }
+}
+
+
void joystick_windows::load_xinput() {
xinput_get_state = &_xinput_get_state;
+ xinput_set_state = &_xinput_set_state;
xinput_dll = LoadLibrary( "XInput1_4.dll" );
if (!xinput_dll) {
xinput_dll = LoadLibrary("XInput1_3.dll");
@@ -519,12 +567,13 @@ void joystick_windows::load_xinput() {
}
XInputGetState_t func = (XInputGetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputGetState");
- if (!func) {
+ XInputSetState_t set_func = (XInputSetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputSetState");
+ if (!func || !set_func) {
unload_xinput();
return;
}
xinput_get_state = func;
- return;
+ xinput_set_state = set_func;
}
void joystick_windows::unload_xinput() {
diff --git a/platform/windows/joystick.h b/platform/windows/joystick.h
index 332e86fbb8..77dee0466f 100644
--- a/platform/windows/joystick.h
+++ b/platform/windows/joystick.h
@@ -39,8 +39,8 @@
#define SAFE_RELEASE(x) \
if(x != NULL) \
{ \
- x->Release(); \
- x = NULL; \
+ x->Release(); \
+ x = NULL; \
}
#endif
@@ -96,16 +96,23 @@ private:
int id;
bool attached;
+ bool vibrating;
DWORD last_packet;
XINPUT_STATE state;
+ uint64_t ff_timestamp;
+ uint64_t ff_end_timestamp;
xinput_gamepad() {
attached = false;
+ vibrating = false;
+ ff_timestamp = 0;
+ ff_end_timestamp = 0;
last_packet = 0;
}
};
typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState);
+ typedef DWORD (WINAPI *XInputSetState_t) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
HWND* hWnd;
HANDLE xinput_dll;
@@ -132,9 +139,12 @@ private:
bool have_device(const GUID &p_guid);
bool is_xinput_device(const GUID* p_guid);
bool setup_dinput_joystick(const DIDEVICEINSTANCE* instance);
+ void joystick_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
+ void joystick_vibration_stop_xinput(int p_device, uint64_t p_timestamp);
InputDefault::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
XInputGetState_t xinput_get_state;
+ XInputSetState_t xinput_set_state;
};
#endif