mirror of https://github.com/libsdl-org/SDL.git
624 lines
21 KiB
C++
624 lines
21 KiB
C++
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
#include "SDL_internal.h"
|
|
|
|
#include "SDL_windowsvideo.h"
|
|
|
|
#ifdef HAVE_GAMEINPUT_H
|
|
|
|
#include "../../core/windows/SDL_gameinput.h"
|
|
extern "C" {
|
|
#include "../../events/SDL_mouse_c.h"
|
|
#include "../../events/SDL_keyboard_c.h"
|
|
#include "../../events/scancodes_windows.h"
|
|
}
|
|
|
|
#define MAX_GAMEINPUT_BUTTONS 7 // GameInputMouseWheelTiltRight is the highest button
|
|
|
|
static const Uint8 GAMEINPUT_button_map[MAX_GAMEINPUT_BUTTONS] = {
|
|
SDL_BUTTON_LEFT,
|
|
SDL_BUTTON_RIGHT,
|
|
SDL_BUTTON_MIDDLE,
|
|
SDL_BUTTON_X1,
|
|
SDL_BUTTON_X2,
|
|
6,
|
|
7
|
|
};
|
|
|
|
typedef struct GAMEINPUT_Device
|
|
{
|
|
IGameInputDevice *pDevice;
|
|
const GameInputDeviceInfo *info;
|
|
char *name;
|
|
Uint32 instance_id; // generated by SDL
|
|
bool registered;
|
|
bool delete_requested;
|
|
IGameInputReading *last_mouse_reading;
|
|
IGameInputReading *last_keyboard_reading;
|
|
} GAMEINPUT_Device;
|
|
|
|
struct WIN_GameInputData
|
|
{
|
|
IGameInput *pGameInput;
|
|
GameInputCallbackToken gameinput_callback_token;
|
|
int num_devices;
|
|
GAMEINPUT_Device **devices;
|
|
GameInputKind enabled_input;
|
|
SDL_Mutex *lock;
|
|
uint64_t timestamp_offset;
|
|
};
|
|
|
|
static bool GAMEINPUT_InternalAddOrFind(WIN_GameInputData *data, IGameInputDevice *pDevice)
|
|
{
|
|
GAMEINPUT_Device **devicelist = NULL;
|
|
GAMEINPUT_Device *device = NULL;
|
|
const GameInputDeviceInfo *info;
|
|
bool result = false;
|
|
|
|
#if GAMEINPUT_API_VERSION >= 1
|
|
HRESULT hr = pDevice->GetDeviceInfo(&info);
|
|
if (FAILED(hr)) {
|
|
return WIN_SetErrorFromHRESULT("IGameInputDevice_GetDeviceInfo", hr);
|
|
}
|
|
#else
|
|
info = pDevice->GetDeviceInfo();
|
|
#endif
|
|
|
|
SDL_LockMutex(data->lock);
|
|
{
|
|
for (int i = 0; i < data->num_devices; ++i) {
|
|
device = data->devices[i];
|
|
if (device && device->pDevice == pDevice) {
|
|
// we're already added
|
|
device->delete_requested = false;
|
|
result = true;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
device = (GAMEINPUT_Device *)SDL_calloc(1, sizeof(*device));
|
|
if (!device) {
|
|
goto done;
|
|
}
|
|
|
|
devicelist = (GAMEINPUT_Device **)SDL_realloc(data->devices, (data->num_devices + 1) * sizeof(*devicelist));
|
|
if (!devicelist) {
|
|
SDL_free(device);
|
|
goto done;
|
|
}
|
|
|
|
if (info->displayName) {
|
|
// This could give us a product string, but it's NULL for all the devices I've tested
|
|
}
|
|
|
|
pDevice->AddRef();
|
|
device->pDevice = pDevice;
|
|
device->instance_id = SDL_GetNextObjectID();
|
|
device->info = info;
|
|
|
|
data->devices = devicelist;
|
|
data->devices[data->num_devices++] = device;
|
|
|
|
result = true;
|
|
}
|
|
done:
|
|
SDL_UnlockMutex(data->lock);
|
|
|
|
return result;
|
|
}
|
|
|
|
static bool GAMEINPUT_InternalRemoveByIndex(WIN_GameInputData *data, int idx)
|
|
{
|
|
GAMEINPUT_Device **devicelist = NULL;
|
|
GAMEINPUT_Device *device;
|
|
bool result = false;
|
|
|
|
SDL_LockMutex(data->lock);
|
|
{
|
|
if (idx < 0 || idx >= data->num_devices) {
|
|
result = SDL_SetError("GAMEINPUT_InternalRemoveByIndex argument idx %d is out of range", idx);
|
|
goto done;
|
|
}
|
|
|
|
device = data->devices[idx];
|
|
if (device) {
|
|
if (device->registered) {
|
|
if (device->info->supportedInput & GameInputKindMouse) {
|
|
SDL_RemoveMouse(device->instance_id, true);
|
|
}
|
|
if (device->info->supportedInput & GameInputKindKeyboard) {
|
|
SDL_RemoveKeyboard(device->instance_id, true);
|
|
}
|
|
if (device->last_mouse_reading) {
|
|
device->last_mouse_reading->Release();
|
|
device->last_mouse_reading = NULL;
|
|
}
|
|
if (device->last_keyboard_reading) {
|
|
device->last_keyboard_reading->Release();
|
|
device->last_keyboard_reading = NULL;
|
|
}
|
|
}
|
|
device->pDevice->Release();
|
|
SDL_free(device->name);
|
|
SDL_free(device);
|
|
}
|
|
data->devices[idx] = NULL;
|
|
|
|
if (data->num_devices == 1) {
|
|
// last element in the list, free the entire list then
|
|
SDL_free(data->devices);
|
|
data->devices = NULL;
|
|
} else {
|
|
if (idx != data->num_devices - 1) {
|
|
size_t bytes = sizeof(*devicelist) * (data->num_devices - idx - 1);
|
|
SDL_memmove(&data->devices[idx], &data->devices[idx + 1], bytes);
|
|
}
|
|
}
|
|
|
|
// decrement the count and return
|
|
--data->num_devices;
|
|
result = true;
|
|
}
|
|
done:
|
|
SDL_UnlockMutex(data->lock);
|
|
|
|
return result;
|
|
}
|
|
|
|
static void CALLBACK GAMEINPUT_InternalDeviceCallback(
|
|
_In_ GameInputCallbackToken callbackToken,
|
|
_In_ void *context,
|
|
_In_ IGameInputDevice *pDevice,
|
|
_In_ uint64_t timestamp,
|
|
_In_ GameInputDeviceStatus currentStatus,
|
|
_In_ GameInputDeviceStatus previousStatus)
|
|
{
|
|
WIN_GameInputData *data = (WIN_GameInputData *)context;
|
|
int idx = 0;
|
|
GAMEINPUT_Device *device = NULL;
|
|
|
|
if (!pDevice) {
|
|
// This should never happen, but ignore it if it does
|
|
return;
|
|
}
|
|
|
|
if (currentStatus & GameInputDeviceConnected) {
|
|
GAMEINPUT_InternalAddOrFind(data, pDevice);
|
|
} else {
|
|
for (idx = 0; idx < data->num_devices; ++idx) {
|
|
device = data->devices[idx];
|
|
if (device && device->pDevice == pDevice) {
|
|
// will be deleted on the next Detect call
|
|
device->delete_requested = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool WIN_InitGameInput(SDL_VideoDevice *_this)
|
|
{
|
|
WIN_GameInputData *data;
|
|
HRESULT hr;
|
|
Uint64 now;
|
|
uint64_t timestampUS;
|
|
bool result = false;
|
|
|
|
if (_this->internal->gameinput_context) {
|
|
return true;
|
|
}
|
|
|
|
data = (WIN_GameInputData *)SDL_calloc(1, sizeof(*data));
|
|
if (!data) {
|
|
goto done;
|
|
}
|
|
_this->internal->gameinput_context = data;
|
|
|
|
data->lock = SDL_CreateMutex();
|
|
if (!data->lock) {
|
|
goto done;
|
|
}
|
|
|
|
if (!SDL_InitGameInput(&data->pGameInput)) {
|
|
goto done;
|
|
}
|
|
|
|
hr = data->pGameInput->RegisterDeviceCallback(NULL,
|
|
(GameInputKindMouse | GameInputKindKeyboard),
|
|
GameInputDeviceConnected,
|
|
GameInputBlockingEnumeration,
|
|
data,
|
|
GAMEINPUT_InternalDeviceCallback,
|
|
&data->gameinput_callback_token);
|
|
if (FAILED(hr)) {
|
|
WIN_SetErrorFromHRESULT("IGameInput::RegisterDeviceCallback", hr);
|
|
goto done;
|
|
}
|
|
|
|
// Calculate the relative offset between SDL timestamps and GameInput timestamps
|
|
now = SDL_GetTicksNS();
|
|
timestampUS = data->pGameInput->GetCurrentTimestamp();
|
|
data->timestamp_offset = (SDL_NS_TO_US(now) - timestampUS);
|
|
|
|
result = true;
|
|
|
|
done:
|
|
if (!result) {
|
|
WIN_QuitGameInput(_this);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void GAMEINPUT_InitialMouseReading(WIN_GameInputData *data, SDL_Window *window, GAMEINPUT_Device *device, IGameInputReading *reading)
|
|
{
|
|
GameInputMouseState state;
|
|
if (reading->GetMouseState(&state)) {
|
|
Uint64 timestamp = SDL_US_TO_NS(reading->GetTimestamp() + data->timestamp_offset);
|
|
SDL_MouseID mouseID = device->instance_id;
|
|
|
|
for (int i = 0; i < MAX_GAMEINPUT_BUTTONS; ++i) {
|
|
const GameInputMouseButtons mask = GameInputMouseButtons(1 << i);
|
|
bool down = ((state.buttons & mask) != 0);
|
|
SDL_SendMouseButton(timestamp, window, mouseID, GAMEINPUT_button_map[i], down);
|
|
}
|
|
|
|
// Invalidate mouse button flags
|
|
window->internal->mouse_button_flags = (WPARAM)-1;
|
|
}
|
|
}
|
|
|
|
static void GAMEINPUT_HandleMouseDelta(WIN_GameInputData *data, SDL_Window *window, GAMEINPUT_Device *device, IGameInputReading *last_reading, IGameInputReading *reading)
|
|
{
|
|
GameInputMouseState last;
|
|
GameInputMouseState state;
|
|
if (last_reading->GetMouseState(&last) && reading->GetMouseState(&state)) {
|
|
Uint64 timestamp = SDL_US_TO_NS(reading->GetTimestamp() + data->timestamp_offset);
|
|
SDL_MouseID mouseID = device->instance_id;
|
|
|
|
GameInputMouseState delta;
|
|
delta.buttons = (state.buttons ^ last.buttons);
|
|
delta.positionX = (state.positionX - last.positionX);
|
|
delta.positionY = (state.positionY - last.positionY);
|
|
delta.wheelX = (state.wheelX - last.wheelX);
|
|
delta.wheelY = (state.wheelY - last.wheelY);
|
|
|
|
if (delta.positionX || delta.positionY) {
|
|
SDL_SendMouseMotion(timestamp, window, mouseID, true, (float)delta.positionX, (float)delta.positionY);
|
|
}
|
|
if (delta.buttons) {
|
|
for (int i = 0; i < MAX_GAMEINPUT_BUTTONS; ++i) {
|
|
const GameInputMouseButtons mask = GameInputMouseButtons(1 << i);
|
|
if (delta.buttons & mask) {
|
|
bool down = ((state.buttons & mask) != 0);
|
|
SDL_SendMouseButton(timestamp, window, mouseID, GAMEINPUT_button_map[i], down);
|
|
}
|
|
}
|
|
|
|
// Invalidate mouse button flags
|
|
window->internal->mouse_button_flags = (WPARAM)-1;
|
|
}
|
|
if (delta.wheelX || delta.wheelY) {
|
|
float fAmountX = (float)delta.wheelX / WHEEL_DELTA;
|
|
float fAmountY = (float)delta.wheelY / WHEEL_DELTA;
|
|
SDL_SendMouseWheel(timestamp, SDL_GetMouseFocus(), device->instance_id, fAmountX, fAmountY, SDL_MOUSEWHEEL_NORMAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static SDL_Scancode GetScancodeFromKeyState(const GameInputKeyState *state)
|
|
{
|
|
Uint8 index = (Uint8)(state->scanCode & 0xFF);
|
|
if ((state->scanCode & 0xFF00) == 0xE000) {
|
|
index |= 0x80;
|
|
}
|
|
return windows_scancode_table[index];
|
|
}
|
|
|
|
static bool KeysHaveScancode(const GameInputKeyState *keys, uint32_t count, SDL_Scancode scancode)
|
|
{
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
if (GetScancodeFromKeyState(&keys[i]) == scancode) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void GAMEINPUT_InitialKeyboardReading(WIN_GameInputData *data, SDL_Window *window, GAMEINPUT_Device *device, IGameInputReading *reading)
|
|
{
|
|
Uint64 timestamp = SDL_US_TO_NS(reading->GetTimestamp() + data->timestamp_offset);
|
|
SDL_KeyboardID keyboardID = device->instance_id;
|
|
|
|
uint32_t max_keys = device->info->keyboardInfo->maxSimultaneousKeys;
|
|
GameInputKeyState *keys = SDL_stack_alloc(GameInputKeyState, max_keys);
|
|
if (!keys) {
|
|
return;
|
|
}
|
|
|
|
uint32_t num_keys = reading->GetKeyState(max_keys, keys);
|
|
if (!num_keys) {
|
|
// FIXME: We probably need to track key state by keyboardID
|
|
SDL_ResetKeyboard();
|
|
return;
|
|
}
|
|
|
|
// Go through and send key up events for any key that's not held down
|
|
int num_scancodes;
|
|
const bool *keyboard_state = SDL_GetKeyboardState(&num_scancodes);
|
|
for (int i = 0; i < num_scancodes; ++i) {
|
|
if (keyboard_state[i] && !KeysHaveScancode(keys, num_keys, (SDL_Scancode)i)) {
|
|
SDL_SendKeyboardKey(timestamp, keyboardID, keys[i].scanCode, (SDL_Scancode)i, false);
|
|
}
|
|
}
|
|
|
|
// Go through and send key down events for any key that's held down
|
|
for (uint32_t i = 0; i < num_keys; ++i) {
|
|
SDL_SendKeyboardKey(timestamp, keyboardID, keys[i].scanCode, GetScancodeFromKeyState(&keys[i]), true);
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_KEYS
|
|
static void DumpKeys(const char *prefix, GameInputKeyState *keys, uint32_t count)
|
|
{
|
|
SDL_Log("%s", prefix);
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
char str[5];
|
|
*SDL_UCS4ToUTF8(keys[i].codePoint, str) = '\0';
|
|
SDL_Log(" Key 0x%.2x (%s)", keys[i].scanCode, str);
|
|
}
|
|
}
|
|
#endif // DEBUG_KEYS
|
|
|
|
static void GAMEINPUT_HandleKeyboardDelta(WIN_GameInputData *data, SDL_Window *window, GAMEINPUT_Device *device, IGameInputReading *last_reading, IGameInputReading *reading)
|
|
{
|
|
Uint64 timestamp = SDL_US_TO_NS(reading->GetTimestamp() + data->timestamp_offset);
|
|
SDL_KeyboardID keyboardID = device->instance_id;
|
|
|
|
uint32_t max_keys = device->info->keyboardInfo->maxSimultaneousKeys;
|
|
GameInputKeyState *last = SDL_stack_alloc(GameInputKeyState, max_keys);
|
|
GameInputKeyState *keys = SDL_stack_alloc(GameInputKeyState, max_keys);
|
|
if (!last || !keys) {
|
|
return;
|
|
}
|
|
|
|
uint32_t index_last = 0;
|
|
uint32_t index_keys = 0;
|
|
uint32_t num_last = last_reading->GetKeyState(max_keys, last);
|
|
uint32_t num_keys = reading->GetKeyState(max_keys, keys);
|
|
#ifdef DEBUG_KEYS
|
|
SDL_Log("Timestamp: %llu", timestamp);
|
|
DumpKeys("Last keys:", last, num_last);
|
|
DumpKeys("New keys:", keys, num_keys);
|
|
#endif
|
|
while (index_last < num_last || index_keys < num_keys) {
|
|
if (index_last < num_last && index_keys < num_keys) {
|
|
if (last[index_last].scanCode == keys[index_keys].scanCode) {
|
|
// No change
|
|
++index_last;
|
|
++index_keys;
|
|
} else {
|
|
// This key was released
|
|
SDL_SendKeyboardKey(timestamp, keyboardID, last[index_last].scanCode, GetScancodeFromKeyState(&last[index_last]), false);
|
|
++index_last;
|
|
}
|
|
} else if (index_last < num_last) {
|
|
// This key was released
|
|
SDL_SendKeyboardKey(timestamp, keyboardID, last[index_last].scanCode, GetScancodeFromKeyState(&last[index_last]), false);
|
|
++index_last;
|
|
} else {
|
|
// This key was pressed
|
|
SDL_SendKeyboardKey(timestamp, keyboardID, keys[index_keys].scanCode, GetScancodeFromKeyState(&keys[index_keys]), true);
|
|
++index_keys;
|
|
}
|
|
}
|
|
}
|
|
|
|
void WIN_UpdateGameInput(SDL_VideoDevice *_this)
|
|
{
|
|
WIN_GameInputData *data = _this->internal->gameinput_context;
|
|
|
|
SDL_LockMutex(data->lock);
|
|
{
|
|
// Key events and relative mouse motion both go to the window with keyboard focus
|
|
SDL_Window *window = SDL_GetKeyboardFocus();
|
|
|
|
for (int i = 0; i < data->num_devices; ++i) {
|
|
GAMEINPUT_Device *device = data->devices[i];
|
|
IGameInputReading *reading;
|
|
|
|
if (!device->registered) {
|
|
if (device->info->supportedInput & GameInputKindMouse) {
|
|
SDL_AddMouse(device->instance_id, device->name, true);
|
|
}
|
|
if (device->info->supportedInput & GameInputKindKeyboard) {
|
|
SDL_AddKeyboard(device->instance_id, device->name, true);
|
|
}
|
|
device->registered = true;
|
|
}
|
|
|
|
if (device->delete_requested) {
|
|
GAMEINPUT_InternalRemoveByIndex(data, i--);
|
|
continue;
|
|
}
|
|
|
|
if (!(device->info->supportedInput & data->enabled_input)) {
|
|
continue;
|
|
}
|
|
|
|
if (!window) {
|
|
continue;
|
|
}
|
|
|
|
if (data->enabled_input & GameInputKindMouse) {
|
|
if (device->last_mouse_reading) {
|
|
HRESULT hr;
|
|
while (SUCCEEDED(hr = data->pGameInput->GetNextReading(device->last_mouse_reading, GameInputKindMouse, device->pDevice, &reading))) {
|
|
GAMEINPUT_HandleMouseDelta(data, window, device, device->last_mouse_reading, reading);
|
|
device->last_mouse_reading->Release();
|
|
device->last_mouse_reading = reading;
|
|
}
|
|
if (hr != GAMEINPUT_E_READING_NOT_FOUND) {
|
|
if (SUCCEEDED(data->pGameInput->GetCurrentReading(GameInputKindMouse, device->pDevice, &reading))) {
|
|
GAMEINPUT_HandleMouseDelta(data, window, device, device->last_mouse_reading, reading);
|
|
device->last_mouse_reading->Release();
|
|
device->last_mouse_reading = reading;
|
|
}
|
|
}
|
|
} else {
|
|
if (SUCCEEDED(data->pGameInput->GetCurrentReading(GameInputKindMouse, device->pDevice, &reading))) {
|
|
GAMEINPUT_InitialMouseReading(data, window, device, reading);
|
|
device->last_mouse_reading = reading;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data->enabled_input & GameInputKindKeyboard) {
|
|
if (window->text_input_active) {
|
|
// Reset raw input while text input is active
|
|
if (device->last_keyboard_reading) {
|
|
device->last_keyboard_reading->Release();
|
|
device->last_keyboard_reading = NULL;
|
|
}
|
|
} else {
|
|
if (device->last_keyboard_reading) {
|
|
HRESULT hr;
|
|
while (SUCCEEDED(hr = data->pGameInput->GetNextReading(device->last_keyboard_reading, GameInputKindKeyboard, device->pDevice, &reading))) {
|
|
GAMEINPUT_HandleKeyboardDelta(data, window, device, device->last_keyboard_reading, reading);
|
|
device->last_keyboard_reading->Release();
|
|
device->last_keyboard_reading = reading;
|
|
}
|
|
if (hr != GAMEINPUT_E_READING_NOT_FOUND) {
|
|
if (SUCCEEDED(data->pGameInput->GetCurrentReading(GameInputKindKeyboard, device->pDevice, &reading))) {
|
|
GAMEINPUT_HandleKeyboardDelta(data, window, device, device->last_keyboard_reading, reading);
|
|
device->last_keyboard_reading->Release();
|
|
device->last_keyboard_reading = reading;
|
|
}
|
|
}
|
|
} else {
|
|
if (SUCCEEDED(data->pGameInput->GetCurrentReading(GameInputKindKeyboard, device->pDevice, &reading))) {
|
|
GAMEINPUT_InitialKeyboardReading(data, window, device, reading);
|
|
device->last_keyboard_reading = reading;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SDL_UnlockMutex(data->lock);
|
|
}
|
|
|
|
bool WIN_UpdateGameInputEnabled(SDL_VideoDevice *_this)
|
|
{
|
|
WIN_GameInputData *data = _this->internal->gameinput_context;
|
|
bool raw_mouse_enabled = _this->internal->raw_mouse_enabled;
|
|
bool raw_keyboard_enabled = _this->internal->raw_keyboard_enabled;
|
|
|
|
SDL_LockMutex(data->lock);
|
|
{
|
|
data->enabled_input = (raw_mouse_enabled ? GameInputKindMouse : GameInputKindUnknown) |
|
|
(raw_keyboard_enabled ? GameInputKindKeyboard : GameInputKindUnknown);
|
|
|
|
// Reset input if not enabled
|
|
for (int i = 0; i < data->num_devices; ++i) {
|
|
GAMEINPUT_Device *device = data->devices[i];
|
|
|
|
if (device->last_mouse_reading && !raw_mouse_enabled) {
|
|
device->last_mouse_reading->Release();
|
|
device->last_mouse_reading = NULL;
|
|
}
|
|
|
|
if (device->last_keyboard_reading && !raw_keyboard_enabled) {
|
|
device->last_keyboard_reading->Release();
|
|
device->last_keyboard_reading = NULL;
|
|
}
|
|
}
|
|
}
|
|
SDL_UnlockMutex(data->lock);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WIN_QuitGameInput(SDL_VideoDevice *_this)
|
|
{
|
|
WIN_GameInputData *data = _this->internal->gameinput_context;
|
|
|
|
if (!data) {
|
|
return;
|
|
}
|
|
|
|
if (data->pGameInput) {
|
|
// free the callback
|
|
if (data->gameinput_callback_token) {
|
|
#if GAMEINPUT_API_VERSION >= 1
|
|
data->pGameInput->UnregisterCallback(data->gameinput_callback_token);
|
|
#else
|
|
data->pGameInput->UnregisterCallback(data->gameinput_callback_token, 10000);
|
|
#endif
|
|
data->gameinput_callback_token = 0;
|
|
}
|
|
|
|
// free the list
|
|
while (data->num_devices > 0) {
|
|
GAMEINPUT_InternalRemoveByIndex(data, 0);
|
|
}
|
|
|
|
data->pGameInput->Release();
|
|
data->pGameInput = NULL;
|
|
}
|
|
|
|
if (data->pGameInput) {
|
|
SDL_QuitGameInput();
|
|
data->pGameInput = NULL;
|
|
}
|
|
|
|
if (data->lock) {
|
|
SDL_DestroyMutex(data->lock);
|
|
data->lock = NULL;
|
|
}
|
|
|
|
SDL_free(data);
|
|
_this->internal->gameinput_context = NULL;
|
|
}
|
|
|
|
#else // !HAVE_GAMEINPUT_H
|
|
|
|
bool WIN_InitGameInput(SDL_VideoDevice *_this)
|
|
{
|
|
return SDL_Unsupported();
|
|
}
|
|
|
|
bool WIN_UpdateGameInputEnabled(SDL_VideoDevice *_this)
|
|
{
|
|
return SDL_Unsupported();
|
|
}
|
|
|
|
void WIN_UpdateGameInput(SDL_VideoDevice *_this)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void WIN_QuitGameInput(SDL_VideoDevice *_this)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#endif // HAVE_GAMEINPUT_H
|