1
0
mirror of synced 2024-11-12 00:40:47 +01:00

Remember keybinds

This commit is contained in:
Bottersnike 2023-02-14 07:46:24 +00:00
parent dd4f7f97a5
commit be903943bb
10 changed files with 164 additions and 50 deletions

View File

@ -130,13 +130,13 @@ BOOL smbus_PCA9535_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
static bool lastTest = false; static bool lastTest = false;
static bool lastSystem = false; static bool lastSystem = false;
if (keySystemTest && GetAsyncKeyState(keySystemTest) < 0) { if (MiceConfig.keys.test && GetAsyncKeyState(MiceConfig.keys.test) < 0) {
// if (!lastSystem) // if (!lastSystem)
dip &= ~0x04; dip &= ~0x04;
// lastSystem = true; // lastSystem = true;
} else } else
lastSystem = false; lastSystem = false;
if (keySystemService && GetAsyncKeyState(keySystemService) < 0) { if (MiceConfig.keys.service && GetAsyncKeyState(MiceConfig.keys.service) < 0) {
// if (!lastTest) // if (!lastTest)
dip &= ~0x08; dip &= ~0x08;
// lastTest = true; // lastTest = true;

View File

@ -1,11 +1,10 @@
#include <Windows.h> #include <Windows.h>
#include "../common.h" #include "../common.h"
#include "../key_config.h"
#include "jvs.h" #include "jvs.h"
#include "mx.h" #include "mx.h"
#include "../key_config.h"
BOOL JVS_SENSE = false; BOOL JVS_SENSE = false;
BOOL coin_solenoid = false; BOOL coin_solenoid = false;
BOOL test_btn = false; BOOL test_btn = false;
@ -81,9 +80,9 @@ void update_jvs_buttons(jvs_board_t* board) {
if (scancode == 0) continue; if (scancode == 0) continue;
if (invert) if (invert)
buttons |= (GetAsyncKeyState(scancode) >= 0);// << i; buttons |= (GetAsyncKeyState(scancode) >= 0); // << i;
else else
buttons |= (GetAsyncKeyState(scancode) < 0);// << i; buttons |= (GetAsyncKeyState(scancode) < 0); // << i;
} }
// 0x80 == push 3 // 0x80 == push 3
@ -214,10 +213,8 @@ unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCo
int coin1 = jvsKeybindings[board->num].buttons[0]; int coin1 = jvsKeybindings[board->num].buttons[0];
int coin2 = jvsKeybindings[board->num].buttons[1]; int coin2 = jvsKeybindings[board->num].buttons[1];
if (coin1 && GetAsyncKeyState(coin1) & 1) if (coin1 && GetAsyncKeyState(coin1) & 1) board->coin_counts[0]++;
board->coin_counts[0]++; if (coin2 && GetAsyncKeyState(coin2) & 1) board->coin_counts[1]++;
if (coin2 && GetAsyncKeyState(coin2) & 1)
board->coin_counts[1]++;
for (unsigned char slot = 0; slot < coin_count; slot++) { for (unsigned char slot = 0; slot < coin_count; slot++) {
jvs_write(board->coin_counts[slot] >> 8); jvs_write(board->coin_counts[slot] >> 8);
@ -333,19 +330,20 @@ void mxjvs_handle(unsigned char* paddedIn, short inCount, unsigned char* outData
unsigned char destination = inData[1]; unsigned char destination = inData[1];
// Not broadcast, not master-bound, and within bounds // Not broadcast, not master-bound, and within bounds
if (destination != 0xff && (destination == 0 || destination > numJvsBoards)) return; if (destination != 0xff && (destination == 0 || destination > MiceConfig.keys.board_count))
return;
unsigned char* response = malloc(maxOut); unsigned char* response = malloc(maxOut);
unsigned char packetSize; unsigned char packetSize;
unsigned char status; unsigned char status;
if (destination == 0xff) { if (destination == 0xff) {
for (int i = 0; i < numJvsBoards; i++) { for (int i = 0; i < MiceConfig.keys.board_count; i++) {
jvs_board_t *board = &jvs_boards[i]; jvs_board_t* board = &jvs_boards[i];
status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize); status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize);
if (packetSize != 0) break; if (packetSize != 0) break;
} }
} else { } else {
jvs_board_t* board = &jvs_boards[numJvsBoards - destination]; jvs_board_t* board = &jvs_boards[MiceConfig.keys.board_count - destination];
status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize); status = board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize);
} }
free(inData); free(inData);

