optimized boot speed(use safetyhook) & more optimized IO latency & update SDL3(fix conflict, thanks @asesidaa)

This commit is contained in:
ptmaster
2024-12-14 02:07:27 +08:00
parent f338074851
commit e2ff0b4630
7 changed files with 276 additions and 213 deletions
+6 -7
View File
@@ -94,15 +94,15 @@ FetchContent_Declare(
set(SAFETYHOOK_FETCH_ZYDIS ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(safetyhook)
# Fetch SDL2
# Fetch SDL3
FetchContent_Declare(
SDL2
URL https://github.com/libsdl-org/SDL/releases/download/release-2.26.5/SDL2-2.26.5.tar.gz
SDL3
URL https://github.com/libsdl-org/SDL/releases/download/preview-3.1.6/SDL3-3.1.6.tar.gz
)
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
set(SDL_STATIC ON CACHE BOOL "" FORCE)
set(SDL_TEST OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(SDL2)
FetchContent_MakeAvailable(SDL3)
# Fetch xxHash
FetchContent_Declare(
@@ -137,7 +137,6 @@ set(SOURCES
src/patches/audio.cpp
src/patches/plugins.cpp
src/patches/scanner.cpp
# src/patches/qr.cpp
src/patches/layeredfs.cpp
src/patches/testmode.cpp
src/patches/timer.cpp
@@ -157,7 +156,7 @@ set_target_properties(bnusio PROPERTIES PREFIX "")
target_include_directories(bnusio PRIVATE
src
${tomlc99_SOURCE_DIR}
${SDL2_SOURCE_DIR}/include
${SDL3_SOURCE_DIR}/include
${xxhash_SOURCE_DIR}
${zlib_SOURCE_DIR}
${libtomcrypt_SOURCE_DIR}/src/headers
@@ -177,7 +176,7 @@ endif()
# Link libraries
target_link_libraries(bnusio PRIVATE
tomlc99
SDL2-static
SDL3-static
xxhash
zlibstatic
libtomcrypt
+14 -12
View File
@@ -35,7 +35,7 @@ Keybindings SERVICE = {.keycodes = {VK_F2}};
Keybindings DEBUG_UP = {.keycodes = {VK_UP}};
Keybindings DEBUG_DOWN = {.keycodes = {VK_DOWN}};
Keybindings DEBUG_ENTER = {.keycodes = {VK_RETURN}};
Keybindings COIN_ADD = {.keycodes = {VK_RETURN}, .buttons = {SDL_CONTROLLER_BUTTON_START}};
Keybindings COIN_ADD = {.keycodes = {VK_RETURN}, .buttons = {SDL_GAMEPAD_BUTTON_START}};
Keybindings CARD_INSERT_1 = {.keycodes = {'P'}};
Keybindings CARD_INSERT_2 = {};
Keybindings QR_DATA_READ = {.keycodes = {'Q'}};
@@ -52,15 +52,17 @@ Keybindings P2_RIGHT_BLUE = {.keycodes = {'V'}};
// CARD_INSERT_1, CARD_INSERT_2, QR_DATA_READ, QR_IMAGE_READ, P1_LEFT_BLUE, P1_LEFT_RED,
// P1_RIGHT_RED, P1_RIGHT_BLUE, P2_LEFT_BLUE, P2_LEFT_RED, P2_RIGHT_RED, P2_RIGHT_BLUE };
const int exitWait = 100;
int exited = 0;
bool testEnabled = false;
int coin_count = 0;
int service_count = 0;
bool inited = false;
bool updateByCoin = false;
HWND windowHandle = nullptr;
bool usePoll = false;
const int exitWait = 100;
int exited = 0;
bool testEnabled = false;
bool insert_coin = false;
bool insert_service = false;
u16 coin_count = 0;
u16 service_count = 0;
bool inited = false;
bool updateByCoin = false;
HWND windowHandle = nullptr;
bool usePoll = false;
HKL currentLayout;
namespace bnusio {
@@ -293,9 +295,9 @@ UpdateLoop () {
#endif
std::vector<uint8_t> buffer = {};
if (IsButtonTapped (COIN_ADD)) coin_count++;
if (IsButtonTapped (SERVICE) && !testEnabled) service_count++;
if (IsButtonTapped (SERVICE)) service_count++;
if (IsButtonTapped (TEST)) testEnabled = !testEnabled;
if (IsButtonTapped (EXIT)) {
if (IsButtonTapped (EXIT)) {
LogMessage (LogLevel::INFO, "Exit By Press Exit Button!");
exited += 1; testEnabled = 1; patches::Plugins::Exit ();
}
+38 -18
View File
@@ -47,8 +47,10 @@ namespace Card {
};
namespace Internal {
enum CardErrorCode { ReadError = -201, NotSupport = -400 };
void
AgentInsertCard (uint8_t cardData[168], bool internalInvoke) {
InsertCard (uint8_t cardData[168], bool internalInvoke) {
if (callbackTouch) {
state = internalInvoke ? State::Disable : State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
@@ -68,7 +70,16 @@ namespace Card {
}
void
AgentInsertCardPlugin (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) {
InsertError (CardErrorCode errorCode) {
if (callbackTouch) {
state = State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
callbackTouch (0, errorCode, cardData, touchData);
}
}
void
AgentCallbackTouch (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) {
if (callbackTouch) {
state = State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
@@ -77,10 +88,11 @@ namespace Card {
}
void
AgentInsertCardOfficial (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) {
AgentCallbackTouchOfficial (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) {
if (callbackTouch) {
state = State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
LogMessage (LogLevel::DEBUG, "Official CallbackTouch a1={} a2={}", a1, a2);
if (acceptInvalidCards && !a3[0]) {
char AccessId[21] = "00000000000000000001";
uint8_t UID[8] = {a3[12], a3[14], a3[15], a3[16], 0x90, 0x00, 0x00, 0x00};
@@ -105,7 +117,7 @@ namespace Card {
for (size_t i = 0; i < 32; i++) *(cardData + 0x2C + i) = i < chipId.length() ? chipId[i] : 0;
for (size_t i = 0; i < 20; i++) *(cardData + 0x50 + i) = i < accessCode.length() ? accessCode[i] : 0;
if (!internalInvoke) LogMessage (LogLevel::INFO, "[Card] Insert Card accessCode: \"{}\" chipId: \"{}\"", accessCode, chipId);
patches::Scanner::Card::Internal::AgentInsertCard (cardData, internalInvoke);
patches::Scanner::Card::Internal::InsertCard (cardData, internalInvoke);
return true;
}
}
@@ -143,7 +155,7 @@ namespace Card {
FAST_HOOK (u64, bngrw_ReqWaitTouch, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, CallbackTouch callback, u64 a5) {
state = State::Ready;
patches::Plugins::UpdateStatus (1, true);
patches::Plugins::WaitTouch (Internal::AgentInsertCardPlugin, a5);
patches::Plugins::WaitTouch (Internal::AgentCallbackTouch, a5);
callbackTouch = callback;
touchData = a5;
return 1;
@@ -161,7 +173,7 @@ namespace Card {
patches::Plugins::UpdateStatus (1, true);
callbackTouch = callback;
touchData = a5;
return originalbngrw_ReqWaitTouchOfficial (a1, a2, a3, Internal::AgentInsertCardOfficial, a5);
return originalbngrw_ReqWaitTouchOfficial (a1, a2, a3, Internal::AgentCallbackTouchOfficial, a5);
}
bool
@@ -176,10 +188,12 @@ namespace Card {
}
if (accessCode.length() == 0 || accessCode.length() > 20) {
LogMessage (LogLevel::ERROR, "[Card] Not an effective accessCode: \"{}\"", accessCode);
patches::Scanner::Card::Internal::InsertError (Internal::CardErrorCode::NotSupport);
return false;
}
if (chipId.length() > 32) {
LogMessage (LogLevel::ERROR, "[Card] Not an effective chipId: \"{}\"", chipId);
patches::Scanner::Card::Internal::InsertError (Internal::CardErrorCode::NotSupport);
return false;
}
return patches::Scanner::Card::Internal::Commit0 (accessCode, chipId, false);
@@ -226,7 +240,7 @@ namespace Card {
}
}
namespace Qr {
std::queue<std::vector<uint8_t>> scanQueue;
std::queue<std::vector<uint8_t> *> scanQueue;
State state = State::Disable;
long long lastScan;
@@ -256,20 +270,26 @@ namespace Qr {
patches::Plugins::UsingQr ();
lastScan = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count ();
if (state == State::CopyWait && scanQueue.size () > 0) {
std::vector<uint8_t> data = scanQueue.front ();
if ((int)data.size () > length) {
LogMessage (LogLevel::ERROR, "[QR] Not an effective code, length: {} require: {}", data.size (), length);
std::vector<uint8_t> *data = scanQueue.front ();
if ((int)data->size () > length) {
LogMessage (LogLevel::ERROR, "[QR] Not an effective code, length: {} require: {}", data->size (), length);
}
std::stringstream hexStream;
hexStream << std::hex << std::uppercase << std::setfill ('0') << std::setw (2);
for (size_t i = 0; i < data.size (); i++) hexStream << static_cast<int> (data[i]) << " ";
LogMessage (LogLevel::INFO, "[QR] Read QRData size: {} data: {}\n", data.size (), hexStream.str ());
memcpy (dest, data.data (), data.size () + 1);
for (size_t i = 0; i < data->size (); i++) hexStream << static_cast<int> ((*data)[i]) << " ";
LogMessage (LogLevel::INFO, "[QR] Read QRData size: {} data: {}\n", data->size (), hexStream.str ());
size_t finalCopySize = std::min (data->size () + 1, (size_t)length);
memcpy (dest, data->data (), finalCopySize);
scanQueue.pop ();
delete data;
if (scanQueue.size () == 0) state = State::Ready;
return data.size ();
return finalCopySize;
} else if (state == State::Disable) {
while (!scanQueue.empty ()) scanQueue.pop ();
while (!scanQueue.empty ()) {
std::vector<uint8_t> *data = scanQueue.front ();
delete data;
scanQueue.pop ();
}
state = State::Ready;
patches::Plugins::UpdateStatus (2, true);
}
@@ -290,10 +310,10 @@ namespace Qr {
LogMessage (LogLevel::ERROR, "[QR] Not an effective code, length: 0");
return false;
}
if (scanQueue.empty() || scanQueue.back() != buffer) {
std::vector<uint8_t> scanData = {};
if (scanQueue.empty() || *scanQueue.back() != buffer) {
std::vector<uint8_t> *scanData = new std::vector<uint8_t> ();
for (uint8_t byte_data : buffer)
scanData.push_back (byte_data);
scanData->push_back (byte_data);
scanQueue.push (scanData);
}
if (state == State::Ready) state = State::CopyWait;
+82 -64
View File
@@ -2,18 +2,20 @@
#ifndef ASYNC_IO
#include "polldef.h"
#include <SDL3/SDL_main.h>
extern bool jpLayout;
bool currentKeyboardState[0xFF];
bool lastKeyboardState[0xFF];
bool currentControllerButtonsState[SDL_CONTROLLER_BUTTON_MAX];
bool lastControllerButtonsState[SDL_CONTROLLER_BUTTON_MAX];
bool currentControllerButtonsState[SDL_GAMEPAD_BUTTON_COUNT];
bool lastControllerButtonsState[SDL_GAMEPAD_BUTTON_COUNT];
SDLAxisState currentControllerAxisState;
SDLAxisState lastControllerAxisState;
SDL_Window *window;
SDL_GameController *controllers[255];
SDL_Gamepad *controllers[255];
void
SetKeyboardButtons () {
@@ -32,7 +34,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin
memset (key_bind, 0, sizeof (*key_bind));
for (size_t i = 0; i < std::size (key_bind->buttons); i++)
key_bind->buttons[i] = SDL_CONTROLLER_BUTTON_INVALID;
key_bind->buttons[i] = SDL_GAMEPAD_BUTTON_INVALID;
for (int idx = 0;; idx++) {
const auto [ok, u] = toml_string_at (array, idx);
@@ -54,7 +56,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin
case button: {
*usePoll = true;
for (int i = 0; i < std::size (key_bind->buttons); i++) {
if (key_bind->buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) {
if (key_bind->buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) {
key_bind->buttons[i] = value.button;
break;
}
@@ -95,36 +97,51 @@ InitializePoll (const HWND windowHandle) {
SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5, "1");
SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO) != 0) {
if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO) == 0) {
if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO) != 0) {
if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO) == 0) {
hasRumble = false;
} else {
LogMessage (LogLevel::ERROR,
std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ")
std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ")
+ SDL_GetError ());
return false;
}
}
if (const auto configPath = std::filesystem::current_path () / "gamecontrollerdb.txt";
SDL_GameControllerAddMappingsFromFile (configPath.string ().c_str ()) == -1)
SDL_AddGamepadMappingsFromFile (configPath.string ().c_str ()) == -1)
LogMessage (LogLevel::ERROR, "Cannot read gamecontrollerdb.txt");
SDL_GameControllerEventState (SDL_ENABLE);
SDL_JoystickEventState (SDL_ENABLE);
SDL_SetGamepadEventsEnabled (true);
SDL_SetJoystickEventsEnabled (true);
for (int i = 0; i < SDL_NumJoysticks (); i++) {
if (!SDL_IsGameController (i)) continue;
int numJoysticks = 0;
auto* joyStickIds = SDL_GetJoysticks(&numJoysticks);
if (joyStickIds == nullptr) {
LogMessage (LogLevel::ERROR, "Error getting joystick ids");
exit(1);
}
for (auto id:joyStickIds) {
if (!SDL_IsGamepad (id)) continue;
SDL_Gamepad *controller = SDL_OpenGamepad (id);
SDL_GameController *controller = SDL_GameControllerOpen (i);
if (!controller) {
LogMessage (LogLevel::WARN, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (i) + ": " + SDL_GetError ());
LogMessage (LogLevel::WARN, std::string ("Could not open gamecontroller ") + SDL_GetGamepadNameForID (id) + ": " + SDL_GetError ());
continue;
}
controllers[i] = controller;
}
window = SDL_CreateWindowFrom (windowHandle);
if (window == nullptr) LogMessage (LogLevel::ERROR, std::string ("SDL_CreateWindowFrom (windowHandle): ") + SDL_GetError ());
LogMessage (LogLevel::DEBUG, "Init Controller connected!");
controllers[id] = controller;
}
SDL_free (joyStickIds);
SDL_PropertiesID props = SDL_CreateProperties();
if(props == 0) {
LogMessage (LogLevel::ERROR, "Unable to create SDL_Properties");
exit(1);
}
SDL_SetPointerProperty (props, SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER, windowHandle);
window = SDL_CreateWindowWithProperties (props);
if (window == NULL) LogMessage (LogLevel::ERROR, std::string ("SDL_CreateWindowFrom (windowHandle): ") + SDL_GetError ());
atexit (DisposePoll);
return hasRumble;
@@ -149,71 +166,71 @@ UpdatePoll (const HWND windowHandle) {
ScreenToClient (windowHandle, &currentMouseState.Position);
SDL_Event event;
SDL_GameController *controller;
SDL_Gamepad *controller;
while (SDL_PollEvent (&event) != 0) {
switch (event.type) {
case SDL_CONTROLLERDEVICEADDED:
if (!SDL_IsGameController (event.cdevice.which)) break;
case SDL_EVENT_GAMEPAD_ADDED:
if (!SDL_IsGamepad (event.cdevice.which)) break;
controller = SDL_GameControllerOpen (event.cdevice.which);
controller = SDL_OpenGamepad (event.cdevice.which);
if (!controller) {
LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which)
LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GetGamepadNameForID (event.cdevice.which)
+ ": " + SDL_GetError ());
continue;
}
controllers[event.cdevice.which] = controller;
break;
case SDL_CONTROLLERDEVICEREMOVED:
if (!SDL_IsGameController (event.cdevice.which)) break;
SDL_GameControllerClose (controllers[event.cdevice.which]);
case SDL_EVENT_GAMEPAD_REMOVED:
if (!SDL_IsGamepad (event.cdevice.which)) break;
SDL_CloseGamepad (controllers[event.cdevice.which]);
break;
case SDL_MOUSEWHEEL:
case SDL_EVENT_MOUSE_WHEEL:
if (event.wheel.y > 0) currentMouseState.ScrolledUp = true;
else if (event.wheel.y < 0) currentMouseState.ScrolledDown = true;
break;
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERBUTTONDOWN: currentControllerButtonsState[event.cbutton.button] = event.cbutton.state; break;
case SDL_CONTROLLERAXISMOTION:
if (event.caxis.value > 1) {
switch (event.caxis.axis) {
case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = static_cast<float> (event.caxis.value) / 32767; break;
case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = static_cast<float> (event.caxis.value) / 32767; break;
case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = static_cast<float> (event.caxis.value) / 32767; break;
case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = static_cast<float> (event.caxis.value) / 32767; break;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = static_cast<float> (event.caxis.value) / 32767; break;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
currentControllerAxisState.RTriggerDown = static_cast<float> (event.caxis.value) / 32767;
case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_EVENT_GAMEPAD_BUTTON_DOWN: currentControllerButtonsState[event.gbutton.button] = event.gbutton.down; break;
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
if (event.gaxis.value > 1) {
switch (event.gaxis.axis) {
case SDL_GAMEPAD_AXIS_LEFTX: currentControllerAxisState.LeftRight = static_cast<float> (event.gaxis.value) / 32767; break;
case SDL_GAMEPAD_AXIS_LEFTY: currentControllerAxisState.LeftDown = static_cast<float> (event.gaxis.value) / 32767; break;
case SDL_GAMEPAD_AXIS_RIGHTX: currentControllerAxisState.RightRight = static_cast<float> (event.gaxis.value) / 32767; break;
case SDL_GAMEPAD_AXIS_RIGHTY: currentControllerAxisState.RightDown = static_cast<float> (event.gaxis.value) / 32767; break;
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: currentControllerAxisState.LTriggerDown = static_cast<float> (event.gaxis.value) / 32767; break;
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER:
currentControllerAxisState.RTriggerDown = static_cast<float> (event.gaxis.value) / 32767;
break;
default: break;
}
} else if (event.caxis.value < -1) {
switch (event.caxis.axis) {
case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftLeft = static_cast<float> (event.caxis.value) / -32768; break;
case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftUp = static_cast<float> (event.caxis.value) / -32768; break;
case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightLeft = static_cast<float> (event.caxis.value) / -32768; break;
case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightUp = static_cast<float> (event.caxis.value) / -32768; break;
} else if (event.gaxis.value < -1) {
switch (event.gaxis.axis) {
case SDL_GAMEPAD_AXIS_LEFTX: currentControllerAxisState.LeftLeft = static_cast<float> (event.gaxis.value) / -32768; break;
case SDL_GAMEPAD_AXIS_LEFTY: currentControllerAxisState.LeftUp = static_cast<float> (event.gaxis.value) / -32768; break;
case SDL_GAMEPAD_AXIS_RIGHTX: currentControllerAxisState.RightLeft = static_cast<float> (event.gaxis.value) / -32768; break;
case SDL_GAMEPAD_AXIS_RIGHTY: currentControllerAxisState.RightUp = static_cast<float> (event.gaxis.value) / -32768; break;
default: break;
}
} else {
switch (event.caxis.axis) {
case SDL_CONTROLLER_AXIS_LEFTX:
switch (event.gaxis.axis) {
case SDL_GAMEPAD_AXIS_LEFTX:
currentControllerAxisState.LeftRight = 0;
currentControllerAxisState.LeftLeft = 0;
break;
case SDL_CONTROLLER_AXIS_LEFTY:
case SDL_GAMEPAD_AXIS_LEFTY:
currentControllerAxisState.LeftDown = 0;
currentControllerAxisState.LeftUp = 0;
break;
case SDL_CONTROLLER_AXIS_RIGHTX:
case SDL_GAMEPAD_AXIS_RIGHTX:
currentControllerAxisState.RightRight = 0;
currentControllerAxisState.RightLeft = 0;
break;
case SDL_CONTROLLER_AXIS_RIGHTY:
case SDL_GAMEPAD_AXIS_RIGHTY:
currentControllerAxisState.RightDown = 0;
currentControllerAxisState.RightUp = 0;
break;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = 0; break;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = 0; break;
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: currentControllerAxisState.LTriggerDown = 0; break;
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: currentControllerAxisState.RTriggerDown = 0; break;
default: break;
}
}
@@ -272,7 +289,7 @@ GetInternalButtonState (const Keybindings &bindings) {
if (KeyboardIsTapped (bindings.keycodes[i])) buttons.Tapped = true;
}
for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) {
if (bindings.buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) continue;
if (bindings.buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) continue;
if (ControllerButtonIsReleased (bindings.buttons[i])) buttons.Released = true;
if (ControllerButtonIsDown (bindings.buttons[i])) buttons.Down = 1;
if (ControllerButtonIsTapped (bindings.buttons[i])) buttons.Tapped = true;
@@ -295,11 +312,12 @@ GetInternalButtonState (const Keybindings &bindings) {
}
void
SetRumble (const int left, const int right, const int length) {
SetRumble (int left, int right, int length) {
for (auto &controller : controllers) {
if (!controller || !SDL_GameControllerHasRumble (controller)) continue;
SDL_GameControllerRumble (controller, left, right, length);
const auto props = SDL_GetGamepadProperties(controller);
const bool hasRumble = SDL_GetBooleanProperty (props, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false);
if (!controller || !hasRumble) continue;
SDL_RumbleGamepad (controller, left, right, length);
}
}
@@ -389,32 +407,32 @@ GetMouseScrollIsTapped (const Scroll scroll) {
}
bool
ControllerButtonIsDown (const SDL_GameControllerButton button) {
ControllerButtonIsDown (const SDL_GamepadButton button) {
return currentControllerButtonsState[button];
}
bool
ControllerButtonIsUp (const SDL_GameControllerButton button) {
ControllerButtonIsUp (const SDL_GamepadButton button) {
return !ControllerButtonIsDown (button);
}
bool
ControllerButtonWasDown (const SDL_GameControllerButton button) {
ControllerButtonWasDown (const SDL_GamepadButton button) {
return lastControllerButtonsState[button];
}
bool
ControllerButtonWasUp (const SDL_GameControllerButton button) {
ControllerButtonWasUp (const SDL_GamepadButton button) {
return !ControllerButtonWasDown (button);
}
bool
ControllerButtonIsTapped (const SDL_GameControllerButton button) {
ControllerButtonIsTapped (const SDL_GamepadButton button) {
return ControllerButtonIsDown (button) && ControllerButtonWasUp (button);
}
bool
ControllerButtonIsReleased (const SDL_GameControllerButton button) {
ControllerButtonIsReleased (const SDL_GamepadButton button) {
return ControllerButtonIsUp (button) && ControllerButtonWasDown (button);
}
+14 -14
View File
@@ -1,5 +1,5 @@
#pragma once
#include <SDL.h>
#include <SDL3/SDL.h>
#include "helpers.h"
#include "bnusio.h"
@@ -41,7 +41,7 @@ enum Scroll { MOUSE_SCROLL_INVALID, MOUSE_SCROLL_UP, MOUSE_SCROLL_DOWN };
struct Keybindings {
u8 keycodes[255];
SDL_GameControllerButton buttons[255];
SDL_GamepadButton buttons[255];
SDLAxis axis[255];
Scroll scroll[2];
};
@@ -52,7 +52,7 @@ struct ConfigValue {
EnumType type;
union {
u8 keycode;
SDL_GameControllerButton button;
SDL_GamepadButton button;
SDLAxis axis;
Scroll scroll;
};
@@ -72,16 +72,16 @@ void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *ke
InternalButtonState GetInternalButtonState (const Keybindings &bindings);
void SetRumble (int left, int right, int length);
bool KeyboardIsDown (const uint8_t keycode);
bool KeyboardIsTapped (const uint8_t keycode);
bool KeyboardIsDown (uint8_t keycode);
bool KeyboardIsTapped (uint8_t keycode);
bool GetMouseScrollUp ();
bool GetMouseScrollDown ();
bool GetMouseScrollIsDown (const Scroll scroll);
bool GetMouseScrollIsTapped (const Scroll scroll);
bool ControllerButtonIsDown (const SDL_GameControllerButton button);
bool ControllerButtonIsTapped (const SDL_GameControllerButton button);
float ControllerAxisIsDown (const SDLAxis axis);
bool ControllerAxisIsTapped (const SDLAxis axis);
bool GetMouseScrollIsDown (Scroll scroll);
bool GetMouseScrollIsTapped (Scroll scroll);
bool ControllerButtonIsDown (SDL_GamepadButton button);
bool ControllerButtonIsTapped (SDL_GamepadButton button);
float ControllerAxisIsDown (SDLAxis axis);
bool ControllerAxisIsTapped (SDLAxis axis);
bool IsButtonTapped (const Keybindings &bindings);
float IsButtonDown (const Keybindings &bindings);
@@ -99,9 +99,9 @@ void SetMousePosition (const POINT newPosition);
bool GetWasMouseScrollUp ();
bool GetWasMouseScrollDown ();
bool GetMouseScrollIsReleased (const Scroll scroll);
bool ControllerButtonWasDown (const SDL_GameControllerButton button);
bool ControllerButtonWasUp (const SDL_GameControllerButton button);
bool ControllerButtonIsReleased (const SDL_GameControllerButton button);
bool ControllerButtonWasDown (const SDL_GamepadButton button);
bool ControllerButtonWasUp (const SDL_GamepadButton button);
bool ControllerButtonIsReleased (const SDL_GamepadButton button);
bool ControllerAxisIsUp (const SDLAxis axis);
float ControllerAxisWasDown (const SDLAxis axis);
bool ControllerAxisWasUp (const SDLAxis axis);
+100 -76
View File
@@ -2,22 +2,21 @@
#ifdef ASYNC_IO
#include "polldef.h"
#define SDL_MAIN_NOIMPL
#include <SDL3/SDL_main.h>
extern bool jpLayout;
extern int exited;
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
bool wndForeground = false;
bool currentKeyboardState[0xFF] = { false };
uint8_t keyboardCount[0xFF] = { 0 };
uint8_t keyboardDiff[0xFF] = { 0 };
bool keyboardClean = false;
bool currentControllerButtonsState[SDL_CONTROLLER_BUTTON_MAX] = { false };
uint8_t controllerCount[SDL_CONTROLLER_BUTTON_MAX] = { 0 };
uint8_t controllerDiff[SDL_CONTROLLER_BUTTON_MAX] = { 0 };
bool currentControllerButtonsState[SDL_GAMEPAD_BUTTON_COUNT] = { false };
uint8_t controllerCount[SDL_GAMEPAD_BUTTON_COUNT] = { 0 };
uint8_t controllerDiff[SDL_GAMEPAD_BUTTON_COUNT] = { 0 };
char currentMouseWheelDirection = 0;
uint8_t mouseWheelCount[2] = { 0 };
uint8_t mouseWheelDiff[2] = { 0 };
@@ -27,7 +26,8 @@ int maxCount = 1;
SDLAxisState currentControllerAxisState;
SDL_Window *window;
SDL_GameController *controllers[255];
SDL_Gamepad *controllers[255];
bool flipped[255];
std::thread updatePollThread;
@@ -48,7 +48,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin
memset (key_bind, 0, sizeof (*key_bind));
for (size_t i = 0; i < std::size (key_bind->buttons); i++)
key_bind->buttons[i] = SDL_CONTROLLER_BUTTON_INVALID;
key_bind->buttons[i] = SDL_GAMEPAD_BUTTON_INVALID;
for (int idx = 0;; idx++) {
const auto [ok, u] = toml_string_at (array, idx);
@@ -69,7 +69,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin
case button: {
*usePoll = true;
for (int i = 0; i < std::size (key_bind->buttons); i++) {
if (key_bind->buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) {
if (key_bind->buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) {
key_bind->buttons[i] = value.button;
break;
}
@@ -108,9 +108,9 @@ LRESULT CALLBACK InputProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
switch (wParam) {
case WM_KEYDOWN: if (wndForeground) {
KBDLLHOOKSTRUCT* pKeyboard = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
auto* pKeyboard = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
DWORD keyCode = pKeyboard->vkCode;
if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] = MIN (keyboardCount[keyCode] + 1, maxCount);
if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] = std::min (keyboardCount[keyCode] + 1, maxCount);
currentKeyboardState[keyCode] = true;
} break;
// keyup will accepted even if you're not focus in this window
@@ -123,13 +123,14 @@ LRESULT CALLBACK InputProc(int nCode, WPARAM wParam, LPARAM lParam) {
MSLLHOOKSTRUCT *pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
int wheelDelta = GET_WHEEL_DELTA_WPARAM(pMouseStruct->mouseData);
if (wheelDelta > 0) {
mouseWheelCount[0] = MIN (mouseWheelCount[0] + wheelDelta, maxCount);
mouseWheelCount[0] = std::min (mouseWheelCount[0] + wheelDelta, maxCount);
currentMouseState.ScrolledUp = true;
} else if (wheelDelta < 0) {
mouseWheelCount[1] = MIN (mouseWheelCount[1] - wheelDelta, maxCount);
mouseWheelCount[1] = std::min (mouseWheelCount[1] - wheelDelta, maxCount);
currentMouseState.ScrolledDown = true;
}
} break;
default: break;
}
}
return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
@@ -150,14 +151,12 @@ DisposeKeyboard () {
if (mouseHook) UnhookWindowsHookEx(mouseHook);
}
// void
// UpdateLoop () {
// LogMessage (LogLevel::DEBUG, "Enter Controller UpdateLoop");
// while (!exited) {
// }
// }
void
CheckFlipped (uint32_t which, SDL_Gamepad *gamepad) {
if (SDL_GetGamepadButtonLabel(gamepad, SDL_GAMEPAD_BUTTON_SOUTH) == SDL_GAMEPAD_BUTTON_LABEL_B) {
flipped[which] = true;
} else flipped[which] = false;
}
bool
InitializePoll (HWND windowHandle) {
@@ -171,44 +170,53 @@ InitializePoll (HWND windowHandle) {
SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5, "1");
SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO) != 0) {
if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO) == 0) {
if (!SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO)) {
if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO)) {
hasRumble = false;
} else {
LogMessage (LogLevel::ERROR,
std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ")
+ SDL_GetError ());
LogMessage (LogLevel::ERROR, std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ") + SDL_GetError ());
return false;
}
}
auto configPath = std::filesystem::current_path () / "gamecontrollerdb.txt";
if (SDL_GameControllerAddMappingsFromFile (configPath.string ().c_str ()) == -1)
if (SDL_AddGamepadMappingsFromFile (configPath.string ().c_str ()) == -1)
LogMessage (LogLevel::ERROR, "Cannot read gamecontrollerdb.txt");
SDL_GameControllerEventState (SDL_ENABLE);
SDL_JoystickEventState (SDL_ENABLE);
SDL_SetGamepadEventsEnabled (true);
SDL_SetJoystickEventsEnabled (true);
for (int i = 0; i < SDL_NumJoysticks (); i++) {
if (!SDL_IsGameController (i)) continue;
int numJoysticks = 0;
auto* joyStickIds = SDL_GetJoysticks(&numJoysticks);
if (joyStickIds == nullptr) {
LogMessage (LogLevel::ERROR, "Error getting joystick ids");
exit(1);
}
for (int i = 0; i < numJoysticks; i++) {
auto id = joyStickIds[i];
if (!SDL_IsGamepad (id)) continue;
SDL_Gamepad *controller = SDL_OpenGamepad (id);
SDL_GameController *controller = SDL_GameControllerOpen (i);
if (!controller) {
LogMessage (LogLevel::WARN, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (i) + ": " + SDL_GetError ());
LogMessage (LogLevel::WARN, std::string ("Could not open gamecontroller ") + SDL_GetGamepadNameForID (id) + ": " + SDL_GetError ());
continue;
}
LogMessage (LogLevel::DEBUG, "Init Controller connected!");
controllers[i] = controller;
CheckFlipped (id, controller);
controllers[id] = controller;
}
SDL_free (joyStickIds);
window = SDL_CreateWindowFrom (windowHandle);
SDL_PropertiesID props = SDL_CreateProperties();
if(props == 0) {
LogMessage (LogLevel::ERROR, "Unable to create SDL_Properties");
exit(1);
}
SDL_SetPointerProperty (props, SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER, windowHandle);
window = SDL_CreateWindowWithProperties (props);
if (window == NULL) LogMessage (LogLevel::ERROR, std::string ("SDL_CreateWindowFrom (windowHandle): ") + SDL_GetError ());
atexit (DisposePoll);
// updatePollThread = std::thread (UpdateLoop);
// updatePollThread.detach ();
return hasRumble;
}
@@ -222,6 +230,18 @@ CheckForegroundWindow (HWND processWindow) {
return wndForeground;
}
uint8_t
CorrectButton (uint32_t which, uint8_t button) {
if (!flipped[which]) return button;
switch (button) {
case SDL_GAMEPAD_BUTTON_SOUTH: return SDL_GAMEPAD_BUTTON_EAST;
case SDL_GAMEPAD_BUTTON_EAST: return SDL_GAMEPAD_BUTTON_SOUTH;
case SDL_GAMEPAD_BUTTON_WEST: return SDL_GAMEPAD_BUTTON_NORTH;
case SDL_GAMEPAD_BUTTON_NORTH: return SDL_GAMEPAD_BUTTON_WEST;
default: return button;
}
}
void
UpdatePoll (HWND windowHandle, bool useController) {
if (!CheckForegroundWindow (windowHandle)) return;
@@ -240,50 +260,52 @@ UpdatePoll (HWND windowHandle, bool useController) {
// GetCursorPos (&currentMouseState.Position);
// ScreenToClient (windowHandle, &currentMouseState.Position);
if (useController) {
for (int i=0; i<SDL_CONTROLLER_BUTTON_MAX; i++) controllerCount[i] -= (bool)controllerDiff[i];
memset (controllerDiff, 0, SDL_CONTROLLER_BUTTON_MAX);
for (int i=0; i<SDL_GAMEPAD_BUTTON_COUNT; i++) controllerCount[i] -= (bool)controllerDiff[i];
memset (controllerDiff, 0, SDL_GAMEPAD_BUTTON_COUNT);
SDL_Event event;
SDL_GameController *controller;
SDL_Gamepad *controller;
while (SDL_PollEvent (&event) != 0) {
// LogMessage (LogLevel::DEBUG, "Receive SDL Event! type={}", (u64)event.type);
switch (event.type) {
case SDL_CONTROLLERDEVICEADDED:
if (!SDL_IsGameController (event.cdevice.which)) break;
controller = SDL_GameControllerOpen (event.cdevice.which);
case SDL_EVENT_GAMEPAD_ADDED:
if (!SDL_IsGamepad (event.gdevice.which)) break;
controller = SDL_OpenGamepad (event.gdevice.which);
if (!controller) {
LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which)
+ ": " + SDL_GetError ());
LogMessage (LogLevel::ERROR, "Could not open gamecontroller {}: {}", SDL_GetGamepadNameForID (event.gdevice.which), SDL_GetError ());
continue;
}
LogMessage (LogLevel::DEBUG, "Controller connected!");
controllers[event.cdevice.which] = controller;
CheckFlipped (event.gdevice.which, controller);
controllers[event.gdevice.which] = controller;
break;
case SDL_CONTROLLERDEVICEREMOVED:
case SDL_EVENT_GAMEPAD_REMOVED:
LogMessage (LogLevel::DEBUG, "Controller removed!");
if (!SDL_IsGameController (event.cdevice.which)) break;
SDL_GameControllerClose (controllers[event.cdevice.which]);
if (!SDL_IsGamepad (event.gdevice.which)) break;
SDL_CloseGamepad (controllers[event.gdevice.which]);
break;
case SDL_CONTROLLERBUTTONUP:
// keyup will accepted even if you're not focus in this window
currentControllerButtonsState[event.cbutton.button] = false; break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP: {
uint8_t button = CorrectButton (event.gbutton.which, event.gbutton.button);
currentControllerButtonsState[button] = false;
} break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
if (wndForeground) {
if (!currentControllerButtonsState[event.cbutton.button]) {
controllerCount[event.cbutton.button] = MIN (controllerCount[event.cbutton.button] + 1, maxCount);
uint8_t button = CorrectButton (event.gbutton.which, event.gbutton.button);
LogMessage (LogLevel::DEBUG, "Controller {}: button {} pressed, remapped to {}", event.gbutton.which, event.gbutton.button, button);
if (!currentControllerButtonsState[button]) {
controllerCount[button] = std::min (controllerCount[button] + 1, maxCount);
}
currentControllerButtonsState[event.cbutton.button] = true;
} else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!");
currentControllerButtonsState[button] = true;
} else LogMessage (LogLevel::DEBUG, "Controller button pressed but window not focused!");
break;
case SDL_CONTROLLERAXISMOTION:
float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f);
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
float sensorValue = event.gaxis.value == 0 ? 0 : event.gaxis.value / (event.gaxis.value > 0 ? 32767.0f : -32768.0f);
if (wndForeground || sensorValue == 0) {
switch (event.caxis.axis) {
case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break;
case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break;
case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break;
case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break;
switch (event.gaxis.axis) {
case SDL_GAMEPAD_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break;
case SDL_GAMEPAD_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break;
case SDL_GAMEPAD_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break;
case SDL_GAMEPAD_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break;
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: currentControllerAxisState.LTriggerDown = sensorValue; break;
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: currentControllerAxisState.RTriggerDown = sensorValue; break;
}
}
break;
@@ -333,8 +355,10 @@ StringToConfigEnum (const char *value) {
void
SetRumble (int left, int right, int length) {
for (auto &controller : controllers) {
if (!controller || !SDL_GameControllerHasRumble (controller)) continue;
SDL_GameControllerRumble (controller, left, right, length);
const auto props = SDL_GetGamepadProperties(controller);
const bool hasRumble = SDL_GetBooleanProperty (props, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false);
if (!controller || !hasRumble) continue;
SDL_RumbleGamepad (controller, left, right, length);
}
}
@@ -388,13 +412,13 @@ GetMouseScrollIsTapped (const Scroll scroll) {
}
bool
ControllerButtonIsDown (const SDL_GameControllerButton button) {
ControllerButtonIsDown (const SDL_GamepadButton button) {
return currentControllerButtonsState[button];
}
int maxButtonCount = 1;
bool
ControllerButtonIsTapped (const SDL_GameControllerButton button) {
ControllerButtonIsTapped (const SDL_GamepadButton button) {
if (controllerCount[button] > 0) {
// if (maxButtonCount < controllerCount[button]) {
// maxButtonCount = controllerCount[button];
@@ -435,7 +459,7 @@ IsButtonTapped (const Keybindings &bindings) {
if (KeyboardIsTapped (bindings.keycodes[i])) return true;
}
for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) {
if (bindings.buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) continue;
if (bindings.buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) continue;
if (ControllerButtonIsTapped (bindings.buttons[i])) return true;
}
for (size_t i = 0; i < std::size (ConfigControllerAXIS); i++) {
@@ -457,7 +481,7 @@ IsButtonDown (const Keybindings &bindings) {
if (KeyboardIsDown (bindings.keycodes[i])) return 1.0f;
}
for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) {
if (bindings.buttons[i] == SDL_CONTROLLER_BUTTON_INVALID) continue;
if (bindings.buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) continue;
if (ControllerButtonIsDown (bindings.buttons[i])) return 1.0f;
}
for (size_t i = 0; i < std::size (ConfigControllerAXIS); i++) {
+22 -22
View File
@@ -254,29 +254,29 @@ KeyCodePair ConfigKeyboardButtons_JP[] = {
struct {
const char *string;
SDL_GameControllerButton button;
SDL_GamepadButton button;
} ConfigControllerButtons[] = {
{"SDL_A", SDL_CONTROLLER_BUTTON_A},
{"SDL_B", SDL_CONTROLLER_BUTTON_B},
{"SDL_X", SDL_CONTROLLER_BUTTON_X},
{"SDL_Y", SDL_CONTROLLER_BUTTON_Y},
{"SDL_BACK", SDL_CONTROLLER_BUTTON_BACK},
{"SDL_GUIDE", SDL_CONTROLLER_BUTTON_GUIDE},
{"SDL_START", SDL_CONTROLLER_BUTTON_START},
{"SDL_LSTICK_PRESS", SDL_CONTROLLER_BUTTON_LEFTSTICK},
{"SDL_RSTICK_PRESS", SDL_CONTROLLER_BUTTON_RIGHTSTICK},
{"SDL_LSHOULDER", SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
{"SDL_RSHOULDER", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{"SDL_DPAD_UP", SDL_CONTROLLER_BUTTON_DPAD_UP},
{"SDL_DPAD_DOWN", SDL_CONTROLLER_BUTTON_DPAD_DOWN},
{"SDL_DPAD_LEFT", SDL_CONTROLLER_BUTTON_DPAD_LEFT},
{"SDL_DPAD_RIGHT", SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
{"SDL_MISC", SDL_CONTROLLER_BUTTON_MISC1},
{"SDL_PADDLE1", SDL_CONTROLLER_BUTTON_PADDLE1},
{"SDL_PADDLE2", SDL_CONTROLLER_BUTTON_PADDLE2},
{"SDL_PADDLE3", SDL_CONTROLLER_BUTTON_PADDLE3},
{"SDL_PADDLE4", SDL_CONTROLLER_BUTTON_PADDLE4},
{"SDL_TOUCHPAD", SDL_CONTROLLER_BUTTON_TOUCHPAD},
{"SDL_A", SDL_GAMEPAD_BUTTON_SOUTH},
{"SDL_B", SDL_GAMEPAD_BUTTON_EAST},
{"SDL_X", SDL_GAMEPAD_BUTTON_WEST},
{"SDL_Y", SDL_GAMEPAD_BUTTON_NORTH},
{"SDL_BACK", SDL_GAMEPAD_BUTTON_BACK},
{"SDL_GUIDE", SDL_GAMEPAD_BUTTON_GUIDE},
{"SDL_START", SDL_GAMEPAD_BUTTON_START},
{"SDL_LSTICK_PRESS", SDL_GAMEPAD_BUTTON_LEFT_STICK},
{"SDL_RSTICK_PRESS", SDL_GAMEPAD_BUTTON_RIGHT_STICK},
{"SDL_LSHOULDER", SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
{"SDL_RSHOULDER", SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
{"SDL_DPAD_UP", SDL_GAMEPAD_BUTTON_DPAD_UP},
{"SDL_DPAD_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
{"SDL_DPAD_LEFT", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
{"SDL_DPAD_RIGHT", SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
{"SDL_MISC", SDL_GAMEPAD_BUTTON_MISC1},
{"SDL_PADDLE1", SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1},
{"SDL_PADDLE2", SDL_GAMEPAD_BUTTON_LEFT_PADDLE1},
{"SDL_PADDLE3", SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2},
{"SDL_PADDLE4", SDL_GAMEPAD_BUTTON_LEFT_PADDLE2},
{"SDL_TOUCHPAD", SDL_GAMEPAD_BUTTON_TOUCHPAD},
};
struct {