4#include "gamepad_driver.h"
9#pragma warning (disable:4995)
12using namespace gamepad;
15float convert(BYTE value) {
return (
float)value / 255; }
16float convert(SHORT value) {
return value > 0 ? (float)value / 32767 : (float)value / 32768; }
17float convert(WORD value) {
return (
float)value / 65535; }
20void* get_handle(
int user_index)
22 void* device_handle = 0;
23 (
int&)device_handle = user_index;
28int get_user_index(
void* device_handle)
30 int user_index = (
int&)device_handle;
31 assert(user_index >= 0 && user_index < 4);
39 xinput_gamepad_driver(
const std::string& options)
41 for (
unsigned user_index = 0; user_index < 4; ++user_index)
42 enabled[user_index] =
true;
45 std::string get_name()
47 return "XInput Gamepad Driver";
50 void set_driver_state(
bool enabled)
52 XInputEnable(enabled ? TRUE : FALSE);
55 void scan_devices(std::vector<device_info>& infos)
57 XINPUT_CAPABILITIES caps;
58 unsigned nr_devices = 0;
59 for (
unsigned user_index = 0; user_index < 4; ++user_index) {
60 DWORD result = XInputGetCapabilities(user_index, XINPUT_FLAG_GAMEPAD, &caps);
61 if (result == ERROR_DEVICE_NOT_CONNECTED) {
62 enabled[user_index] =
false;
65 enabled[user_index] =
true;
66 infos.resize(infos.size() + 1);
67 infos.back().device_handle = get_handle(user_index);
68 infos.back().enabled =
true;
69 infos.back().force_feedback_support = (caps.Flags | XINPUT_CAPS_FFB_SUPPORTED) != 0;
70 infos.back().is_wireless = (caps.Flags | XINPUT_CAPS_WIRELESS) != 0;
71 infos.back().no_menu_buttons = (caps.Flags | XINPUT_CAPS_NO_NAVIGATION) != 0;
72 infos.back().name = std::string(
"controler_");
73 infos.back().name +=
'0' + user_index;
74 infos.back().vibration_strength[0] = convert(caps.Vibration.wLeftMotorSpeed);
75 infos.back().vibration_strength[1] = convert(caps.Vibration.wRightMotorSpeed);
79 void set_device_state(
void* device_handle,
bool _enabled)
81 enabled[get_user_index(device_handle)] = _enabled;
84 bool get_device_battery_info(
void* device_handle, BatteryType& battery_type,
float& fill_state)
86 int user_index = get_user_index(device_handle);
87 XINPUT_BATTERY_INFORMATION battery_info;
88 DWORD result = XInputGetBatteryInformation(user_index, BATTERY_DEVTYPE_GAMEPAD, &battery_info);
89 if (result == ERROR_DEVICE_NOT_CONNECTED)
91 switch (battery_info.BatteryType) {
92 case BATTERY_TYPE_DISCONNECTED:
return false;
93 case BATTERY_TYPE_WIRED: battery_type = BT_WIRED;
break;
94 case BATTERY_TYPE_ALKALINE: battery_type = BT_ALKALINE;
break;
95 case BATTERY_TYPE_NIMH: battery_type = BT_NIMH;
break;
96 case BATTERY_TYPE_UNKNOWN: battery_type = BT_UNKNOWN;
break;
99 switch (battery_info.BatteryLevel) {
100 case BATTERY_LEVEL_EMPTY: fill_state = 0.0f;
break;
101 case BATTERY_LEVEL_LOW: fill_state = 0.2f;
break;
102 case BATTERY_LEVEL_MEDIUM: fill_state = 0.5f;
break;
103 case BATTERY_LEVEL_FULL: fill_state = 1.0f;
break;
108 bool query_device_key_event(
void* device_handle, GamepadKeys& gk, KeyAction& action)
110 XINPUT_KEYSTROKE keystroke;
111 DWORD result = XInputGetKeystroke(get_user_index(device_handle), 0, &keystroke);
112 if (result == ERROR_DEVICE_NOT_CONNECTED)
114 if (result == ERROR_EMPTY)
116 switch (keystroke.VirtualKey) {
117 case VK_PAD_A: gk = GPK_A;
break;
118 case VK_PAD_B: gk = GPK_B;
break;
119 case VK_PAD_X: gk = GPK_X;
break;
120 case VK_PAD_Y: gk = GPK_Y;
break;
121 case VK_PAD_RSHOULDER: gk = GPK_RIGHT_BUMPER;
break;
122 case VK_PAD_LSHOULDER: gk = GPK_LEFT_BUMPER;
break;
123 case VK_PAD_LTRIGGER: gk = GPK_LEFT_TRIGGER;
break;
124 case VK_PAD_RTRIGGER: gk = GPK_RIGHT_TRIGGER;
break;
125 case VK_PAD_DPAD_UP: gk = GPK_DPAD_UP;
break;
126 case VK_PAD_DPAD_DOWN: gk = GPK_DPAD_DOWN;
break;
127 case VK_PAD_DPAD_LEFT: gk = GPK_DPAD_LEFT;
break;
128 case VK_PAD_DPAD_RIGHT: gk = GPK_DPAD_RIGHT;
break;
129 case VK_PAD_START: gk = GPK_START;
break;
130 case VK_PAD_BACK: gk = GPK_BACK;
break;
131 case VK_PAD_LTHUMB_PRESS: gk = GPK_LEFT_STICK_PRESS;
break;
132 case VK_PAD_RTHUMB_PRESS: gk = GPK_RIGHT_STICK_PRESS;
break;
133 case VK_PAD_LTHUMB_UP: gk = GPK_LEFT_STICK_UP;
break;
134 case VK_PAD_LTHUMB_DOWN: gk = GPK_LEFT_STICK_DOWN;
break;
135 case VK_PAD_LTHUMB_RIGHT: gk = GPK_LEFT_STICK_RIGHT;
break;
136 case VK_PAD_LTHUMB_LEFT: gk = GPK_LEFT_STICK_LEFT;
break;
137 case VK_PAD_LTHUMB_UPLEFT: gk = GPK_LEFT_STICK_UPLEFT;
break;
138 case VK_PAD_LTHUMB_UPRIGHT: gk = GPK_LEFT_STICK_UPRIGHT;
break;
139 case VK_PAD_LTHUMB_DOWNRIGHT: gk = GPK_LEFT_STICK_DOWNRIGHT;
break;
140 case VK_PAD_LTHUMB_DOWNLEFT: gk = GPK_LEFT_STICK_DOWNLEFT;
break;
141 case VK_PAD_RTHUMB_UP: gk = GPK_RIGHT_STICK_UP;
break;
142 case VK_PAD_RTHUMB_DOWN: gk = GPK_RIGHT_STICK_DOWN;
break;
143 case VK_PAD_RTHUMB_RIGHT: gk = GPK_RIGHT_STICK_RIGHT;
break;
144 case VK_PAD_RTHUMB_LEFT: gk = GPK_RIGHT_STICK_LEFT;
break;
145 case VK_PAD_RTHUMB_UPLEFT: gk = GPK_RIGHT_STICK_UPLEFT;
break;
146 case VK_PAD_RTHUMB_UPRIGHT: gk = GPK_RIGHT_STICK_UPRIGHT;
break;
147 case VK_PAD_RTHUMB_DOWNRIGHT: gk = GPK_RIGHT_STICK_DOWNRIGHT;
break;
148 case VK_PAD_RTHUMB_DOWNLEFT: gk = GPK_RIGHT_STICK_DOWNLEFT;
break;
149 default: gk = GPK_UNKNOWN;
break;
151 switch (keystroke.Flags) {
152 case XINPUT_KEYSTROKE_KEYUP: action = KA_RELEASE;
break;
153 case XINPUT_KEYSTROKE_KEYDOWN: action = KA_PRESS;
break;
154 case XINPUT_KEYSTROKE_KEYDOWN + XINPUT_KEYSTROKE_REPEAT: action = KA_REPEAT;
break;
155 default: action = KeyAction(-1);
break;
160 bool xinput_gamepad_driver::get_device_state(
void* device_handle,
gamepad_state& state)
162 XINPUT_STATE pad_state;
163 DWORD result = XInputGetState(get_user_index(device_handle), &pad_state);
164 if (result == ERROR_DEVICE_NOT_CONNECTED)
177 bool xinput_gamepad_driver::set_device_vibration(
void* device_handle,
float low_frequency_strength,
float high_frequency_strength)
179 XINPUT_VIBRATION vibration;
180 vibration.wLeftMotorSpeed = WORD(low_frequency_strength * 65535);
181 vibration.wRightMotorSpeed = WORD(high_frequency_strength * 65535);
182 DWORD result = XInputSetState(get_user_index(device_handle), &vibration);
183 if (result == ERROR_DEVICE_NOT_CONNECTED)
use this template to register your own driver
interface class for gamepad drivers, when implementing your driver, provide a constructor with a sing...
see https://upload.wikimedia.org/wikipedia/commons/2/2c/360_controller.svg for an explanation of the ...
float right_stick_position[2]
x and y position of left thumb in the range [-1,1]
unsigned time_stamp
time stamp can be used whether a change has happened between two states
float left_stick_position[2]
x and y position of left thumb in the range [-1,1]
unsigned button_flags
combination of flags in GamepadButtonStateFlags combined with the OR operation
float trigger_position[2]
values of left and right triggers in the range [0,1]