View File

@ -690,11 +690,14 @@ void AddSettingButton(int board, int id) {
} }
if (jvsKeybindings[board].buttons[id * 2]) { if (jvsKeybindings[board].buttons[id * 2]) {
igSameLine(0, -1); igSameLine(0, -1);
if (igButton(clear, vec0)) jvsKeybindings[board].buttons[id * 2] = 0; if (igButton(clear, vec0)) {
jvsKeybindings[board].buttons[id * 2] = 0;
save_current_config();
}
} }
igNextColumn(); igNextColumn();
igBeginDisabled(!jvsKeybindings[board].buttons[id * 2]); igBeginDisabled(!jvsKeybindings[board].buttons[id * 2]);
igCheckbox(invertName, &jvsKeybindings[board].invert[id * 2]); if (igCheckbox(invertName, &jvsKeybindings[board].invert[id * 2])) save_current_config();
igEndDisabled(); igEndDisabled();
igNextColumn(); igNextColumn();
@ -716,11 +719,12 @@ void AddSettingButton(int board, int id) {
igSameLine(0, -1); igSameLine(0, -1);
if (igButton(clear2, vec0)) { if (igButton(clear2, vec0)) {
jvsKeybindings[board].buttons[id * 2 + 1] = 0; jvsKeybindings[board].buttons[id * 2 + 1] = 0;
save_current_config();
} }
} }
igNextColumn(); igNextColumn();
igBeginDisabled(!jvsKeybindings[board].buttons[id * 2 + 1]); igBeginDisabled(!jvsKeybindings[board].buttons[id * 2 + 1]);
igCheckbox(invertName2, &jvsKeybindings[board].invert[id * 2 + 1]); if (igCheckbox(invertName2, &jvsKeybindings[board].invert[id * 2 + 1])) save_current_config();
igEndDisabled(); igEndDisabled();
igNextColumn(); igNextColumn();
@ -729,6 +733,7 @@ void AddSettingButton(int board, int id) {
if (igKeyBindPopup(name, &boundKey)) { if (igKeyBindPopup(name, &boundKey)) {
if (boundKey != -1) { if (boundKey != -1) {
jvsKeybindings[board].buttons[id * 2 + (currentlyBinding - 1)] = boundKey; jvsKeybindings[board].buttons[id * 2 + (currentlyBinding - 1)] = boundKey;
save_current_config();
} }
currentlyBinding = 0; currentlyBinding = 0;
} }
@ -777,11 +782,17 @@ void tab_jvs_board(int num) {
if (igButton("Bind##JvsTest", vec0)) igOpenPopup_Str("BindJvsTest", ImGuiPopupFlags_None); if (igButton("Bind##JvsTest", vec0)) igOpenPopup_Str("BindJvsTest", ImGuiPopupFlags_None);
if (jvsKeybindings[num].test) { if (jvsKeybindings[num].test) {
igSameLine(0, -1); igSameLine(0, -1);
if (igButton("Clear##ClearJvsTest", vec0)) jvsKeybindings[num].test = 0; if (igButton("Clear##ClearJvsTest", vec0)) {
jvsKeybindings[num].test = 0;
save_current_config();
}
} }
int boundKey; int boundKey;
if (igKeyBindPopup("BindJvsTest", &boundKey)) if (igKeyBindPopup("BindJvsTest", &boundKey))
if (boundKey != -1) jvsKeybindings[num].test = boundKey; if (boundKey != -1) {
jvsKeybindings[num].test = boundKey;
save_current_config();
}
igEndColumns(); igEndColumns();
@ -803,51 +814,66 @@ void tab_system_buttons() {
igTextUnformatted("System Test", NULL); igTextUnformatted("System Test", NULL);
igNextColumn(); igNextColumn();
if (keySystemTest == 0) { if (MiceConfig.keys.test == 0) {
igTextColored(DISABLED_COL, "None"); igTextColored(DISABLED_COL, "None");
} else { } else {
GetKeyNameTextA(MapVirtualKey(keySystemTest, MAPVK_VK_TO_VSC) << 16, keyName, GetKeyNameTextA(MapVirtualKey(MiceConfig.keys.test, MAPVK_VK_TO_VSC) << 16, keyName,
_countof(keyName)); _countof(keyName));
igTextUnformatted(keyName, NULL); igTextUnformatted(keyName, NULL);
} }
igNextColumn(); igNextColumn();
if (igButton("Bind##BindTest", vec0)) igOpenPopup_Str("BindSysTest", ImGuiPopupFlags_None); if (igButton("Bind##BindTest", vec0)) igOpenPopup_Str("BindSysTest", ImGuiPopupFlags_None);
if (keySystemTest) { if (MiceConfig.keys.test) {
igSameLine(0, -1); igSameLine(0, -1);
if (igButton("Clear##ClearTest", vec0)) keySystemTest = 0; if (igButton("Clear##ClearTest", vec0)) {
MiceConfig.keys.test = 0;
save_current_config();
}
} }
igNextColumn(); igNextColumn();
if (igKeyBindPopup("BindSysTest", &boundKey)) if (igKeyBindPopup("BindSysTest", &boundKey))
if (boundKey != -1) keySystemTest = boundKey; if (boundKey != -1) {
MiceConfig.keys.test = boundKey;
save_current_config();
}
igTextUnformatted("System Service", NULL); igTextUnformatted("System Service", NULL);
igNextColumn(); igNextColumn();
if (keySystemService == 0) { if (MiceConfig.keys.service == 0) {
igTextColored(DISABLED_COL, "None"); igTextColored(DISABLED_COL, "None");
} else { } else {
GetKeyNameTextA(MapVirtualKey(keySystemService, MAPVK_VK_TO_VSC) << 16, keyName, GetKeyNameTextA(MapVirtualKey(MiceConfig.keys.service, MAPVK_VK_TO_VSC) << 16, keyName,
_countof(keyName)); _countof(keyName));
igTextUnformatted(keyName, NULL); igTextUnformatted(keyName, NULL);
} }
igNextColumn(); igNextColumn();
if (igButton("Bind##BindService", vec0)) if (igButton("Bind##BindService", vec0))
igOpenPopup_Str("BindSysService", ImGuiPopupFlags_None); igOpenPopup_Str("BindSysService", ImGuiPopupFlags_None);
if (keySystemService) { if (MiceConfig.keys.service) {
igSameLine(0, -1); igSameLine(0, -1);
if (igButton("Clear##ClearService", vec0)) keySystemService = 0; if (igButton("Clear##ClearService", vec0)) {
MiceConfig.keys.service = 0;
save_current_config();
}
} }
igNextColumn(); igNextColumn();
if (igKeyBindPopup("BindSysService", &boundKey)) if (igKeyBindPopup("BindSysService", &boundKey))
if (boundKey != -1) keySystemService = boundKey; if (boundKey != -1) {
MiceConfig.keys.service = boundKey;
save_current_config();
}
} }
void tab_main_keybinds() { void tab_main_keybinds() {
igInputInt("Number of JVS boards", &numJvsBoards, 1, 1, ImGuiInputTextFlags_None); if (igInputInt("Number of JVS boards", &MiceConfig.keys.board_count, 1, 1,
if (numJvsBoards < 0) numJvsBoards = 0; ImGuiInputTextFlags_None)) {
if (numJvsBoards > JVS_IO_MAX) numJvsBoards = JVS_IO_MAX; if (MiceConfig.keys.board_count < 0) MiceConfig.keys.board_count = 0;
if (MiceConfig.keys.board_count > JVS_IO_MAX) MiceConfig.keys.board_count = JVS_IO_MAX;
save_current_config();
}
if (igBeginTabBar("JVSBoards", 0)) { if (igBeginTabBar("JVSBoards", 0)) {
for (int i = 0; i < numJvsBoards; i++) { for (int i = 0; i < MiceConfig.keys.board_count; i++) {
char name[32]; char name[32];
snprintf(name, _countof(name), "Board %d", i + 1); snprintf(name, _countof(name), "Board %d", i + 1);
if (igBeginTabItem(name, NULL, 0)) { if (igBeginTabItem(name, NULL, 0)) {

View File

@ -320,12 +320,12 @@ int WINAPI FakeGetSystemMetrics(int nIndex) {
return TrueGetSystemMetrics(nIndex); return TrueGetSystemMetrics(nIndex);
} }
void __cdecl Fake_glutFullScreen(void) { void __stdcall Fake_glutFullScreen(void) {
hookType = UI_HOOK_GLUT; hookType = UI_HOOK_GLUT;
if (!MiceConfig.window.windowed) True_glutFullScreen(); if (!MiceConfig.window.windowed) True_glutFullScreen();
} }
void __cdecl Fake_glutSwapBuffers(void) { void __stdcall Fake_glutSwapBuffers(void) {
hookType = UI_HOOK_GLUT; hookType = UI_HOOK_GLUT;
end_scene_hook_t* head = end_scene_hook_list; end_scene_hook_t* head = end_scene_hook_list;
while (head != NULL) { while (head != NULL) {
@ -342,11 +342,29 @@ LONG WINAPI FakeChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, DEVMODEW* lpDev
return TrueChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam); return TrueChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
} }
void __cdecl Fake_glutInitDisplayMode(unsigned int mode) { void __stdcall Fake_glutInitDisplayMode(unsigned int mode) {
hookType = UI_HOOK_GLUT; hookType = UI_HOOK_GLUT;
True_glutInitDisplayMode(mode); True_glutInitDisplayMode(mode);
} }
void __stdcall Fake_glutPositionWindow(int x, int y) {
RECT winRect;
GetWindowRect(window, &winRect);
DWORD dwStyle = GetWindowLongW(window, GWL_STYLE);
SetupWindowPosition(&winRect, dwStyle);
// True_glutPositionWindow(winRect.left, winRect.top);
// True_glutPositionWindow(x, y);
}
void __stdcall Fake_glutReshapeWindow(int width, int height) {
RECT winRect;
GetWindowRect(window, &winRect);
DWORD dwStyle = GetWindowLongW(window, GWL_STYLE);
SetupWindowPosition(&winRect, dwStyle);
// True_glutReshapeWindow(winRect.right - winRect.left, winRect.bottom - winRect.top);
}
void hook_gui() { void hook_gui() {
hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA); hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA);
hook("User32.dll", "CreateWindowExW", FakeCreateWindowExW, (void**)&TrueCreateWindowExW); hook("User32.dll", "CreateWindowExW", FakeCreateWindowExW, (void**)&TrueCreateWindowExW);
@ -358,5 +376,9 @@ void hook_gui() {
hook("FREEGLUT.DLL", "glutInitDisplayMode", Fake_glutInitDisplayMode, hook("FREEGLUT.DLL", "glutInitDisplayMode", Fake_glutInitDisplayMode,
(void**)&True_glutInitDisplayMode); (void**)&True_glutInitDisplayMode);
hook("FREEGLUT.DLL", "glutFullScreen", Fake_glutFullScreen, (void**)&True_glutFullScreen); hook("FREEGLUT.DLL", "glutFullScreen", Fake_glutFullScreen, (void**)&True_glutFullScreen);
hook("FREEGLUT.DLL", "glutPositionWindow", Fake_glutPositionWindow,
(void**)&True_glutPositionWindow);
hook("FREEGLUT.DLL", "glutReshapeWindow", Fake_glutReshapeWindow,
(void**)&True_glutReshapeWindow);
hook("FREEGLUT.DLL", "glutSwapBuffers", Fake_glutSwapBuffers, (void**)&True_glutSwapBuffers); hook("FREEGLUT.DLL", "glutSwapBuffers", Fake_glutSwapBuffers, (void**)&True_glutSwapBuffers);
} }

View File

@ -13,10 +13,12 @@ static BOOL(WINAPI* TrueSetSystemCursor)(HCURSOR hcur, DWORD id);
static IDirect3D9*(WINAPI* TrueDirect3DCreate9)(UINT SDKVersion); static IDirect3D9*(WINAPI* TrueDirect3DCreate9)(UINT SDKVersion);
static int(WINAPI* TrueGetSystemMetrics)(int nIndex); static int(WINAPI* TrueGetSystemMetrics)(int nIndex);
static void (*__cdecl True_glutFullScreen)(void); static void (__stdcall* True_glutFullScreen)(void);
static void (*__cdecl True_glutSwapBuffers)(void); static void (__stdcall* True_glutSwapBuffers)(void);
static void (*__cdecl True_glutInitDisplayMode)(unsigned int mode); static void (__stdcall* True_glutPositionWindow)(int x, int y);
static LONG (*WINAPI TrueChangeDisplaySettingsExW)(LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, static void (__stdcall* True_glutReshapeWindow)(int width, int height);
static void (__stdcall* True_glutInitDisplayMode)(unsigned int mode);
static LONG (WINAPI* TrueChangeDisplaySettingsExW)(LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode,
HWND hwnd, DWORD dwflags, LPVOID lParam); HWND hwnd, DWORD dwflags, LPVOID lParam);
#define _GetSystemMetrics (TrueGetSystemMetrics ? TrueGetSystemMetrics : GetSystemMetrics) #define _GetSystemMetrics (TrueGetSystemMetrics ? TrueGetSystemMetrics : GetSystemMetrics)

View File

@ -3,11 +3,11 @@
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) { int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr); ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr);
USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port); USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port);
// Poorly exclude pcps. TODO: better // Poorly exclude nxauth. TODO: better
// if (port < 40100 || port > 40120) { if (port != 40190) {
log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff, log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
(addr >> 8) & 0xff, addr & 0xff, port); (addr >> 8) & 0xff, addr & 0xff, port);
// } }
return True_connect(s, name, namelen); return True_connect(s, name, namelen);
} }

View File

@ -12,6 +12,3 @@ struct {
} jvsKeybindings[JVS_IO_MAX]; } jvsKeybindings[JVS_IO_MAX];
int keySystemTest = 0; int keySystemTest = 0;
int keySystemService = 0;
int numJvsBoards = 1;

View File

@ -115,6 +115,12 @@ void* CreateHook32(PVOID src, PVOID dst) {
// mov ebp,esp // mov ebp,esp
// mov eax,DWORD PTR [...] // mov eax,DWORD PTR [...]
len = 6; len = 6;
} else if (bSrc[0] == 0x55 && bSrc[1] == 0x8B && bSrc[2] == 0xEC && bSrc[3] == 0x80 &&
bSrc[4] == 0x3D) {
// pusb ebp
// mov ebp,esp
// cmd BYTE PTR ds:0x...,0x...
len = 10;
} else { } else {
log_error(HOOKS_LOGGER, "Unable to identify gateway length! Function peek:"); log_error(HOOKS_LOGGER, "Unable to identify gateway length! Function peek:");
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {

View File

@ -6,6 +6,7 @@
#include "../../../../subprojects/inih_dep/ini.h" #include "../../../../subprojects/inih_dep/ini.h"
#include "../../dll/devices/smb_pca9535.h" #include "../../dll/devices/smb_pca9535.h"
#include "../../dll/key_config.h"
config_t MiceConfig = { config_t MiceConfig = {
#define SECTION(s, comment) .s = { #define SECTION(s, comment) .s = {
@ -79,7 +80,24 @@ void make_default_config() {
fclose(config_file); fclose(config_file);
} }
char keybindBuffer[8192];
void save_current_config() { void save_current_config() {
// Dump keybind settings
int i = 0;
for (int board = 0; board < MiceConfig.keys.board_count; board++) {
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
jvsKeybindings[board].test);
for (int n = 0; n < JVS_BUTTON_PAIR_COUNT * 2; n++) {
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
jvsKeybindings[board].buttons[n]);
i += snprintf(keybindBuffer + i, _countof(keybindBuffer) - i, "%d,",
jvsKeybindings[board].invert[n]);
}
}
keybindBuffer[i] = '\0';
free(MiceConfig.keys.keys);
MiceConfig.keys.keys = strdup(keybindBuffer);
FILE *config_file; FILE *config_file;
fopen_s(&config_file, CONFIG_PATH, "w"); fopen_s(&config_file, CONFIG_PATH, "w");
if (config_file == NULL) { if (config_file == NULL) {
@ -162,8 +180,8 @@ static int handler(void *user, const char *section, const char *name, const char
return 1; return 1;
} }
const unsigned int RES_W[8] = {640, 640, 1024, 1024, 1280, 1280, 1360, 1920}; const unsigned int RES_W[8] = { 640, 640, 1024, 1024, 1280, 1280, 1360, 1920 };
const unsigned int RES_H[8] = {480, 480, 600, 768, 720, 1024, 768, 1080}; const unsigned int RES_H[8] = { 480, 480, 600, 768, 720, 1024, 768, 1080 };
void load_mice_config() { void load_mice_config() {
if (ini_parse(CONFIG_PATH, handler, &MiceConfig) < 0) { if (ini_parse(CONFIG_PATH, handler, &MiceConfig) < 0) {
make_default_config(); make_default_config();
@ -191,4 +209,42 @@ void load_mice_config() {
else if (MiceConfig.window.w == 640 && MiceConfig.window.h == 480) else if (MiceConfig.window.w == 640 && MiceConfig.window.h == 480)
MiceConfig.sysconf.dipsw |= DIPSW_RES_640x480; MiceConfig.sysconf.dipsw |= DIPSW_RES_640x480;
} }
if (MiceConfig.keys.board_count < 0) MiceConfig.keys.board_count = 0;
if (MiceConfig.keys.board_count > JVS_IO_MAX) MiceConfig.keys.board_count = JVS_IO_MAX;
char *text = MiceConfig.keys.keys;
printf("Text: %s\n", text);
if (text) {
char *copy = (char *)malloc(strlen(text) + 1);
memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1);
char *next_token;
char *token = strtok_s(copy, ",", &next_token);
int board = 0;
int state = 0;
int n = 0;
while (token != NULL) {
int val = atoi(token);
if (state == 0) {
jvsKeybindings[board].test = val;
state = 1;
} else {
if (state == 1) {
jvsKeybindings[board].buttons[n] = val;
state = 2;
} else {
jvsKeybindings[board].invert[n] = val;
state = 1;
if (n++ == JVS_BUTTON_PAIR_COUNT * 2) {
n = 0;
state = 0;
if (board++ == JVS_IO_MAX) break;
}
}
}
token = strtok_s(NULL, ",", &next_token);
}
free(copy);
}
} }

View File

@ -95,6 +95,13 @@ CFG_bool(hooks, registry, true, "")
CFG_bool(hooks, drives, true, "Provides an emulation layer for the physical game SSD") CFG_bool(hooks, drives, true, "Provides an emulation layer for the physical game SSD")
ENDSECTION(hooks) ENDSECTION(hooks)
SECTION(keys, "Raw keybinding data. Edit this using the built in binding tool!")
CFG_int(keys, test, 0, "")
CFG_int(keys, service, 0, "")
CFG_int(keys, board_count, 1, "")
CFG_str(keys, keys, 0, "")
ENDSECTION(keys)
#undef CFG_str #undef CFG_str
#undef CFG_int #undef CFG_int
#undef CFG_bool #undef CFG_bool