diff --git a/engine/Makefile b/engine/Makefile index 6c0769e2f..da9bf1b50 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -438,8 +438,7 @@ endif ifdef BUILD_SDL_IO -GAME_CONSOLE += sdl/joysticks.o \ - sdl/control.o \ +GAME_CONSOLE += sdl/control.o \ sdl/sblaster.o \ sdl/timer.o \ sdl/sdlport.o \ diff --git a/engine/openbor.c b/engine/openbor.c index a41e50cdb..74ad4418a 100644 --- a/engine/openbor.c +++ b/engine/openbor.c @@ -748,10 +748,10 @@ int ent_max = 0; s_player player[MAX_PLAYERS]; u64 bothkeys, bothnewkeys; -s_playercontrols playercontrols1; -s_playercontrols playercontrols2; -s_playercontrols playercontrols3; -s_playercontrols playercontrols4; +s_playercontrols playercontrols1 = {0, 0, 0}; +s_playercontrols playercontrols2 = {1, 0, 0}; +s_playercontrols playercontrols3 = {2, 0, 0}; +s_playercontrols playercontrols4 = {3, 0, 0}; s_playercontrols *playercontrolpointers[] = {&playercontrols1, &playercontrols2, &playercontrols3, &playercontrols4}; s_playercontrols default_control; int default_keys[MAX_BTN_NUM]; @@ -2421,113 +2421,6 @@ void execute_pdie_script(int index) // ------------------------ Save/load ----------------------------- -void clearbuttons(int player) -{ - savedata.joyrumble[player] = 0; - - if (player == 0) - { - savedata.keys[0][SDID_MOVEUP] = CONTROL_DEFAULT1_UP; //Kratus (22-04-21) Maintain the key config only for player 1 because other modules like PSP will not work with CONTROL_NONE - savedata.keys[0][SDID_MOVEDOWN] = CONTROL_DEFAULT1_DOWN; - savedata.keys[0][SDID_MOVELEFT] = CONTROL_DEFAULT1_LEFT; - savedata.keys[0][SDID_MOVERIGHT] = CONTROL_DEFAULT1_RIGHT; - savedata.keys[0][SDID_ATTACK] = CONTROL_DEFAULT1_FIRE1; - savedata.keys[0][SDID_ATTACK2] = CONTROL_DEFAULT1_FIRE2; - savedata.keys[0][SDID_ATTACK3] = CONTROL_DEFAULT1_FIRE3; - savedata.keys[0][SDID_ATTACK4] = CONTROL_DEFAULT1_FIRE4; - savedata.keys[0][SDID_JUMP] = CONTROL_DEFAULT1_FIRE5; - savedata.keys[0][SDID_SPECIAL] = CONTROL_DEFAULT1_FIRE6; - savedata.keys[0][SDID_START] = CONTROL_DEFAULT1_START; - savedata.keys[0][SDID_SCREENSHOT] = CONTROL_DEFAULT1_SCREENSHOT; - #ifdef SDL - //savedata.keys[0][SDID_ESC] = CONTROL_DEFAULT1_ESC; - #endif - - /* *************** SET DEFAULT KEYS *************** */ - // White Dragon: These are default keys: for Android is the touchpad and for Win/Linux etc. is the keyboard - default_keys[SDID_MOVEUP] = CONTROL_DEFAULT1_UP; - default_keys[SDID_MOVEDOWN] = CONTROL_DEFAULT1_DOWN; - default_keys[SDID_MOVELEFT] = CONTROL_DEFAULT1_LEFT; - default_keys[SDID_MOVERIGHT] = CONTROL_DEFAULT1_RIGHT; - default_keys[SDID_ATTACK] = CONTROL_DEFAULT1_FIRE1; - default_keys[SDID_ATTACK2] = CONTROL_DEFAULT1_FIRE2; - default_keys[SDID_ATTACK3] = CONTROL_DEFAULT1_FIRE3; - default_keys[SDID_ATTACK4] = CONTROL_DEFAULT1_FIRE4; - default_keys[SDID_JUMP] = CONTROL_DEFAULT1_FIRE5; - default_keys[SDID_SPECIAL] = CONTROL_DEFAULT1_FIRE6; - default_keys[SDID_START] = CONTROL_DEFAULT1_START; - default_keys[SDID_SCREENSHOT] = CONTROL_DEFAULT1_SCREENSHOT; - - control_setkey(&default_control, FLAG_ESC, CONTROL_ESC); - control_setkey(&default_control, FLAG_MOVEUP, default_keys[SDID_MOVEUP]); - control_setkey(&default_control, FLAG_MOVEDOWN, default_keys[SDID_MOVEDOWN]); - control_setkey(&default_control, FLAG_MOVELEFT, default_keys[SDID_MOVELEFT]); - control_setkey(&default_control, FLAG_MOVERIGHT, default_keys[SDID_MOVERIGHT]); - control_setkey(&default_control, FLAG_ATTACK, default_keys[SDID_ATTACK]); - control_setkey(&default_control, FLAG_ATTACK2, default_keys[SDID_ATTACK2]); - control_setkey(&default_control, FLAG_ATTACK3, default_keys[SDID_ATTACK3]); - control_setkey(&default_control, FLAG_ATTACK4, default_keys[SDID_ATTACK4]); - control_setkey(&default_control, FLAG_JUMP, default_keys[SDID_JUMP]); - control_setkey(&default_control, FLAG_SPECIAL, default_keys[SDID_SPECIAL]); - control_setkey(&default_control, FLAG_START, default_keys[SDID_START]); - control_setkey(&default_control, FLAG_SCREENSHOT, default_keys[SDID_SCREENSHOT]); - } - else if (player == 1) - { - savedata.keys[1][SDID_MOVEUP] = CONTROL_NONE; //Kratus (20-04-21) Used to clear all keys - savedata.keys[1][SDID_MOVEDOWN] = CONTROL_NONE; - savedata.keys[1][SDID_MOVELEFT] = CONTROL_NONE; - savedata.keys[1][SDID_MOVERIGHT] = CONTROL_NONE; - savedata.keys[1][SDID_ATTACK] = CONTROL_NONE; - savedata.keys[1][SDID_ATTACK2] = CONTROL_NONE; - savedata.keys[1][SDID_ATTACK3] = CONTROL_NONE; - savedata.keys[1][SDID_ATTACK4] = CONTROL_NONE; - savedata.keys[1][SDID_JUMP] = CONTROL_NONE; - savedata.keys[1][SDID_SPECIAL] = CONTROL_NONE; - savedata.keys[1][SDID_START] = CONTROL_NONE; - savedata.keys[1][SDID_SCREENSHOT] = CONTROL_NONE; - #ifdef SDL - //savedata.keys[1][SDID_ESC] = CONTROL_DEFAULT2_ESC; - #endif - } - else if (player == 2) - { - savedata.keys[2][SDID_MOVEUP] = CONTROL_NONE; //Kratus (20-04-21) Used to clear all keys - savedata.keys[2][SDID_MOVEDOWN] = CONTROL_NONE; - savedata.keys[2][SDID_MOVELEFT] = CONTROL_NONE; - savedata.keys[2][SDID_MOVERIGHT] = CONTROL_NONE; - savedata.keys[2][SDID_ATTACK] = CONTROL_NONE; - savedata.keys[2][SDID_ATTACK2] = CONTROL_NONE; - savedata.keys[2][SDID_ATTACK3] = CONTROL_NONE; - savedata.keys[2][SDID_ATTACK4] = CONTROL_NONE; - savedata.keys[2][SDID_JUMP] = CONTROL_NONE; - savedata.keys[2][SDID_SPECIAL] = CONTROL_NONE; - savedata.keys[2][SDID_START] = CONTROL_NONE; - savedata.keys[2][SDID_SCREENSHOT] = CONTROL_NONE; - #ifdef SDL - //savedata.keys[2][SDID_ESC] = CONTROL_DEFAULT3_ESC; - #endif - } - else if (player == 3) - { - savedata.keys[3][SDID_MOVEUP] = CONTROL_NONE; //Kratus (20-04-21) Used to clear all keys - savedata.keys[3][SDID_MOVEDOWN] = CONTROL_NONE; - savedata.keys[3][SDID_MOVELEFT] = CONTROL_NONE; - savedata.keys[3][SDID_MOVERIGHT] = CONTROL_NONE; - savedata.keys[3][SDID_ATTACK] = CONTROL_NONE; - savedata.keys[3][SDID_ATTACK2] = CONTROL_NONE; - savedata.keys[3][SDID_ATTACK3] = CONTROL_NONE; - savedata.keys[3][SDID_ATTACK4] = CONTROL_NONE; - savedata.keys[3][SDID_JUMP] = CONTROL_NONE; - savedata.keys[3][SDID_SPECIAL] = CONTROL_NONE; - savedata.keys[3][SDID_START] = CONTROL_NONE; - savedata.keys[3][SDID_SCREENSHOT] = CONTROL_NONE; - #ifdef SDL - //savedata.keys[3][SDID_ESC] = CONTROL_DEFAULT4_ESC; - #endif - } -} - void clearsettings() { int i = 0; @@ -2581,8 +2474,10 @@ void clearsettings() for (i = 0; i < MAX_PLAYERS; i++) { - clearbuttons(i); + savedata.joyrumble[i] = 0; } + + control_clearmappings(); } @@ -2602,6 +2497,15 @@ void savesettings() } fwrite(&savedata, 1, sizeof(savedata), handle); fclose(handle); + + // save controls + getBasePath(path, "Saves", 0); + getPakName(tmpname, 5); + strcat(path, tmpname); + if (!control_savemappings(path)) + { + printf("Failed to save controls to %s\n", path); + } #endif } @@ -2619,6 +2523,14 @@ void saveasdefault() } fwrite(&savedata, 1, sizeof(savedata), handle); fclose(handle); + + // save controls + getBasePath(path, "Saves", 0); + strcat(path, "default.controls"); + if (!control_savemappings(path)) + { + printf("Failed to save controls to %s\n", path); + } #endif } @@ -2649,6 +2561,15 @@ void loadsettings() { clearsettings(); } + + // load controls + getBasePath(path, "Saves", 0); + getPakName(tmpname, 5); + strcat(path, tmpname); + if (!control_loadmappings(path)) + { + printf("Failed to load controls from %s\n", path); + } #else clearsettings(); #endif @@ -2673,6 +2594,14 @@ void loadfromdefault() { clearsettings(); } + + // load controls + getBasePath(path, "Saves", 0); + strcat(path, "default.controls"); + if (!control_loadmappings(path)) + { + printf("Failed to load controls from %s\n", path); + } #else clearsettings(); #endif @@ -35294,6 +35223,7 @@ void fade_out(int type, int speed) void apply_controls() { +#if 0 // TODO int p; for(p = 0; p < MAX_PLAYERS; p++) @@ -35312,6 +35242,7 @@ void apply_controls() control_setkey(playercontrolpointers[p], FLAG_START, savedata.keys[p][SDID_START]); control_setkey(playercontrolpointers[p], FLAG_SCREENSHOT, savedata.keys[p][SDID_SCREENSHOT]); } +#endif } @@ -38168,7 +38099,7 @@ void keyboard_setup(int player) size_t size; ArgList arglist; char argbuf[MAX_ARG_LEN + 1] = ""; - #if SDL || WII || DC + #if SDL || WII int OPTIONS_NUM = btnnum + 3; #else int OPTIONS_NUM = btnnum + 2; @@ -38236,6 +38167,9 @@ void keyboard_setup(int player) while(!quit) { + int deviceID = playercontrolpointers[player]->deviceID; + int *mapping = control_getmappings(deviceID); + voffset = -6; _menutextm(2, -8, 0, Tr("Player %i"), player + 1); for(i = 0; i < btnnum; i++) @@ -38243,11 +38177,11 @@ void keyboard_setup(int player) if(!disabledkey[i]) { _menutext((selector == i), col1, voffset, "%s", buttonnames[i]); - _menutext((selector == i), col2, voffset, "%s", control_getkeyname(savedata.keys[player][i])); + _menutext((selector == i), col2, voffset, "%s", i == setting ? "..." : control_getkeyname(deviceID, mapping[i])); voffset++; } } - #if SDL || WII || DC + #if SDL || WII ++voffset; if(savedata.joyrumble[player]) { @@ -38266,23 +38200,22 @@ void keyboard_setup(int player) if(setting > -1) { - if(bothnewkeys & FLAG_ESC) + k = control_getremappedkey(); + if (k >= 0) { - savedata.keys[player][setting] = ok; - sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol, savedata.effectvol, 50); + safe_set(mapping, setting, k, ok); + sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol, savedata.effectvol, 100); + + // Prevent the newly configured button from counting as "pressed" and starting config again + playercontrolpointers[player]->keyflags |= (1 << setting); + setting = -1; + control_remapdevice(-1); } - if(setting > -1) + else if (bothnewkeys & FLAG_ESC) { - k = control_scankey(); - if(k) - { - safe_set(savedata.keys[player], setting, k, ok); - sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol, savedata.effectvol, 100); - setting = -1; - // Prevent accidental screenshot - bothnewkeys = 0; - } + sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol, savedata.effectvol, 50); + setting = -1; } } else @@ -38322,27 +38255,20 @@ void keyboard_setup(int player) while(disabledkey[selector]) if(++selector > btnnum - 1) break; } - #if SDL || WII || DC - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - #else - if(bothnewkeys & (FLAG_ANYBUTTON)) - #endif - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) +#if SDL || WII + if (selector == OPTIONS_NUM - 3 && (bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON))) + { + // TODO: make rumble enable/disable a property of device, not player + sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol, savedata.effectvol, 100); + savedata.joyrumble[player] = !savedata.joyrumble[player]; + } + else +#endif + if (bothnewkeys & FLAG_ANYBUTTON) { sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol, savedata.effectvol, 100); - #if SDL || WII || DC - if (selector != OPTIONS_NUM - 3 && - bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT)) continue; - - if(selector == OPTIONS_NUM - 3) - { - savedata.joyrumble[player] ^= 1; - } - else if(selector == OPTIONS_NUM - 2) // OK - #else if(selector == OPTIONS_NUM - 2) // OK - #endif { quit = 2; } @@ -38352,16 +38278,14 @@ void keyboard_setup(int player) } else if(selector == OPTIONS_NUM) // default { - clearbuttons(player); + control_resetmappings(deviceID); + savedata.joyrumble[player] = 0; } else { setting = selector; - ok = savedata.keys[player][setting]; - savedata.keys[player][setting] = 0; - #ifndef DC - keyboard_getlastkey(); - #endif + ok = mapping[setting]; + control_remapdevice(deviceID); } } } @@ -38377,139 +38301,203 @@ void keyboard_setup(int player) loadsettings(); } - update(0, 0); bothnewkeys = 0; printf("Done!\n"); } +// Set device safely (with switching) +static void safe_set_device(int player, int newdevice, int olddevice) +{ + int i; + for (i = 0; i < levelsets[current_set].maxplayers; i++) + { + if (playercontrolpointers[i]->deviceID == newdevice) + { + playercontrolpointers[i]->deviceID = olddevice; + } + } + playercontrolpointers[player]->deviceID = newdevice; +} + void menu_options_input() { int quit = 0; - int selector = 1; // 0 - int x_pos = -6; + int selector = 0; + const int col1 = -7; + const int col2 = 1; + const int max_players = levelsets[current_set].maxplayers; + const int base = -4 + (4 - max_players); + int active_devices = 0; + int selected_device = playercontrolpointers[0]->deviceID; #if ANDROID - int OPTIONS_NUM = 6; + const int OPTIONS_NUM = 9; #else - int OPTIONS_NUM = 5; + const int OPTIONS_NUM = 8; #endif controloptionsMenu = 1; bothnewkeys = 0; - while(!quit) + while (!quit) { - _menutextm(2, x_pos-1, 0, Tr("Control Options")); + _menutextm(2, base - 2, 0, Tr("Control Options")); - #if PSP - if(savedata.usejoy) - { - _menutext((selector == 0), -4, -2, Tr("Analog Pad Enabled")); - } - else - { - _menutext((selector == 0), -4, -2, Tr("Analog Pad Disabled")); - } - #elif WII - if(savedata.usejoy) + for (int i = 0; i < max_players; i++) { - _menutext((selector == 0), -4, -2, Tr("Nunchuk Analog Enabled")); + _menutext((selector == i), col1, base + i + (selector < i), Tr("Player %i"), i+1); + _menutext((selector == i), col2, base + i + (selector < i), "< %s >", + control_getdevicename(selector == i ? selected_device : playercontrolpointers[i]->deviceID)); } - else + + if (selector < max_players) { - _menutext((selector == 0), -4, -2, Tr("Nunchuk Analog Disabled")); + _menutextm(1, selector + base + 1, 0, Tr("Press Start to apply, Up or Down to cancel")); } - #else - if(savedata.usejoy) + + active_devices = 0; + for (int i = 0; i < max_players; i++) { - _menutext((selector == 0), x_pos, -2, Tr("GamePads Enabled")); - if(!control_getjoyenabled()) + if (control_isvaliddevice(playercontrolpointers[i]->deviceID)) { - _menutext((selector == 0), x_pos+11, -2, Tr(" - Device Not Ready")); + _menutextm((selector == 4+i), 1 + active_devices, 0, Tr("Setup Player %i..."), i + 1); + ++active_devices; } } - else - { - _menutext((selector == 0), x_pos, -2, Tr("GamePads Disabled")); - } - #endif - _menutext((selector == 1), x_pos,-1, Tr("Setup Player 1...")); - _menutext((selector == 2), x_pos, 0, Tr("Setup Player 2...")); - _menutext((selector == 3), x_pos, 1, Tr("Setup Player 3...")); - _menutext((selector == 4), x_pos, 2, Tr("Setup Player 4...")); #if ANDROID - if(savedata.is_touchpad_vibration_enabled) + if (savedata.is_touchpad_vibration_enabled) { - _menutextm((selector == 5), 4, 0, Tr("Touchpad Vibration Enabled")); + _menutextm((selector == 8), 2 + active_devices, 0, Tr("Touchpad Vibration Enabled")); } else { - _menutextm((selector == 5), 4, 0, Tr("Touchpad Vibration Disabled")); + _menutextm((selector == 8), 2 + active_devices, 0, Tr("Touchpad Vibration Disabled")); } - _menutextm((selector == 6), 6, 0, Tr("Back")); + _menutextm((selector == 9), 4 + active_devices, 0, Tr("Back")); #else - _menutextm((selector == 5), 5, 0, Tr("Back")); + _menutextm((selector == 8), 2 + active_devices, 0, Tr("Back")); #endif update((level != NULL), 0); - if(bothnewkeys & FLAG_ESC) + if (bothnewkeys & FLAG_ESC) { quit = 1; } - if(bothnewkeys & FLAG_MOVEUP) + if (bothnewkeys & FLAG_MOVEUP) { --selector; - if(SAMPLE_BEEP >= 0) + if (SAMPLE_BEEP >= 0) { sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol, savedata.effectvol, 100); } + + // skip over invisible configuration entries for non-existent devices + while (selector >= 4 && selector <= 7 && !control_isvaliddevice(selector - 4)) + { + --selector; + } + + // skip over invisible device selection entries for non-existent players + if (selector < 4 && selector >= max_players) + { + selector = max_players - 1; + } } - if(bothnewkeys & FLAG_MOVEDOWN) + if (bothnewkeys & FLAG_MOVEDOWN) { ++selector; - if(SAMPLE_BEEP >= 0) + if (SAMPLE_BEEP >= 0) { sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol, savedata.effectvol, 100); } + + // skip over invisible device selection entries for non-existent players + if (selector < 4 && selector >= max_players) + { + selector = 4; + } + + // skip over invisible configuration entries for non-existent devices + while (selector >= 4 && selector <= 7 && !control_isvaliddevice(selector - 4)) + { + ++selector; + } } - if(selector < 0) + if (selector < 0) { selector = OPTIONS_NUM; } - if(selector > OPTIONS_NUM) + if (selector > OPTIONS_NUM) { selector = 0; } - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) + if (selector < 4 && (bothnewkeys & (FLAG_MOVEUP | FLAG_MOVEDOWN))) { + selected_device = playercontrolpointers[selector]->deviceID; + } - if(SAMPLE_BEEP2 >= 0) + if (bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) + { + // Left/right only make sense for device reassignment + if (selector >= 4 && !(bothnewkeys & FLAG_ANYBUTTON)) + { + continue; + } + + if (SAMPLE_BEEP2 >= 0) { sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol, savedata.effectvol, 100); } - switch(selector) + switch (selector) { case 0: - control_usejoy((savedata.usejoy ^= 1)); - break; case 1: + case 2: + case 3: + if (bothnewkeys & FLAG_MOVELEFT) + { + do { + --selected_device; + if (selected_device < 0) + { + selected_device = MAX_DEVICES - 1; + } + } while (!control_isvaliddevice(selected_device)); + } + else if (bothnewkeys & FLAG_MOVERIGHT) + { + do { + ++selected_device; + if (selected_device >= MAX_DEVICES) + { + selected_device = 0; + } + } while (!control_isvaliddevice(selected_device)); + } + else // (bothnewkeys & FLAG_ANYBUTTON) + { + // assign selected device to player + safe_set_device(selector, selected_device, playercontrolpointers[selector]->deviceID); + } + break; + case 4: keyboard_setup(0); break; - case 2: + case 5: keyboard_setup(1); break; - case 3: + case 6: keyboard_setup(2); break; - case 4: + case 7: keyboard_setup(3); break; #if ANDROID - case 5: - savedata.is_touchpad_vibration_enabled ^= 1; + case 8: + savedata.is_touchpad_vibration_enabled = !savedata.is_touchpad_vibration_enabled; break; #endif default: diff --git a/engine/openbor.h b/engine/openbor.h index 9c06b2034..a19fafbe5 100644 --- a/engine/openbor.h +++ b/engine/openbor.h @@ -416,33 +416,6 @@ typedef struct // Key definitions. typedef enum { - FLAG_ESC = (1 << 0), - FLAG_START = (1 << 1), - FLAG_MOVELEFT = (1 << 2), - FLAG_MOVERIGHT = (1 << 3), - FLAG_MOVEUP = (1 << 4), - FLAG_MOVEDOWN = (1 << 5), - FLAG_ATTACK = (1 << 6), - FLAG_JUMP = (1 << 7), - FLAG_SPECIAL = (1 << 8), - FLAG_SCREENSHOT = (1 << 9), - FLAG_ATTACK2 = (1 << 10), - FLAG_ATTACK3 = (1 << 11), - FLAG_ATTACK4 = (1 << 12), - FLAG_ANYBUTTON = (FLAG_START|FLAG_SPECIAL|FLAG_ATTACK|FLAG_ATTACK2|FLAG_ATTACK3|FLAG_ATTACK4|FLAG_JUMP), - FLAG_CONTROLKEYS = (FLAG_SPECIAL|FLAG_ATTACK|FLAG_ATTACK2|FLAG_ATTACK3|FLAG_ATTACK4|FLAG_JUMP|FLAG_MOVEUP|FLAG_MOVEDOWN|FLAG_MOVELEFT|FLAG_MOVERIGHT), - FLAG_FORWARD = (1 << 13), - FLAG_BACKWARD = (1 << 14) -} e_key_def; - -typedef enum -{ - /* - Key id enum. - Damon V. Caskey - 2013-12-27 - */ - SDID_MOVEUP, SDID_MOVEDOWN, SDID_MOVELEFT, @@ -455,7 +428,8 @@ typedef enum SDID_SPECIAL, SDID_START, SDID_SCREENSHOT, - SDID_ESC + SDID_ESC, + SDID_COUNT // not a key ID; it's the number of key IDs } e_key_id; // Caskey, Damon V. @@ -464,6 +438,34 @@ typedef enum // Entity types. typedef enum { + FLAG_MOVEUP = (1 << SDID_MOVEUP), + FLAG_MOVEDOWN = (1 << SDID_MOVEDOWN), + FLAG_MOVELEFT = (1 << SDID_MOVELEFT), + FLAG_MOVERIGHT = (1 << SDID_MOVERIGHT), + FLAG_ATTACK = (1 << SDID_ATTACK), + FLAG_ATTACK2 = (1 << SDID_ATTACK2), + FLAG_ATTACK3 = (1 << SDID_ATTACK3), + FLAG_ATTACK4 = (1 << SDID_ATTACK4), + FLAG_JUMP = (1 << SDID_JUMP), + FLAG_SPECIAL = (1 << SDID_SPECIAL), + FLAG_START = (1 << SDID_START), + FLAG_SCREENSHOT = (1 << SDID_SCREENSHOT), + FLAG_ESC = (1 << SDID_ESC), + + FLAG_ANYBUTTON = (FLAG_START|FLAG_SPECIAL|FLAG_ATTACK|FLAG_ATTACK2|FLAG_ATTACK3|FLAG_ATTACK4|FLAG_JUMP), + FLAG_CONTROLKEYS = (FLAG_SPECIAL|FLAG_ATTACK|FLAG_ATTACK2|FLAG_ATTACK3|FLAG_ATTACK4|FLAG_JUMP|FLAG_MOVEUP|FLAG_MOVEDOWN|FLAG_MOVELEFT|FLAG_MOVERIGHT), + FLAG_FORWARD = 0x40000000, + FLAG_BACKWARD = 0x80000000 +} e_key_def; + +typedef enum +{ + /* + Entity type enumerator. + Damon V. Caskey + 2013-12-27 + */ + TYPE_NONE = (1 << 0), TYPE_PLAYER = (1 << 1), TYPE_ENEMY = (1 << 2), diff --git a/engine/sdl/control.c b/engine/sdl/control.c index 9118fb1cf..110e264d1 100644 --- a/engine/sdl/control.c +++ b/engine/sdl/control.c @@ -3,614 +3,879 @@ * ----------------------------------------------------------------------- * All rights reserved, see LICENSE in OpenBOR root for details. * - * Copyright (c) 2004 - 2014 OpenBOR Team + * Copyright (c) 2004 - 2019 OpenBOR Team */ // Generic control stuff (keyboard+joystick) -#include "video.h" +#include +#include +#include #include "globals.h" #include "control.h" -#include "stristr.h" -#include "sblaster.h" -#include "joysticks.h" #include "openbor.h" - -#define T_AXIS 7000 +#include "List.h" + +#define AXIS_THRESHOLD 7000 + +typedef enum { + DEVICE_TYPE_NONE, + DEVICE_TYPE_KEYBOARD, + DEVICE_TYPE_CONTROLLER, // XInput compatible controller + DEVICE_TYPE_JOYSTICK, // controller not compatible with XInput +} DeviceType; + +typedef struct { + DeviceType deviceType; + char name[CONTROL_DEVICE_NAME_SIZE]; + int mappings[SDID_COUNT]; + SDL_Haptic *haptic; + union { + // no extra structure needed for keyboard + SDL_GameController *controller; + SDL_Joystick *joystick; + }; +} InputDevice; + +static InputDevice devices[MAX_DEVICES]; +static bool controlInited = false; +static int keyboardDeviceID = -1; +static bool altEnterPressed = false; + +// if non-null, device is being remapped in the input settings menu +static InputDevice *remapDevice = NULL; +static int remapKeycode = -1; + +// each list member is an array of SDID_COUNT ints, dynamically allocated +static List savedMappings; +static bool savedMappingsInited = false; #ifdef ANDROID -#include "jniutils.h" -#endif - -SDL_Joystick *joystick[JOY_LIST_TOTAL]; // SDL struct for joysticks -SDL_Haptic *joystick_haptic[JOY_LIST_TOTAL]; // SDL haptic for joysticks -static int usejoy; // To be or Not to be used? -static int numjoy; // Number of Joy(s) found -static int lastkey; // Last keyboard key Pressed -static int lastjoy; // Last joystick button/axis/hat input - -int sdl_game_started = 0; +#define MAX_POINTERS 30 +typedef enum +{ + TOUCH_STATUS_UP, + TOUCH_STATUS_DOWN +} touch_status; -extern int default_keys[MAX_BTN_NUM]; -extern s_playercontrols default_control; +typedef struct TouchStatus { + float px[MAX_POINTERS]; + float py[MAX_POINTERS]; + SDL_FingerID pid[MAX_POINTERS]; + touch_status pstatus[MAX_POINTERS]; +} TouchStatus; -#ifdef ANDROID extern int nativeWidth; extern int nativeHeight; static TouchStatus touch_info; + +static void control_update_android_touch(TouchStatus *touch_info, int maxp); #endif -/* -Here is where we aquiring all joystick events -and map them to BOR's layout. Currently support -up to 4 controllers. -*/ -void getPads(Uint8* keystate, Uint8* keystate_def) +// update the mappings for a device in the save data +static void update_saved_mapping(int deviceID) { - int i, j, x, axis; - SDL_Event ev; - while(SDL_PollEvent(&ev)) - { - switch(ev.type) - { - case SDL_KEYDOWN: -#ifdef SDL2 - lastkey = ev.key.keysym.scancode; - if((keystate[SDL_SCANCODE_LALT] || keystate[SDL_SCANCODE_RALT]) && (lastkey == SDL_SCANCODE_RETURN)) - { - video_fullscreen_flip(); - keystate[SDL_SCANCODE_RETURN] = 0; - } - if(lastkey != SDL_SCANCODE_F10) break; -#else - lastkey = ev.key.keysym.sym; - if((keystate[SDLK_LALT] || keystate[SDLK_RALT]) && (lastkey == SDLK_RETURN)) - { - video_fullscreen_flip(); - keystate[SDLK_RETURN] = 0; - } - if(lastkey != SDLK_F10) break; -#endif -#ifdef ANDROID - case SDL_FINGERDOWN: - { - for(i=0; iw, s->h, videomodes.hRes, videomodes.vRes); - break; - } - } - SDL_Delay(1); - } - } - break; -#endif - case SDL_QUIT: - borShutdown(0, DEFAULT_SHUTDOWN_MESSAGE); - break; - - case SDL_JOYBUTTONUP: - for(i=0; i= 8 && ev.jbutton.button <= 18) joysticks[i].Buttons &= ~(JoystickBits[ev.jbutton.button - 3]); - } - /*else - { - // add key flag from event - #ifdef ANDROID - joysticks[i].Buttons &= 0x00 << ev.jbutton.button; - #endif - }*/ - } - } - break; - - case SDL_JOYBUTTONDOWN: - for(i=0; i> (4*ev.jhat.hat)) & 0x0F; // hat's previous state - if(ev.jhat.value & SDL_HAT_UP && !(x & SDL_HAT_UP)) lastjoy = hatfirst; - if(ev.jhat.value & SDL_HAT_RIGHT && !(x & SDL_HAT_RIGHT)) lastjoy = hatfirst + 1; - if(ev.jhat.value & SDL_HAT_DOWN && !(x & SDL_HAT_DOWN)) lastjoy = hatfirst + 2; - if(ev.jhat.value & SDL_HAT_LEFT && !(x & SDL_HAT_LEFT)) lastjoy = hatfirst + 3; - //if(lastjoy) fprintf(stderr, "SDL_JOYHATMOTION - Joystick %i Hat %i (Index %i)\n", i, ev.jhat.hat, lastjoy); - - // add key flag from event (0x01 0x02 0x04 0x08) - #ifdef ANDROID - if(ev.jhat.value & SDL_HAT_UP) joysticks[i].Hats |= SDL_HAT_UP << (ev.jhat.hat*4); - if(ev.jhat.value & SDL_HAT_RIGHT) joysticks[i].Hats |= SDL_HAT_RIGHT << (ev.jhat.hat*4); - if(ev.jhat.value & SDL_HAT_DOWN) joysticks[i].Hats |= SDL_HAT_DOWN << (ev.jhat.hat*4); - if(ev.jhat.value & SDL_HAT_LEFT) joysticks[i].Hats |= SDL_HAT_LEFT << (ev.jhat.hat*4); - #endif - } - } - break; - - case SDL_JOYAXISMOTION: - for(i=0; i> (2*ev.jaxis.axis)) & 0x03; // previous state of axis - if(ev.jaxis.value < -1*T_AXIS && !(x & 0x01)) lastjoy = axisfirst; - if(ev.jaxis.value > T_AXIS && !(x & 0x02)) lastjoy = axisfirst + 1; - //if(lastjoy) fprintf(stderr, "SDL_JOYAXISMOTION - Joystick %i Axis %i = Position %i (Index %i)\n", i, ev.jaxis.axis, ev.jaxis.value, lastjoy); - - // add key flag from event - #ifdef ANDROID - if(ev.jaxis.value < -1*T_AXIS) { joysticks[i].Axes |= 0x01 << (ev.jaxis.axis*2); } - if(ev.jaxis.value > T_AXIS) { joysticks[i].Axes |= 0x02 << (ev.jaxis.axis*2); } - #endif - } - } - break; - - // PLUG AND PLAY - case SDL_JOYDEVICEADDED: - if (ev.jdevice.which < JOY_LIST_TOTAL) - { - int i = ev.jdevice.which; - char buffer[MAX_BUFFER_LEN]; - char joy_name[MAX_BUFFER_LEN]; - open_joystick(i); - //get_time_string(buffer, MAX_BUFFER_LEN, (time_t)ev.jdevice.timestamp, TIMESTAMP_PATTERN); - get_now_string(buffer, MAX_BUFFER_LEN, TIMESTAMP_PATTERN); - numjoy = SDL_NumJoysticks(); - strcpy(joy_name,get_joystick_name(joysticks[i].Name)); - printf("Joystick: \"%s\" connected at port: %d at %s\n",joy_name,i,buffer); - } - break; + InputDevice *device = &devices[deviceID]; + if (device->deviceType == DEVICE_TYPE_NONE) return; - case SDL_JOYDEVICEREMOVED: - if (ev.jdevice.which < JOY_LIST_TOTAL) - { - int i = ev.jdevice.which; - if(joystick[i]) - { - char buffer[MAX_BUFFER_LEN]; - char joy_name[MAX_BUFFER_LEN]; - get_now_string(buffer, MAX_BUFFER_LEN, TIMESTAMP_PATTERN); - //close_joystick(i); //Kratus (20-04-21) disable the entire code to maintain joystick IDs - numjoy = SDL_NumJoysticks(); - strcpy(joy_name,get_joystick_name(joysticks[i].Name)); - printf("Joystick: \"%s\" disconnected from port: %d at %s\n",joy_name,i,buffer); - } - } - break; + if (List_FindByName(&savedMappings, device->name)) + { + memcpy(List_Retrieve(&savedMappings), device->mappings, SDID_COUNT * sizeof(int)); + } + else + { + int *mappings = malloc(SDID_COUNT * sizeof(int)); + memcpy(mappings, device->mappings, SDID_COUNT * sizeof(int)); + List_InsertAfter(&savedMappings, mappings, device->name); + } +} - default: - break; - } +// set the mappings for a device to the saved settings +static void load_from_saved_mapping(int deviceID) +{ + InputDevice *device = &devices[deviceID]; + if (device->deviceType == DEVICE_TYPE_NONE) return; - } + if (List_FindByName(&savedMappings, device->name)) + { + memcpy(device->mappings, List_Retrieve(&savedMappings), SDID_COUNT * sizeof(int)); + } + else + { + control_resetmappings(deviceID); + } +} - if(joysticks[0].Type != JOY_TYPE_GAMEPARK) +static void clear_saved_mappings() +{ + if (!savedMappingsInited) + { + List_Init(&savedMappings); + savedMappingsInited = true; + } + + int numMappings = List_GetSize(&savedMappings); + List_Reset(&savedMappings); + for (int i = 0; i < numMappings; i++) { - // new PC joystick code - forget about SDL joystick events, just do a state check - SDL_JoystickUpdate(); - for(i = 0; i < JOY_LIST_TOTAL; i++) - { - // reset state - joysticks[i].Axes = joysticks[i].Hats = joysticks[i].Buttons = 0; - if (joystick[i] == NULL) continue; + free(List_Retrieve(&savedMappings)); + List_GotoNext(&savedMappings); + } + List_Clear(&savedMappings); +} - // check buttons - for(j = 0; j < joysticks[i].NumButtons; j++) - { - joysticks[i].Buttons |= SDL_JoystickGetButton(joystick[i], j) << j; - } +/* If 2 or more of the same type of controller are plugged in, we need to disambiguate them so that a player assigning + devices in the options menu can tell them apart. Do this by appending "#2", "#3", etc. to the names. */ +static void set_device_name(int deviceID, const char *name) +{ + char fullName[CONTROL_DEVICE_NAME_SIZE]; - // check axes - for(j = 0; j < joysticks[i].NumAxes; j++) - { - axis = SDL_JoystickGetAxis(joystick[i], j); - if(axis < -1*T_AXIS) { joysticks[i].Axes |= 0x01 << (j*2); } - if(axis > T_AXIS) { joysticks[i].Axes |= 0x02 << (j*2); } - } + for (int i = 0; i < MAX_DEVICES; i++) + { + bool nameTaken = false; - // check hats - for(j = 0; j < joysticks[i].NumHats; j++) - { - //joysticks[i].Hats |= SDL_JoystickGetHat(joystick[i], j) << (j*4); + if (i == 0) + { + snprintf(fullName, sizeof(fullName), "%s", name); + } + else + { + snprintf(fullName, sizeof(fullName), "%s #%i", name, i + 1); + } - Uint8 hat_value = SDL_JoystickGetHat(joystick[i], j); - if(hat_value & SDL_HAT_UP) joysticks[i].Hats |= SDL_HAT_UP << (j*4); - if(hat_value & SDL_HAT_RIGHT) joysticks[i].Hats |= SDL_HAT_RIGHT << (j*4); - if(hat_value & SDL_HAT_DOWN) joysticks[i].Hats |= SDL_HAT_DOWN << (j*4); - if(hat_value & SDL_HAT_LEFT) joysticks[i].Hats |= SDL_HAT_LEFT << (j*4); + for (int j = 0; j < MAX_DEVICES; j++) + { + if (j != deviceID && devices[j].deviceType != DEVICE_TYPE_NONE) + { + if (0 == strcmp(devices[j].name, fullName)) + { + nameTaken = true; + break; + } } + } - // combine axis, hat, and button state into a single value - joysticks[i].Data = joysticks[i].Buttons; - joysticks[i].Data |= joysticks[i].Axes << joysticks[i].NumButtons; - joysticks[i].Data |= joysticks[i].Hats << (joysticks[i].NumButtons + 2*joysticks[i].NumAxes); - } - } + if (!nameTaken) break; + } + snprintf(devices[deviceID].name, sizeof(devices[deviceID].name), "%s", fullName); } -/* -Convert binary masked data to indexes -*/ -static int flag_to_index(u64 flag) +static void setup_joystick(int deviceID, int sdlDeviceID) { - int index = 0; - u64 bit = 1; - while(!((bit<= MAX_DEVICES) + { + // subtract 1 so we have room for the keyboard later + numJoysticks = MAX_DEVICES - 1; + } - if (scan != 2) + int joystickCount = 0; + for (int i = 0; i < numJoysticks; i++) { - for(i = 0; i < numjoy; i++) + // blacklist the Android accelerometer that SDL counts as a "joystick" + if (0 == stricmp("Android Accelerometer", SDL_JoystickNameForIndex(i))) { - char real_joy_name[MAX_BUFFER_LEN]; + continue; + } - strcpy(real_joy_name,SDL_JoystickNameForIndex(i)); - if (strcmp(real_joy_name, "Android Accelerometer") == 0) - { - --numjoyNoAcc; - } + setup_joystick(joystickCount, i); + joystickCount++; + } + + keyboardDeviceID = joystickCount; + devices[joystickCount].deviceType = DEVICE_TYPE_KEYBOARD; +#ifdef ANDROID + snprintf(devices[joystickCount].name, sizeof(devices[joystickCount].name), "%s", "On-Screen Controller"); +#else + snprintf(devices[joystickCount].name, sizeof(devices[joystickCount].name), "%s", "Keyboard"); +#endif + load_from_saved_mapping(joystickCount); + +#ifdef ANDROID + for (int i = 0; i < MAX_POINTERS; i++) + { + touch_info.pstatus[i] = TOUCH_STATUS_UP; + } +#endif + + controlInited = true; +} + +void control_exit() +{ + if (!controlInited) return; + + clear_saved_mappings(); + + for (int i = 0; i < MAX_DEVICES; i++) + { + InputDevice *device = &devices[i]; + if (device->deviceType == DEVICE_TYPE_CONTROLLER) + { + SDL_GameControllerClose(device->controller); + device->controller = NULL; } - if(numjoyNoAcc <= 0) + else if (device->deviceType == DEVICE_TYPE_JOYSTICK) { - printf("No Joystick(s) Found!\n"); - return; + SDL_JoystickClose(device->joystick); + device->joystick = NULL; } - else + if (device->haptic) { - printf("\n%d joystick(s) found!\n", numjoyNoAcc); + SDL_HapticClose(device->haptic); + device->haptic = NULL; } + device->deviceType = DEVICE_TYPE_NONE; } - if (numjoyNoAcc > JOY_LIST_TOTAL) numjoy = JOY_LIST_TOTAL; // avoid overflow bug + keyboardDeviceID = -1; + remapDevice = NULL; + remapKeycode = -1; + controlInited = false; +} - for(i = 0; i < numjoy; i++) - { - int joy_idx = i; - char real_joy_name[MAX_BUFFER_LEN]; +static void set_default_keyboard_mappings(InputDevice *device) +{ + device->mappings[SDID_MOVEUP] = SDL_SCANCODE_UP; + device->mappings[SDID_MOVEDOWN] = SDL_SCANCODE_DOWN; + device->mappings[SDID_MOVELEFT] = SDL_SCANCODE_LEFT; + device->mappings[SDID_MOVERIGHT] = SDL_SCANCODE_RIGHT; + device->mappings[SDID_ATTACK] = SDL_SCANCODE_A; + device->mappings[SDID_ATTACK2] = SDL_SCANCODE_S; + device->mappings[SDID_ATTACK3] = SDL_SCANCODE_Z; + device->mappings[SDID_ATTACK4] = SDL_SCANCODE_X; + device->mappings[SDID_JUMP] = SDL_SCANCODE_D; + device->mappings[SDID_SPECIAL] = SDL_SCANCODE_F; + device->mappings[SDID_START] = SDL_SCANCODE_RETURN; + device->mappings[SDID_SCREENSHOT] = SDL_SCANCODE_F12; + device->mappings[SDID_ESC] = SDL_SCANCODE_ESCAPE; +} - strcpy(real_joy_name,SDL_JoystickNameForIndex(i)); +static void set_default_controller_mappings(InputDevice *device) +{ + device->mappings[SDID_MOVEUP] = SDL_CONTROLLER_BUTTON_DPAD_UP; + device->mappings[SDID_MOVEDOWN] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + device->mappings[SDID_MOVELEFT] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + device->mappings[SDID_MOVERIGHT] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + device->mappings[SDID_ATTACK] = SDL_CONTROLLER_BUTTON_A; + device->mappings[SDID_ATTACK2] = SDL_CONTROLLER_BUTTON_X; + device->mappings[SDID_ATTACK3] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + device->mappings[SDID_ATTACK4] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + device->mappings[SDID_JUMP] = SDL_CONTROLLER_BUTTON_B; + device->mappings[SDID_SPECIAL] = SDL_CONTROLLER_BUTTON_Y; + device->mappings[SDID_START] = SDL_CONTROLLER_BUTTON_START; + device->mappings[SDID_SCREENSHOT] = SDL_CONTROLLER_BUTTON_BACK; + device->mappings[SDID_ESC] = SDL_CONTROLLER_BUTTON_B; +} - if (strcmp(real_joy_name, "Android Accelerometer") == 0) - { - continue; - } +static void set_default_joystick_mappings(InputDevice *device) +{ + int numButtons = SDL_JoystickNumButtons(device->joystick); + + device->mappings[SDID_MOVEUP] = numButtons; + device->mappings[SDID_MOVEDOWN] = numButtons + 1; + device->mappings[SDID_MOVELEFT] = numButtons + 2; + device->mappings[SDID_MOVERIGHT] = numButtons + 3; + device->mappings[SDID_ATTACK] = 0; + device->mappings[SDID_ATTACK2] = 3; + device->mappings[SDID_ATTACK3] = 4; + device->mappings[SDID_ATTACK4] = 5; + device->mappings[SDID_JUMP] = 1; + device->mappings[SDID_SPECIAL] = 2; + device->mappings[SDID_START] = 6; + device->mappings[SDID_SCREENSHOT] = 7; + device->mappings[SDID_ESC] = device->mappings[SDID_SPECIAL]; +} - open_joystick(joy_idx); +void control_resetmappings(int deviceID) +{ + if (deviceID < 0) return; - if(scan != 2) + InputDevice *device = &devices[deviceID]; + switch (device->deviceType) + { + case DEVICE_TYPE_KEYBOARD: + set_default_keyboard_mappings(device); + break; + case DEVICE_TYPE_CONTROLLER: + set_default_controller_mappings(device); + break; + case DEVICE_TYPE_JOYSTICK: + set_default_joystick_mappings(device); + break; + default: + memset(device->mappings, 0, sizeof(device->mappings)); + break; + } +} + +static void handle_events() +{ + SDL_Event ev; + while (SDL_PollEvent(&ev)) + { + switch (ev.type) { - int is_rumble_support = (joystick_haptic[i] != NULL && SDL_HapticRumbleSupported(joystick_haptic[i])) ? 1 : 0; - char* rumble_support = (is_rumble_support) ? "yes" : "no"; + case SDL_QUIT: + { + borShutdown(0, DEFAULT_SHUTDOWN_MESSAGE); + break; + } + + /* There is also a CONTROLLERDEVICEADDED event, but we can ignore it since this one works for + both kinds of controllers/joysticks. */ + case SDL_JOYDEVICEADDED: + { + bool already_in_use = false; + + /* We get this event for devices that were plugged in at application start, which we already + initialized in control_init(). So look through the device list to avoid duplicates. */ + if (SDL_IsGameController(ev.jdevice.which)) + { + SDL_GameController *controller = SDL_GameControllerOpen(ev.jdevice.which); + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType == DEVICE_TYPE_CONTROLLER && + devices[i].controller == controller) + { + already_in_use = true; + //printf("Already in use as device %i\n", i); + break; + } + } + SDL_GameControllerClose(controller); + } + else + { + SDL_Joystick *joystick = SDL_JoystickOpen(ev.jdevice.which); + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType == DEVICE_TYPE_JOYSTICK && + devices[i].joystick == joystick) + { + already_in_use = true; + //printf("Already in use as device %i\n", i); + break; + } + } + SDL_JoystickClose(joystick); + } + + if (already_in_use) + { + break; + } + + // Okay, it's actually a newly inserted device, not a duplicate. Initialize it. + printf("Controller or joystick hotplugged: SDL device ID=%i\n", ev.jdevice.which); + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType == DEVICE_TYPE_NONE) + { + setup_joystick(i, ev.jdevice.which); + printf("Hotplugged %s set as device #%i\n", + devices[i].deviceType == DEVICE_TYPE_CONTROLLER ? "controller" : "joystick", + i); + break; + } + } + break; + } + + /* There is also a CONTROLLERDEVICEREMOVED event, but we can ignore it since this one works for + both kinds of controllers/joysticks. */ + case SDL_JOYDEVICEREMOVED: + { + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType == DEVICE_TYPE_CONTROLLER && + devices[i].controller == SDL_GameControllerFromInstanceID(ev.jdevice.which)) + { + SDL_GameControllerClose(devices[i].controller); + devices[i].deviceType = DEVICE_TYPE_NONE; + printf("Controller removed: device #%i (SDL instance ID=%i)\n", i, ev.jdevice.which); + break; + } + else if (devices[i].deviceType == DEVICE_TYPE_JOYSTICK && + devices[i].joystick == SDL_JoystickFromInstanceID(ev.jdevice.which)) + { + SDL_JoystickClose(devices[i].joystick); + devices[i].deviceType = DEVICE_TYPE_NONE; + printf("Joystick removed: device #%i (SDL instance ID=%i)\n", i, ev.jdevice.which); + } + } + break; + } + + case SDL_KEYDOWN: + { + if (remapDevice && remapDevice->deviceType == DEVICE_TYPE_KEYBOARD) + { + remapKeycode = ev.key.keysym.scancode; + } + +#if 0 // disable Alt+Enter fullscreen toggle for now because it causes problems under X11 + // Alt+Enter toggles fullscreen + if (ev.key.keysym.scancode == SDL_SCANCODE_RETURN && (SDL_GetModState() & KMOD_ALT) && !altEnterPressed) + { + fprintf(stderr, "Alt+Enter pressed, repeat=%i\n", ev.key.repeat); + video_fullscreen_flip(); + + /* Force the Enter key to unpressed in the SDL keyboard state so it won't be read by the + is_key_pressed() function if it's mapped to something in-game. */ + //((Uint8*)SDL_GetKeyboardState(NULL))[SDL_SCANCODE_RETURN] = 0; + altEnterPressed = true; + } +#endif + break; + } + +#if 0 // disable Alt+Enter fullscreen toggle for now because it causes problems under X11 + case SDL_KEYUP: + { + if (ev.key.keysym.scancode == SDL_SCANCODE_RETURN) + { + altEnterPressed = false; + } + break; + } +#endif + + case SDL_CONTROLLERBUTTONDOWN: + { + if (remapDevice && + remapDevice->deviceType == DEVICE_TYPE_CONTROLLER && + SDL_GameControllerFromInstanceID(ev.cbutton.which) == remapDevice->controller) + { + remapKeycode = ev.cbutton.button; + } + break; + } + case SDL_CONTROLLERAXISMOTION: + { + if (remapDevice && + remapDevice->deviceType == DEVICE_TYPE_CONTROLLER && + SDL_GameControllerFromInstanceID(ev.caxis.which) == remapDevice->controller) + { + if (ev.caxis.value > AXIS_THRESHOLD) + { + switch (ev.caxis.axis) + { + case SDL_CONTROLLER_AXIS_LEFTX: + case SDL_CONTROLLER_AXIS_LEFTY: + case SDL_CONTROLLER_AXIS_RIGHTX: + case SDL_CONTROLLER_AXIS_RIGHTY: + remapKeycode = SDL_CONTROLLER_BUTTON_MAX + (ev.caxis.axis * 2) + 1; + break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + remapKeycode = SDL_CONTROLLER_BUTTON_MAX + 8; + break; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + remapKeycode = SDL_CONTROLLER_BUTTON_MAX + 9; + break; + } + } + else if (ev.caxis.value < -AXIS_THRESHOLD) + { + // the triggers can't have negative values, so we don't need to handle them here + remapKeycode = SDL_CONTROLLER_BUTTON_MAX + (ev.caxis.axis * 2); + } + break; + } + break; + } + case SDL_JOYBUTTONDOWN: + { + if (remapDevice && + remapDevice->deviceType == DEVICE_TYPE_JOYSTICK && + remapDevice->joystick && + SDL_JoystickFromInstanceID(ev.jbutton.which) == remapDevice->joystick) + { + remapKeycode = ev.jbutton.button; + } + break; + } + case SDL_JOYHATMOTION: + { + if (remapDevice && + remapDevice->deviceType == DEVICE_TYPE_JOYSTICK && + remapDevice->joystick && + SDL_JoystickFromInstanceID(ev.jhat.which) == remapDevice->joystick) + { + // do nothing if the d-pad is pressed diagonally; wait for a cardinal direction + unsigned int base = SDL_JoystickNumButtons(remapDevice->joystick) + (4 * ev.jhat.hat); + switch (ev.jhat.value) + { + case SDL_HAT_UP: + remapKeycode = base; + break; + case SDL_HAT_DOWN: + remapKeycode = base + 1; + break; + case SDL_HAT_LEFT: + remapKeycode = base + 2; + break; + case SDL_HAT_RIGHT: + remapKeycode = base + 3; + break; + } + } + break; + } + case SDL_JOYAXISMOTION: + { + if (remapDevice && + remapDevice->deviceType == DEVICE_TYPE_JOYSTICK && + remapDevice->joystick && + SDL_JoystickFromInstanceID(ev.jaxis.which) == remapDevice->joystick) + { + if (ev.jaxis.value < -AXIS_THRESHOLD || ev.jaxis.value > AXIS_THRESHOLD) + { + remapKeycode = SDL_JoystickNumButtons(remapDevice->joystick) + + 4 * SDL_JoystickNumHats(remapDevice->joystick) + + 2 * ev.jaxis.axis + ((ev.jaxis.value < -AXIS_THRESHOLD) ? 0 : 1); + } + } + break; + } - // print JOY_MAX_INPUTS (64) spaces for alignment - if(numjoy == 1) +#ifdef ANDROID + case SDL_FINGERDOWN: { - printf("%s (%s) - %d axes, %d buttons, %d hat(s), rumble support: %s\n", - get_joystick_name(joysticks[joy_idx].Name), SDL_JoystickName(i), joysticks[joy_idx].NumAxes, joysticks[joy_idx].NumButtons, joysticks[joy_idx].NumHats, rumble_support); + for (int i = 0; i < MAX_POINTERS; i++) + { + if (touch_info.pstatus[i] == TOUCH_STATUS_UP) + { + touch_info.pid[i] = ev.tfinger.fingerId; + touch_info.px[i] = ev.tfinger.x * nativeWidth; + touch_info.py[i] = ev.tfinger.y * nativeHeight; + touch_info.pstatus[i] = TOUCH_STATUS_DOWN; + break; + } + } + control_update_android_touch(&touch_info, MAX_POINTERS); + break; } - else if(numjoy > 1) + + case SDL_FINGERUP: { - if(joy_idx) printf("\n"); - printf("%d. %s (%s) - %d axes, %d buttons, %d hat(s), rumble support: %s\n", i + 1, - get_joystick_name(joysticks[joy_idx].Name), SDL_JoystickName(i), joysticks[joy_idx].NumAxes, joysticks[joy_idx].NumButtons, joysticks[joy_idx].NumHats, rumble_support); + for (int i = 0; i < MAX_POINTERS; i++) + { + if (touch_info.pid[i] == ev.tfinger.fingerId) + { + touch_info.pstatus[i] = TOUCH_STATUS_UP; + break; + } + } + control_update_android_touch(&touch_info, MAX_POINTERS); + break; } + + case SDL_FINGERMOTION: + { + for (int i = 0; i < MAX_POINTERS; i++) + { + if (touch_info.pid[i] == ev.tfinger.fingerId) + { + touch_info.px[i] = ev.tfinger.x * nativeWidth; + touch_info.py[i] = ev.tfinger.y * nativeHeight; + touch_info.pstatus[i] = TOUCH_STATUS_DOWN; + break; + } + } + control_update_android_touch(&touch_info, MAX_POINTERS); + break; + } +#endif } - } + } } -/* -Open a single joystick -*/ -void open_joystick(int i) +// Returns 1 if key is pressed, 0 if not +static unsigned int is_key_pressed(InputDevice *device, int keycode) { - int j; + if (device->deviceType == DEVICE_TYPE_KEYBOARD) + { + // If Enter was pressed as part of an Alt+Enter to toggle fullscreen, don't count it as an in-game button press. + if (keycode == SDL_SCANCODE_RETURN && altEnterPressed) + { + return 0; + } - if ( ( joystick[i] = SDL_JoystickOpen(i) ) == NULL ) + return SDL_GetKeyboardState(NULL)[keycode]; + } + else if (device->deviceType == DEVICE_TYPE_CONTROLLER) { - printf("\nWarning: Unable to initialize joystick in port: %d! SDL Error: %s\n", i, SDL_GetError()); - return; + SDL_GameController *controller = device->controller; + if (keycode < SDL_CONTROLLER_BUTTON_MAX) + { + return SDL_GameControllerGetButton(controller, keycode); + } + else + { + int axisCode = keycode - SDL_CONTROLLER_BUTTON_MAX; + switch (axisCode) + { + case 0: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) < -AXIS_THRESHOLD); + case 1: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) > AXIS_THRESHOLD); + case 2: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) < -AXIS_THRESHOLD); + case 3: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) > AXIS_THRESHOLD); + case 4: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) < -AXIS_THRESHOLD); + case 5: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) > AXIS_THRESHOLD); + case 6: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) < -AXIS_THRESHOLD); + case 7: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) > AXIS_THRESHOLD); + case 8: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > AXIS_THRESHOLD); + case 9: return (SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > AXIS_THRESHOLD); + } + return 0; + } } - joysticks[i].NumHats = SDL_JoystickNumHats(joystick[i]); - joysticks[i].NumAxes = SDL_JoystickNumAxes(joystick[i]); - joysticks[i].NumButtons = SDL_JoystickNumButtons(joystick[i]); + else if (device->deviceType == DEVICE_TYPE_JOYSTICK) + { + SDL_Joystick *joystick = device->joystick; + if (keycode < SDL_JoystickNumButtons(joystick)) + { + return SDL_JoystickGetButton(joystick, keycode); + } - strcpy(joysticks[i].Name, SDL_JoystickName(i)); + keycode -= SDL_JoystickNumButtons(joystick); + if (keycode < 4 * SDL_JoystickNumHats(joystick)) + { + const int hatMasks[] = {SDL_HAT_UP, SDL_HAT_DOWN, SDL_HAT_LEFT, SDL_HAT_RIGHT}; + return !!(SDL_JoystickGetHat(joystick, keycode / 4) & hatMasks[keycode % 4]); + } - joystick_haptic[i] = SDL_HapticOpenFromJoystick(joystick[i]); - if (joystick_haptic[i] != NULL) - { - //Get initialize rumble - if( SDL_HapticRumbleInit( joystick_haptic[i] ) < 0 ) + keycode -= 4 * SDL_JoystickNumHats(joystick); + if (keycode < 2 * SDL_JoystickNumAxes(joystick)) { - printf("\nWarning: Unable to initialize rumble for joystick: %s in port: %d! SDL Error: %s\n", joysticks[i].Name, i, SDL_GetError()); + Sint16 axisPosition = SDL_JoystickGetAxis(joystick, keycode / 2); + if (keycode & 1) + { + return (axisPosition > AXIS_THRESHOLD); + } + else + { + return (axisPosition < -AXIS_THRESHOLD); + } } } - #if GP2X - joysticks[i].Type = JOY_TYPE_GAMEPARK; - for(j = 0; j < JOY_MAX_INPUTS + 1; j++) - { - if(j) joysticks[i].KeyName[j] = GameparkKeyName[j + i * JOY_MAX_INPUTS]; - else joysticks[i].KeyName[j] = GameparkKeyName[j]; - } - #else - //SDL_JoystickEventState(SDL_IGNORE); // disable joystick events - for(j = 1; j < JOY_MAX_INPUTS + 1; j++) + return 0; +} + +void control_update_player(s_playercontrols *playerControls) +{ + uint32_t keyflags = 0; + InputDevice *device = &devices[playerControls->deviceID]; + + for (unsigned int i = 0; i < SDID_COUNT; i++) { - strcpy(joysticks[i].KeyName[j], PC_GetJoystickKeyName(i, j)); + keyflags |= (is_key_pressed(device, device->mappings[i]) << i); } - #endif - return; + playerControls->newkeyflags = keyflags & (~playerControls->keyflags); + playerControls->keyflags = keyflags; } -void reset_joystick_map(int i) +void control_update(s_playercontrols **playerControls, int numPlayers) { - memset(joysticks[i].Name,0,sizeof(joysticks[i].Name)); - memset(joysticks[i].KeyName,0,sizeof(joysticks[i].KeyName)); - joysticks[i].Type = 0; - joysticks[i].NumHats = 0; - joysticks[i].NumAxes = 0; - joysticks[i].NumButtons = 0; - joysticks[i].Hats = 0; - joysticks[i].Axes = 0; - joysticks[i].Buttons = 0; - joysticks[i].Data = 0; - set_default_joystick_keynames(i); + handle_events(); + + for (int i = 0; i < numPlayers; i++) + { + control_update_player(playerControls[i]); + } } -/* -Reset All data back to Zero and -destroy all SDL Joystick data. -*/ -void control_exit() +void control_remapdevice(int deviceID) { - int i; - for(i = 0; i < numjoy; i++) + if (deviceID < 0) + { + // done remapping; reset globals to default values + remapDevice = NULL; + remapKeycode = -1; + } + else { - close_joystick(i); - } - usejoy = 0; + assert(devices[deviceID].deviceType != DEVICE_TYPE_NONE); + remapDevice = &devices[deviceID]; + remapKeycode = -1; + } } -/* -Reset single joystick -*/ -void close_joystick(int i) +int control_getremappedkey() { - if(joystick[i] != NULL) SDL_JoystickClose(joystick[i]); - if(joystick_haptic[i] != NULL) SDL_HapticClose(joystick_haptic[i]); - joystick[i] = NULL; - joystick_haptic[i] = NULL; - reset_joystick_map(i); + return remapKeycode; } -/* -Create default values for joysticks if enabled. -Then scan for joysticks and update their data. -*/ -void control_init(int joy_enable) +int *control_getmappings(int deviceID) { - int i; - -#ifdef GP2X - usejoy = joy_enable ? joy_enable : 1; -#else - usejoy = joy_enable; -#endif + return devices[deviceID].mappings; +} - //memset(joysticks, 0, sizeof(s_joysticks) * JOY_LIST_TOTAL); - for(i = 0; i < JOY_LIST_TOTAL; i++) - { - joystick[i] = NULL; - joystick_haptic[i] = NULL; - reset_joystick_map(i); - } - joystick_scan(usejoy); +const char *control_getkeyname(int deviceID, int keycode) +{ + if (deviceID < 0) return "None"; -#ifdef ANDROID - for(i = 0; i < MAX_POINTERS; i++) + if (devices[deviceID].deviceType == DEVICE_TYPE_KEYBOARD) { - touch_info.pstatus[i] = TOUCH_STATUS_UP; + return SDL_GetKeyName(SDL_GetKeyFromScancode(keycode)); } -#endif -} - -void set_default_joystick_keynames(int i) -{ - int j; - for(j = 0; j < JOY_MAX_INPUTS + 1; j++) + else if (devices[deviceID].deviceType == DEVICE_TYPE_CONTROLLER) + { + // These are more readable than the button names we get from SDL + const char *buttonNames[] = { + "A", + "B", + "X", + "Y", + "Back", + "Guide", + "Start", + "Left Stick Button", + "Right Stick Button", + "LB", + "RB", + "D-Pad Up", + "D-Pad Down", + "D-Pad Left", + "D-Pad Right", + "Left Stick Left", + "Left Stick Right", + "Left Stick Up", + "Left Stick Down", + "Right Stick Left", + "Right Stick Right", + "Right Stick Up", + "Right Stick Down", + "LT", + "RT" + }; + + if (keycode < sizeof(buttonNames) / sizeof(buttonNames[0])) + { + return buttonNames[keycode]; + } + } + else if (devices[deviceID].deviceType == DEVICE_TYPE_JOYSTICK) { - if(j) strcpy(joysticks[i].KeyName[j], "DISCONNECTED"); //Kratus (20-04-21) rename all keys when disconnected - // if(j) strcpy(joysticks[i].KeyName[j], JoystickKeyName[j + i * JOY_MAX_INPUTS]); - // else strcpy(joysticks[i].KeyName[j], JoystickKeyName[j]); + static char buttonName[64]; + SDL_Joystick *joystick = devices[deviceID].joystick; + if (keycode < SDL_JoystickNumButtons(joystick)) + { + snprintf(buttonName, sizeof(buttonName), "Button %u", keycode + 1); + return buttonName; + } + + keycode -= SDL_JoystickNumButtons(joystick); + if (keycode < 4 * SDL_JoystickNumHats(joystick)) + { + // omit the hat number because no real device is going to have more than one d-pad + const char *directions[] = {"Up", "Down", "Left", "Right"}; + snprintf(buttonName, sizeof(buttonName), "D-Pad %s", directions[keycode % 4]); + return buttonName; + } + + keycode -= 4 * SDL_JoystickNumHats(joystick); + if (keycode < 2 * SDL_JoystickNumAxes(joystick)) + { + snprintf(buttonName, sizeof(buttonName), "Axis %i %c", (keycode / 2) + 1, (keycode & 1) ? '+' : '-'); + return buttonName; + } } + + return "None"; } -char *control_getkeyname(unsigned int keycode) +bool control_isvaliddevice(int deviceID) { - int i; - for(i = 0; i < JOY_LIST_TOTAL; i++) - { - if((keycode >= (JOY_LIST_FIRST + 1 + (i * JOY_MAX_INPUTS))) && (keycode <= JOY_LIST_FIRST + JOY_MAX_INPUTS + (i * JOY_MAX_INPUTS))) - return (char*)joysticks[i].KeyName[keycode - (JOY_LIST_FIRST + (i * JOY_MAX_INPUTS))]; - } - - if(keycode > SDLK_FIRST && keycode < SDLK_LAST) - return JOY_GetKeyName(keycode); - else - if(keycode == CONTROL_NONE) //Kratus (20-04-21) value used to clear all keys - return "NONE"; - else - return "..."; + return deviceID >= 0 && devices[deviceID].deviceType != DEVICE_TYPE_NONE; } -/* -Set global variable, which is used for -enabling and disabling all joysticks. -*/ -int control_usejoy(int enable) +const char *control_getdevicename(int deviceID) { - usejoy = enable; - return 0; + return devices[deviceID].deviceType == DEVICE_TYPE_NONE ? "None" : devices[deviceID].name; } -#if ANDROID -/* -Get if touchscreen vibration is active -*/ -int is_touchpad_vibration_enabled() +void control_rumble(int deviceID, int ratio, int msec) { - return savedata.is_touchpad_vibration_enabled; + if (msec > 0 && devices[deviceID].haptic) + { + if (SDL_HapticRumblePlay(devices[deviceID].haptic, ratio, msec) != 0) + { + printf("Warning: Unable to play rumble! %s\n", SDL_GetError()); + } + } } -#endif +#ifdef ANDROID /* -Only used in openbor.c to get current status -of joystick usage. +Get if touchscreen vibration is active */ -int control_getjoyenabled() -{ - return usejoy; -} - - -void control_setkey(s_playercontrols * pcontrols, unsigned int flag, int key) +bool is_touchpad_vibration_enabled() { - if(!pcontrols) return; - pcontrols->settings[flag_to_index(flag)] = key; - pcontrols->keyflags = pcontrols->newkeyflags = 0; + return !!(savedata.is_touchpad_vibration_enabled); } -#if ANDROID /* Android touch logic, the rest of the code is in android/jni/video.c, maybe they'll be merged someday. @@ -620,171 +885,202 @@ extern float by[MAXTOUCHB]; extern float br[MAXTOUCHB]; extern unsigned touchstates[MAXTOUCHB]; int hide_t = 5000; -void control_update_android_touch(TouchStatus *touch_info, int maxp, Uint8* keystate, Uint8* keystate_def) + +static void control_update_android_touch(TouchStatus *touch_info, int maxp) { - int i, j; - float tx, ty, tr; - float r[MAXTOUCHB]; - float dirx, diry, circlea, circleb, tan; + #define pc(x) devices[keyboardDeviceID].mappings[x] + int i, j; + float tx, ty, tr; + float r[MAXTOUCHB]; + float dirx, diry, circlea, circleb, tan; + Uint8* keystate = (Uint8*) SDL_GetKeyboardState(NULL); + SDL_Event event; - memset(touchstates, 0, sizeof(touchstates)); + memset(touchstates, 0, sizeof(touchstates)); - for(j=0; jpstatus[i] == TOUCH_STATUS_UP) continue; - tx = touch_info->px[i]-dirx; - ty = touch_info->py[i]-diry; - tr = tx*tx + ty*ty; - //direction button logic is different, check a ring instead of individual buttons - if(tr>circlea && tr<=circleb) - { - if(tx<0) - { - tan = ty/tx; - if(tan>=-tana && tan<=tana) + for(j=0; jpstatus[i] == TOUCH_STATUS_UP) continue; + + event.type = SDL_KEYDOWN; + event.key.type = SDL_KEYDOWN; + event.key.timestamp = SDL_GetTicks(); + event.key.state = SDL_PRESSED; + event.key.repeat = 0; + + tx = touch_info->px[i]-dirx; + ty = touch_info->py[i]-diry; + tr = tx*tx + ty*ty; + + //direction button logic is different, check a ring instead of individual buttons + if(tr>circlea && tr<=circleb) + { + if(tx<0) + { + tan = ty/tx; + if(tan>=-tana && tan<=tana) { - touchstates[SDID_MOVELEFT] = 1; - } - else if(tan<-tanb) + touchstates[SDID_MOVELEFT] = 1; + event.key.keysym.scancode = pc(SDID_MOVELEFT); + SDL_PushEvent(&event); + } + else if(tan<-tanb) { - touchstates[SDID_MOVEDOWN] = 1; - } - else if(tan>tanb) - { - touchstates[SDID_MOVEUP] = 1; - } - else if(ty<0) - { - touchstates[SDID_MOVEUP] = touchstates[SDID_MOVELEFT] = 1; - } - else - { - touchstates[SDID_MOVELEFT] = touchstates[SDID_MOVEDOWN] = 1; + touchstates[SDID_MOVEDOWN] = 1; + event.key.keysym.scancode = pc(SDID_MOVEDOWN); + SDL_PushEvent(&event); } - } - else if(tx>0) - { - tan = ty/tx; - if(tan>=-tana && tan<=tana) + else if(tan>tanb) { - touchstates[SDID_MOVERIGHT] = 1; - } - else if(tan<-tanb) - { - touchstates[SDID_MOVEUP] = 1; - } - else if(tan>tanb) + touchstates[SDID_MOVEUP] = 1; + event.key.keysym.scancode = pc(SDID_MOVEUP); + SDL_PushEvent(&event); + } + else if(ty<0) { - touchstates[SDID_MOVEDOWN] = 1; - } - else if(ty<0) + touchstates[SDID_MOVEUP] = touchstates[SDID_MOVELEFT] = 1; + event.key.keysym.scancode = pc(SDID_MOVEUP); + SDL_PushEvent(&event); + event.key.keysym.scancode = pc(SDID_MOVELEFT); + SDL_PushEvent(&event); + } + else { - touchstates[SDID_MOVEUP] = touchstates[SDID_MOVERIGHT] = 1; - } - else + touchstates[SDID_MOVELEFT] = touchstates[SDID_MOVEDOWN] = 1; + event.key.keysym.scancode = pc(SDID_MOVELEFT); + SDL_PushEvent(&event); + event.key.keysym.scancode = pc(SDID_MOVEDOWN); + SDL_PushEvent(&event); + } + } + else if(tx>0) + { + tan = ty/tx; + if(tan>=-tana && tan<=tana) + { + touchstates[SDID_MOVERIGHT] = 1; + event.key.keysym.scancode = pc(SDID_MOVERIGHT); + SDL_PushEvent(&event); + } + else if(tan<-tanb) + { + touchstates[SDID_MOVEUP] = 1; + event.key.keysym.scancode = pc(SDID_MOVEUP); + SDL_PushEvent(&event); + } + else if(tan>tanb) + { + touchstates[SDID_MOVEDOWN] = 1; + event.key.keysym.scancode = pc(SDID_MOVEDOWN); + SDL_PushEvent(&event); + } + else if(ty<0) + { + touchstates[SDID_MOVEUP] = touchstates[SDID_MOVERIGHT] = 1; + event.key.keysym.scancode = pc(SDID_MOVEUP); + SDL_PushEvent(&event); + event.key.keysym.scancode = pc(SDID_MOVERIGHT); + SDL_PushEvent(&event); + } + else { - touchstates[SDID_MOVERIGHT] = touchstates[SDID_MOVEDOWN] = 1; + touchstates[SDID_MOVERIGHT] = touchstates[SDID_MOVEDOWN] = 1; + event.key.keysym.scancode = pc(SDID_MOVERIGHT); + SDL_PushEvent(&event); + event.key.keysym.scancode = pc(SDID_MOVEDOWN); + SDL_PushEvent(&event); } - } - else - { - if(ty>0) - { + } + else + { + if(ty>0) + { touchstates[SDID_MOVEDOWN] = 1; - } - else - { - touchstates[SDID_MOVEUP] = 1; + event.key.keysym.scancode = pc(SDID_MOVEDOWN); + SDL_PushEvent(&event); + } + else + { + touchstates[SDID_MOVEUP] = 1; + event.key.keysym.scancode = pc(SDID_MOVEUP); + SDL_PushEvent(&event); } - } - } - //rest buttons - for(j=0; jpx[i]-bx[j]; - ty = touch_info->py[i]-by[j]; - tr = tx*tx + ty*ty; - if(tr<=r[j]) + } + } + + //rest of the buttons + for(j=0; jpx[i]-bx[j]; + ty = touch_info->py[i]-by[j]; + tr = tx*tx + ty*ty; + if(tr<=r[j]) { touchstates[j] = 1; + event.key.keysym.scancode = pc(j); + SDL_PushEvent(&event); } - } - } - #undef tana - #undef tanb - - hide_t = timer_gettick() + 5000; - - //map to current user settings - extern s_savedata savedata; - #define pc(x) savedata.keys[0][x] - keystate[pc(SDID_MOVEUP)] = touchstates[SDID_MOVEUP]; - keystate[pc(SDID_MOVEDOWN)] = touchstates[SDID_MOVEDOWN]; - keystate[pc(SDID_MOVELEFT)] = touchstates[SDID_MOVELEFT]; - keystate[pc(SDID_MOVERIGHT)] = touchstates[SDID_MOVERIGHT]; - keystate[pc(SDID_ATTACK)] = touchstates[SDID_ATTACK]; - keystate[pc(SDID_ATTACK2)] = touchstates[SDID_ATTACK2]; - keystate[pc(SDID_ATTACK3)] = touchstates[SDID_ATTACK3]; - keystate[pc(SDID_ATTACK4)] = touchstates[SDID_ATTACK4]; - keystate[pc(SDID_JUMP)] = touchstates[SDID_JUMP]; - keystate[pc(SDID_SPECIAL)] = touchstates[SDID_SPECIAL]; - keystate[pc(SDID_START)] = touchstates[SDID_START]; - keystate[pc(SDID_SCREENSHOT)] = touchstates[SDID_SCREENSHOT]; - #undef pc - - //use default value for touch key mapping - keystate_def[default_keys[SDID_MOVEUP]] = touchstates[SDID_MOVEUP]; - keystate_def[default_keys[SDID_MOVEDOWN]] = touchstates[SDID_MOVEDOWN]; - keystate_def[default_keys[SDID_MOVELEFT]] = touchstates[SDID_MOVELEFT]; - keystate_def[default_keys[SDID_MOVERIGHT]] = touchstates[SDID_MOVERIGHT]; - keystate_def[default_keys[SDID_ATTACK]] = touchstates[SDID_ATTACK]; - keystate_def[default_keys[SDID_ATTACK2]] = touchstates[SDID_ATTACK2]; - keystate_def[default_keys[SDID_ATTACK3]] = touchstates[SDID_ATTACK3]; - keystate_def[default_keys[SDID_ATTACK4]] = touchstates[SDID_ATTACK4]; - keystate_def[default_keys[SDID_JUMP]] = touchstates[SDID_JUMP]; - keystate_def[default_keys[SDID_SPECIAL]] = touchstates[SDID_SPECIAL]; - keystate_def[default_keys[SDID_START]] = touchstates[SDID_START]; - keystate_def[default_keys[SDID_SCREENSHOT]] = touchstates[SDID_SCREENSHOT]; - - keystate[CONTROL_ESC] = keystate_def[CONTROL_ESC] = touchstates[SDID_ESC]; - - return; + } + } + #undef tana + #undef tanb + + hide_t = timer_gettick() + 5000; + + //map to current user settings + assert(keyboardDeviceID >= 0); + keystate[pc(SDID_MOVEUP)] = touchstates[SDID_MOVEUP]; + keystate[pc(SDID_MOVEDOWN)] = touchstates[SDID_MOVEDOWN]; + keystate[pc(SDID_MOVELEFT)] = touchstates[SDID_MOVELEFT]; + keystate[pc(SDID_MOVERIGHT)] = touchstates[SDID_MOVERIGHT]; + keystate[pc(SDID_ATTACK)] = touchstates[SDID_ATTACK]; + keystate[pc(SDID_ATTACK2)] = touchstates[SDID_ATTACK2]; + keystate[pc(SDID_ATTACK3)] = touchstates[SDID_ATTACK3]; + keystate[pc(SDID_ATTACK4)] = touchstates[SDID_ATTACK4]; + keystate[pc(SDID_JUMP)] = touchstates[SDID_JUMP]; + keystate[pc(SDID_SPECIAL)] = touchstates[SDID_SPECIAL]; + keystate[pc(SDID_START)] = touchstates[SDID_START]; + keystate[pc(SDID_SCREENSHOT)] = touchstates[SDID_SCREENSHOT]; + keystate[pc(SDID_SCREENSHOT)] = touchstates[SDID_SCREENSHOT]; + keystate[pc(SDID_ESC)] = touchstates[SDID_ESC]; + + #undef pc } int is_touch_area(float x, float y) { - int j; - float tx, ty, tr; - float r[MAXTOUCHB]; - float dirx, diry, circlea, circleb, tan; + int j; + float tx, ty, tr; + float r[MAXTOUCHB]; + float dirx, diry, circlea, circleb, tan; - for(j=0; j0 = key code for pressed key -// <0 = error -int control_scankey() +bool control_loadmappings(const char *filename) { - static unsigned ready = 0; - unsigned k = 0, j = 0; - - k = keyboard_getlastkey(); - j = lastjoy; - lastjoy = 0; - -#if 0 - if(joysticks[0].Data) j = 1 + 0 * JOY_MAX_INPUTS + flag_to_index(joysticks[0].Data); - else if(joysticks[1].Data) j = 1 + 1 * JOY_MAX_INPUTS + flag_to_index(joysticks[1].Data); - else if(joysticks[2].Data) j = 1 + 2 * JOY_MAX_INPUTS + flag_to_index(joysticks[2].Data); - else if(joysticks[3].Data) j = 1 + 3 * JOY_MAX_INPUTS + flag_to_index(joysticks[3].Data); -#endif + FILE *fp = fopen(filename, "rb"); + if (!fp) + { + return false; + } - if(ready && (k || j)) - { - ready = 0; - if(k) return k; - if(j) return JOY_LIST_FIRST+j; - else return -1; - } - ready = (!k || !j); - return 0; -} + clear_saved_mappings(); -void control_update(s_playercontrols ** playercontrols, int numplayers) -{ - u64 k; - unsigned i; - int player; - int t; - s_playercontrols * pcontrols; - Uint8* keystate = (Uint8*)SDL_GetKeyState(NULL); // Here retrieve keyboard state - Uint8* keystate_def = (Uint8*)SDL_GetKeyState(NULL); // Here retrieve keyboard state for default + while (!feof(fp) && !ferror(fp)) + { + char name[CONTROL_DEVICE_NAME_SIZE]; + int *mapping = malloc(SDID_COUNT * sizeof(int)); + int sentinel; + if (fread(name, 1, sizeof(name), fp) != sizeof(name) || + fread(mapping, sizeof(int), SDID_COUNT, fp) != SDID_COUNT || + fread(&sentinel, sizeof(int), 1, fp) != 1) + { + free(mapping); + break; + } + else if (sentinel != MAPPINGS_FILE_SENTINEL) + { + free(mapping); + fclose(fp); + return false; + } - getPads(keystate,keystate_def); + name[sizeof(name)-1] = '\0'; // just in case + printf("Loaded mapping for %s\n", name); + List_InsertAfter(&savedMappings, mapping, name); + } - for(player = 0; player < numplayers; player++){ + fclose(fp); - pcontrols = playercontrols[player]; + // update all current device mappings with the newly loaded mappings + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType != DEVICE_TYPE_NONE) + { + load_from_saved_mapping(i); + } + } - k = 0; + return true; +} - for(i = 0; i < JOY_MAX_INPUTS; i++) - { - t = pcontrols->settings[i]; - if(t >= SDLK_FIRST && t < SDLK_LAST){ - if(keystate[t]) k |= (1<= SDLK_FIRST && t < SDLK_LAST){ - if(keystate_def[t]) k |= (1<settings[i]; - if(t >= JOY_LIST_FIRST && t <= JOY_LIST_LAST) - { - int portnum = (t-JOY_LIST_FIRST-1) / JOY_MAX_INPUTS; - int shiftby = (t-JOY_LIST_FIRST-1) % JOY_MAX_INPUTS; - if(portnum >= 0 && portnum <= JOY_LIST_TOTAL-1) - { - if((joysticks[portnum].Data >> shiftby) & 1) k |= (1<kb_break = 0; - pcontrols->newkeyflags = k & (~pcontrols->keyflags); - pcontrols->keyflags = k; - - //if (player <= 0) debug_printf("hats: %d, axes: %d, data: %d",joysticks[0].Hats,joysticks[0].Axes,joysticks[0].Data); - } + List_GotoNext(&savedMappings); + } + + fclose(fp); + return true; } -void control_rumble(int port, int ratio, int msec) +void control_clearmappings() { - #if SDL - if (joystick[port] != NULL && joystick_haptic[port] != NULL) { - if(SDL_HapticRumblePlay(joystick_haptic[port], ratio, msec) != 0) + clear_saved_mappings(); + + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType != DEVICE_TYPE_NONE) { - //printf( "Warning: Unable to play rumble! %s\n", SDL_GetError() ); + control_resetmappings(i); } } - #endif } diff --git a/engine/sdl/control.h b/engine/sdl/control.h index a2686c6fc..9e18f141e 100644 --- a/engine/sdl/control.h +++ b/engine/sdl/control.h @@ -3,183 +3,60 @@ * ----------------------------------------------------------------------- * All rights reserved, see LICENSE in OpenBOR root for details. * - * Copyright (c) 2004 - 2014 OpenBOR Team + * Copyright (c) 2004 - 2019 OpenBOR Team */ #ifndef CONTROL_H #define CONTROL_H - // Generic control stuff (keyboard+joystick). -#if ANDROID || DARWIN || SDL2 -#include "SDL_keycode.h" -#else -#include -#endif -#include "joysticks.h" - -#ifdef OPENDINGUX - #define CONTROL_ESC OPENDINGUX_BUTTON_SELECT - #define CONTROL_DEFAULT1_START OPENDINGUX_BUTTON_START - #define CONTROL_DEFAULT1_UP OPENDINGUX_BUTTON_UP - #define CONTROL_DEFAULT1_DOWN OPENDINGUX_BUTTON_DOWN - #define CONTROL_DEFAULT1_LEFT OPENDINGUX_BUTTON_LEFT - #define CONTROL_DEFAULT1_RIGHT OPENDINGUX_BUTTON_RIGHT - #define CONTROL_DEFAULT1_FIRE1 OPENDINGUX_BUTTON_A - #define CONTROL_DEFAULT1_FIRE2 OPENDINGUX_BUTTON_Y - #define CONTROL_DEFAULT1_FIRE3 OPENDINGUX_BUTTON_R - #define CONTROL_DEFAULT1_FIRE4 OPENDINGUX_BUTTON_L - #define CONTROL_DEFAULT1_FIRE5 OPENDINGUX_BUTTON_B - #define CONTROL_DEFAULT1_FIRE6 OPENDINGUX_BUTTON_X - #define CONTROL_DEFAULT1_SCREENSHOT SDLK_F12 - #define CONTROL_DEFAULT1_ESC OPENDINGUX_BUTTON_SELECT -#elif GP2X - #define CONTROL_ESC (JOY_LIST_FIRST + 15) - #define CONTROL_DEFAULT1_UP (JOY_LIST_FIRST + 1) - #define CONTROL_DEFAULT1_RIGHT (JOY_LIST_FIRST + 2) - #define CONTROL_DEFAULT1_DOWN (JOY_LIST_FIRST + 3) - #define CONTROL_DEFAULT1_LEFT (JOY_LIST_FIRST + 4) - #define CONTROL_DEFAULT1_FIRE1 (JOY_LIST_FIRST + 5) - #define CONTROL_DEFAULT1_FIRE2 (JOY_LIST_FIRST + 6) - #define CONTROL_DEFAULT1_FIRE3 (JOY_LIST_FIRST + 7) - #define CONTROL_DEFAULT1_FIRE4 (JOY_LIST_FIRST + 8) - #define CONTROL_DEFAULT1_FIRE5 (JOY_LIST_FIRST + 9) - #define CONTROL_DEFAULT1_FIRE6 (JOY_LIST_FIRST + 10) - #define CONTROL_DEFAULT1_START (JOY_LIST_FIRST + 11) - #define CONTROL_DEFAULT1_SCREENSHOT (JOY_LIST_FIRST + 12) - #define CONTROL_DEFAULT1_ESC (JOY_LIST_FIRST + 15) -#else -#ifdef SDL2 - #define CONTROL_ESC SDL_SCANCODE_ESCAPE - #define CONTROL_DEFAULT1_START SDL_SCANCODE_RETURN - #define CONTROL_DEFAULT1_UP SDL_SCANCODE_UP - #define CONTROL_DEFAULT1_DOWN SDL_SCANCODE_DOWN - #define CONTROL_DEFAULT1_LEFT SDL_SCANCODE_LEFT - #define CONTROL_DEFAULT1_RIGHT SDL_SCANCODE_RIGHT - #define CONTROL_DEFAULT1_FIRE1 SDL_SCANCODE_A - #define CONTROL_DEFAULT1_FIRE2 SDL_SCANCODE_S - #define CONTROL_DEFAULT1_FIRE3 SDL_SCANCODE_Z - #define CONTROL_DEFAULT1_FIRE4 SDL_SCANCODE_X - #define CONTROL_DEFAULT1_FIRE5 SDL_SCANCODE_D - #define CONTROL_DEFAULT1_FIRE6 SDL_SCANCODE_F - #define CONTROL_DEFAULT1_SCREENSHOT SDL_SCANCODE_F12 - #define CONTROL_DEFAULT1_ESC SDL_SCANCODE_ESCAPE -#else - #define CONTROL_ESC SDLK_ESCAPE - #define CONTROL_DEFAULT1_START SDLK_RETURN - #define CONTROL_DEFAULT1_UP SDLK_UP - #define CONTROL_DEFAULT1_DOWN SDLK_DOWN - #define CONTROL_DEFAULT1_LEFT SDLK_LEFT - #define CONTROL_DEFAULT1_RIGHT SDLK_RIGHT - #define CONTROL_DEFAULT1_FIRE1 SDLK_a - #define CONTROL_DEFAULT1_FIRE2 SDLK_s - #define CONTROL_DEFAULT1_FIRE3 SDLK_z - #define CONTROL_DEFAULT1_FIRE4 SDLK_x - #define CONTROL_DEFAULT1_FIRE5 SDLK_d - #define CONTROL_DEFAULT1_FIRE6 SDLK_f - #define CONTROL_DEFAULT1_SCREENSHOT SDLK_F12 - #define CONTROL_DEFAULT1_ESC SDLK_ESCAPE -#endif -#endif - -#define CONTROL_DEFAULT2_UP ((JOY_LIST_FIRST + 1) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_RIGHT ((JOY_LIST_FIRST + 2) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_DOWN ((JOY_LIST_FIRST + 3) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_LEFT ((JOY_LIST_FIRST + 4) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_FIRE1 ((JOY_LIST_FIRST + 5) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_FIRE2 ((JOY_LIST_FIRST + 6) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_FIRE3 ((JOY_LIST_FIRST + 7) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_FIRE4 ((JOY_LIST_FIRST + 8) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_FIRE5 ((JOY_LIST_FIRST + 9) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_FIRE6 ((JOY_LIST_FIRST + 10) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_START ((JOY_LIST_FIRST + 11) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_SCREENSHOT ((JOY_LIST_FIRST + 12) + JOY_MAX_INPUTS) -#define CONTROL_DEFAULT2_ESC ((JOY_LIST_FIRST + 15) + JOY_MAX_INPUTS) - -#define CONTROL_DEFAULT3_UP ((JOY_LIST_FIRST + 1) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_RIGHT ((JOY_LIST_FIRST + 2) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_DOWN ((JOY_LIST_FIRST + 3) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_LEFT ((JOY_LIST_FIRST + 4) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_FIRE1 ((JOY_LIST_FIRST + 5) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_FIRE2 ((JOY_LIST_FIRST + 6) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_FIRE3 ((JOY_LIST_FIRST + 7) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_FIRE4 ((JOY_LIST_FIRST + 8) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_FIRE5 ((JOY_LIST_FIRST + 9) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_FIRE6 ((JOY_LIST_FIRST + 10) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_START ((JOY_LIST_FIRST + 11) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_SCREENSHOT ((JOY_LIST_FIRST + 12) + (JOY_MAX_INPUTS * 2)) -#define CONTROL_DEFAULT3_ESC ((JOY_LIST_FIRST + 15) + (JOY_MAX_INPUTS * 2)) - -#define CONTROL_DEFAULT4_UP ((JOY_LIST_FIRST + 1) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_RIGHT ((JOY_LIST_FIRST + 2) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_DOWN ((JOY_LIST_FIRST + 3) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_LEFT ((JOY_LIST_FIRST + 4) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_FIRE1 ((JOY_LIST_FIRST + 5) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_FIRE2 ((JOY_LIST_FIRST + 6) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_FIRE3 ((JOY_LIST_FIRST + 7) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_FIRE4 ((JOY_LIST_FIRST + 8) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_FIRE5 ((JOY_LIST_FIRST + 9) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_FIRE6 ((JOY_LIST_FIRST + 10) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_START ((JOY_LIST_FIRST + 11) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_SCREENSHOT ((JOY_LIST_FIRST + 12) + (JOY_MAX_INPUTS * 3)) -#define CONTROL_DEFAULT4_ESC ((JOY_LIST_FIRST + 15) + (JOY_MAX_INPUTS * 3)) - -#define CONTROL_NONE ((JOY_LIST_FIRST + 1) + (JOY_MAX_INPUTS * 99)) //Kratus (20-04-21) value used to clear all keys - -#define JOYBUTTON(index, btn) (1 + i * JOY_MAX_INPUTS + btn) -#define JOYAXIS(index, axis, dir) (JOYBUTTON(index, joysticks[index].NumButtons) + 2 * axis + dir) - -#ifdef SDL2 -#define SDLK_FIRST SDL_SCANCODE_UNKNOWN -#define SDLK_LAST SDL_NUM_SCANCODES -#define SDL_GetKeyState SDL_GetKeyboardState -#define SDL_JoystickName(x) SDL_JoystickName(joystick[x]) -#endif - -typedef struct{ - int settings[JOY_MAX_INPUTS]; - u64 keyflags, newkeyflags; - int kb_break; -}s_playercontrols; - -void open_joystick(int i); -void close_joystick(int i); + +#include + +// 32 is an arbitrary number larger than the number of input devices that will ever be available +#define MAX_DEVICES 32 +#define CONTROL_DEVICE_NAME_SIZE 64 + +typedef struct { + int deviceID; + uint32_t keyflags; + uint32_t newkeyflags; +} s_playercontrols; + +void control_init(); void control_exit(); -void control_init(int joy_enable); -int control_usejoy(int enable); -int control_getjoyenabled(); -void control_setkey(s_playercontrols * pcontrols, unsigned int flag, int key); -int control_scankey(); +/* Listen to input from deviceID. The first input from deviceID will be returned by the next call to + control_getremappedkey(). Call with deviceID=-1 to finish remapping. */ +void control_remapdevice(int deviceID); -void set_default_joystick_keynames(int i); -void reset_joystick_map(int i); -char* get_joystick_name(const char* name); -char *control_getkeyname(unsigned int keycode); -void control_update(s_playercontrols ** playercontrols, int numplayers); -void control_rumble(int port, int ratio, int msec); -int keyboard_getlastkey(); +// Returns the keycode of the first key pressed on the device being remapped, or -1 if nothing has been pressed yet +int control_getremappedkey(); -#ifdef ANDROID -#define MAX_POINTERS 30 -typedef enum -{ - TOUCH_STATUS_UP, - TOUCH_STATUS_DOWN -} touch_status; - -typedef struct TouchStatus { - float px[MAX_POINTERS]; - float py[MAX_POINTERS]; - SDL_FingerID pid[MAX_POINTERS]; - touch_status pstatus[MAX_POINTERS]; -} TouchStatus; - -int is_touchpad_vibration_enabled(); -void control_update_android_touch(TouchStatus *touch_info, int maxp, Uint8* keystate, Uint8* keystate_def); -int is_touch_area(float x, float y); -#endif +// Returns an array of size SDID_COUNT +int *control_getmappings(int deviceID); +// Resets mappings for device to default +void control_resetmappings(int deviceID); +void control_update(s_playercontrols **allPlayerControls, int numPlayers); +void control_update_keyboard(s_playercontrols *keyboardControls); +const char *control_getkeyname(int deviceID, int keycode); +bool control_isvaliddevice(int deviceID); +const char *control_getdevicename(int deviceID); +void control_rumble(int deviceID, int ratio, int msec); +bool control_loadmappings(const char *filename); +bool control_savemappings(const char *filename); + +// clears saved mappings and resets every device's mappings to defaults +void control_clearmappings(); + + +#define control_getmappedkeyname(deviceID, key) control_getkeyname(deviceID, control_getmappings(deviceID)[key]) + +#ifdef ANDROID +bool is_touchpad_vibration_enabled(); +int is_touch_area(float x, float y); +#endif /* defined(ANDROID) */ -#endif +#endif /* defined(CONTROL_H) */ diff --git a/engine/sdl/joysticks.c b/engine/sdl/joysticks.c deleted file mode 100644 index 1556d2b2c..000000000 --- a/engine/sdl/joysticks.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * OpenBOR - http://www.chronocrash.com - * ----------------------------------------------------------------------- - * All rights reserved, see LICENSE in OpenBOR root for details. - * - * Copyright (c) 2004 - 2014 OpenBOR Team - */ - -#include "sdlport.h" -#include "joysticks.h" - -s_joysticks joysticks[JOY_LIST_TOTAL]; - -const char *JoystickKeyName[JOY_NAME_SIZE] = { - "...", - #define JOYSTICK_NAMES(x) \ - x" Up", \ - x" Right", \ - x" Down", \ - x" Left", \ - x" Button 1", \ - x" Button 2", \ - x" Button 3", \ - x" Button 4", \ - x" Button 5", \ - x" Button 6", \ - x" Button 7", \ - x" Button 8", \ - x" Button 9", \ - x" Button 10", \ - x" Button 11", \ - x" Button 12", \ - x" Button 13", \ - x" Button 14", \ - x" Button 15", \ - x" Button 16", \ - x" Button 17", \ - x" Button 18", \ - x" Button 19", \ - x" Button 20", \ - x" Button 21", \ - x" Button 22", \ - x" Button 23", \ - x" Button 24", \ - x" Button 25", \ - x" Button 26", \ - x" Button 27", \ - x" Button 28", \ - x" Button 29", \ - x" Button 30", \ - x" Button 31", \ - x" Button 32", \ - x" Button 33", \ - x" Button 34", \ - x" Button 35", \ - x" Button 36", \ - x" Button 37", \ - x" Button 38", \ - x" Button 39", \ - x" Button 40", \ - x" Button 41", \ - x" Button 42", \ - x" Button 43", \ - x" Button 44", \ - x" Button 45", \ - x" Button 46", \ - x" Button 47", \ - x" Button 48", \ - x" Button 49", \ - x" Button 50", \ - x" Button 51", \ - x" Button 52", \ - x" Button 53", \ - x" Button 54", \ - x" Button 55", \ - x" Button 56", \ - x" Button 57", \ - x" Button 58", \ - x" Button 59", \ - x" Button 60", - JOYSTICK_NAMES("P1") - JOYSTICK_NAMES("P2") - JOYSTICK_NAMES("P3") - JOYSTICK_NAMES("P4") - "undefined" -}; - -const char *GameparkKeyName[JOY_NAME_SIZE] = { - "...", -#define GAMEPARK_NAMES(x) \ - x" Up", \ - x" Right", \ - x" Down", \ - x" Left", \ - x" Start", \ - x" Select", \ - x" L-Trigger", \ - x" R-Trigger", \ - x" A", \ - x" B", \ - x" X", \ - x" Y", \ - x" Volume Up", \ - x" Volume Down", \ - x" Click", \ - x" unknown 16", \ - x" unknown 17", \ - x" unknown 18", \ - x" unknown 19", \ - x" unknown 20", \ - x" unknown 21", \ - x" unknown 22", \ - x" unknown 23", \ - x" unknown 24", \ - x" unknown 25", \ - x" unknown 26", \ - x" unknown 27", \ - x" unknown 28", \ - x" unknown 29", \ - x" unknown 30", \ - x" unknown 31", \ - x" unknown 32", \ - x" unknown 33", \ - x" unknown 34", \ - x" unknown 35", \ - x" unknown 36", \ - x" unknown 37", \ - x" unknown 38", \ - x" unknown 39", \ - x" unknown 40", \ - x" unknown 41", \ - x" unknown 42", \ - x" unknown 43", \ - x" unknown 44", \ - x" unknown 45", \ - x" unknown 46", \ - x" unknown 47", \ - x" unknown 48", \ - x" unknown 49", \ - x" unknown 50", \ - x" unknown 51", \ - x" unknown 52", \ - x" unknown 53", \ - x" unknown 54", \ - x" unknown 55", \ - x" unknown 56", \ - x" unknown 57", \ - x" unknown 58", \ - x" unknown 59", \ - x" unknown 60", - GAMEPARK_NAMES("P1") - GAMEPARK_NAMES("P2") - GAMEPARK_NAMES("P3") - GAMEPARK_NAMES("P4") - "undefined" -}; - -const u64 JoystickBits[JOY_MAX_INPUTS + 1] = { - 0x0000000000000000, // No Buttons Pressed - 0x0000000000000001, // Hat Up - 0x0000000000000002, // Hat Right - 0x0000000000000004, // Hat Down - 0x0000000000000008, // Hat Left - 0x0000000000000010, // Button 1 - 0x0000000000000020, // Button 2 - 0x0000000000000040, // Button 3 - 0x0000000000000080, // Button 4 - 0x0000000000000100, // Button 5 - 0x0000000000000200, // Button 6 - 0x0000000000000400, // Button 7 - 0x0000000000000800, // Button 8 - 0x0000000000001000, // Button 9 - 0x0000000000002000, // Button 10 - 0x0000000000004000, // Button 11 - 0x0000000000008000, // Button 12 - 0x0000000000010000, // Button 13 - 0x0000000000020000, // Button 14 - 0x0000000000040000, // Button 15 - 0x0000000000080000, // Button 16 - 0x0000000000100000, // Button 17 - 0x0000000000200000, // Button 18 - 0x0000000000400000, // Button 19 - 0x0000000000800000, // Button 20 - 0x0000000001000000, // Button 21 - 0x0000000002000000, // Button 22 - 0x0000000004000000, // Button 23 - 0x0000000008000000, // Button 24 - 0x0000000010000000, // Button 25 - 0x0000000020000000, // Button 26 - 0x0000000040000000, // Button 27 - 0x0000000080000000, // Button 28 - - 0x0000000100000000, - 0x0000000200000000, - 0x0000000400000000, - 0x0000000800000000, - 0x0000001000000000, - 0x0000002000000000, - 0x0000004000000000, - 0x0000008000000000, - 0x0000010000000000, - 0x0000020000000000, - 0x0000040000000000, - 0x0000080000000000, - 0x0000100000000000, - 0x0000200000000000, - 0x0000400000000000, - 0x0000800000000000, - 0x0001000000000000, - 0x0002000000000000, - 0x0004000000000000, - 0x0008000000000000, - 0x0010000000000000, - 0x0020000000000000, - 0x0040000000000000, - 0x0080000000000000, - 0x0100000000000000, - 0x0200000000000000, - 0x0400000000000000, - 0x0800000000000000, - 0x1000000000000000, - 0x2000000000000000, - 0x4000000000000000, - 0x8000000000000000 // Button 60 -}; - -const char* JoystickButtonNames[JOY_NAME_SIZE] = { - "...", -#define BUTTON_NAMES(x) \ - x" Button 1", \ - x" Button 2", \ - x" Button 3", \ - x" Button 4", \ - x" Button 5", \ - x" Button 6", \ - x" Button 7", \ - x" Button 8", \ - x" Button 9", \ - x" Button 10", \ - x" Button 11", \ - x" Button 12", \ - x" Button 13", \ - x" Button 14", \ - x" Button 15", \ - x" Button 16", \ - x" Button 17", \ - x" Button 18", \ - x" Button 19", \ - x" Button 20", \ - x" Button 21", \ - x" Button 22", \ - x" Button 23", \ - x" Button 24", \ - x" Button 25", \ - x" Button 26", \ - x" Button 27", \ - x" Button 28", \ - x" Button 29", \ - x" Button 30", \ - x" Button 31", \ - x" Button 32", \ - x" Button 33", \ - x" Button 34", \ - x" Button 35", \ - x" Button 36", \ - x" Button 37", \ - x" Button 38", \ - x" Button 39", \ - x" Button 40", \ - x" Button 41", \ - x" Button 42", \ - x" Button 43", \ - x" Button 44", \ - x" Button 45", \ - x" Button 46", \ - x" Button 47", \ - x" Button 48", \ - x" Button 49", \ - x" Button 50", \ - x" Button 51", \ - x" Button 52", \ - x" Button 53", \ - x" Button 54", \ - x" Button 55", \ - x" Button 56", \ - x" Button 57", \ - x" Button 58", \ - x" Button 59", \ - x" Button 60", \ - x" Button 61", \ - x" Button 62", \ - x" Button 63", \ - x" Button 64", - BUTTON_NAMES("P1") - BUTTON_NAMES("P2") - BUTTON_NAMES("P3") - BUTTON_NAMES("P4") -}; - -const char* JoystickAxisNames[JOY_NAME_SIZE] = { - "...", -#define AXIS_BUTTONS(x,n) \ - x" Axis "n" -", \ - x" Axis "n" +", -#define AXIS_NAMES(x) \ - AXIS_BUTTONS(x,"1") \ - AXIS_BUTTONS(x,"2") \ - AXIS_BUTTONS(x,"3") \ - AXIS_BUTTONS(x,"4") \ - AXIS_BUTTONS(x,"5") \ - AXIS_BUTTONS(x,"6") \ - AXIS_BUTTONS(x,"7") \ - AXIS_BUTTONS(x,"8") \ - AXIS_BUTTONS(x,"9") \ - AXIS_BUTTONS(x,"10") \ - AXIS_BUTTONS(x,"11") \ - AXIS_BUTTONS(x,"12") \ - AXIS_BUTTONS(x,"13") \ - AXIS_BUTTONS(x,"14") \ - AXIS_BUTTONS(x,"15") \ - AXIS_BUTTONS(x,"16") \ - AXIS_BUTTONS(x,"17") \ - AXIS_BUTTONS(x,"18") \ - AXIS_BUTTONS(x,"19") \ - AXIS_BUTTONS(x,"20") \ - AXIS_BUTTONS(x,"21") \ - AXIS_BUTTONS(x,"22") \ - AXIS_BUTTONS(x,"23") \ - AXIS_BUTTONS(x,"24") \ - AXIS_BUTTONS(x,"25") \ - AXIS_BUTTONS(x,"26") \ - AXIS_BUTTONS(x,"27") \ - AXIS_BUTTONS(x,"28") \ - AXIS_BUTTONS(x,"29") \ - AXIS_BUTTONS(x,"30") \ - AXIS_BUTTONS(x,"31") \ - AXIS_BUTTONS(x,"32") - AXIS_NAMES("P1") - AXIS_NAMES("P2") - AXIS_NAMES("P3") - AXIS_NAMES("P4") -}; - -const char* JoystickHatNames[JOY_NAME_SIZE] = { - "...", -#define HAT_BUTTONS(x,n) \ - x" Hat "n" Up", \ - x" Hat "n" Right", \ - x" Hat "n" Down", \ - x" Hat "n" Left", -#define HAT_NAMES(x) \ - HAT_BUTTONS(x,"1") \ - HAT_BUTTONS(x,"2") \ - HAT_BUTTONS(x,"3") \ - HAT_BUTTONS(x,"4") \ - HAT_BUTTONS(x,"5") \ - HAT_BUTTONS(x,"6") \ - HAT_BUTTONS(x,"7") \ - HAT_BUTTONS(x,"8") \ - HAT_BUTTONS(x,"9") \ - HAT_BUTTONS(x,"10") \ - HAT_BUTTONS(x,"11") \ - HAT_BUTTONS(x,"12") \ - HAT_BUTTONS(x,"13") \ - HAT_BUTTONS(x,"14") \ - HAT_BUTTONS(x,"15") \ - HAT_BUTTONS(x,"16") - HAT_NAMES("P1") - HAT_NAMES("P2") - HAT_NAMES("P3") - HAT_NAMES("P4") -}; - -const char* JoystickUnknownNames[JOY_NAME_SIZE] = { - "...", -#define UNKNOWN_NAMES(x) \ - x" unknown 1", \ - x" unknown 2", \ - x" unknown 3", \ - x" unknown 4", \ - x" unknown 5", \ - x" unknown 6", \ - x" unknown 7", \ - x" unknown 8", \ - x" unknown 9", \ - x" unknown 10", \ - x" unknown 11", \ - x" unknown 12", \ - x" unknown 13", \ - x" unknown 14", \ - x" unknown 15", \ - x" unknown 16", \ - x" unknown 17", \ - x" unknown 18", \ - x" unknown 19", \ - x" unknown 20", \ - x" unknown 21", \ - x" unknown 22", \ - x" unknown 23", \ - x" unknown 24", \ - x" unknown 25", \ - x" unknown 26", \ - x" unknown 27", \ - x" unknown 28", \ - x" unknown 29", \ - x" unknown 30", \ - x" unknown 31", \ - x" unknown 32", \ - x" unknown 33", \ - x" unknown 34", \ - x" unknown 35", \ - x" unknown 36", \ - x" unknown 37", \ - x" unknown 38", \ - x" unknown 39", \ - x" unknown 40", \ - x" unknown 41", \ - x" unknown 42", \ - x" unknown 43", \ - x" unknown 44", \ - x" unknown 45", \ - x" unknown 46", \ - x" unknown 47", \ - x" unknown 48", \ - x" unknown 49", \ - x" unknown 50", \ - x" unknown 51", \ - x" unknown 52", \ - x" unknown 53", \ - x" unknown 54", \ - x" unknown 55", \ - x" unknown 56", \ - x" unknown 57", \ - x" unknown 58", \ - x" unknown 59", \ - x" unknown 60", \ - x" unknown 61", \ - x" unknown 62", \ - x" unknown 63", \ - x" unknown 64", - UNKNOWN_NAMES("P1") - UNKNOWN_NAMES("P2") - UNKNOWN_NAMES("P3") - UNKNOWN_NAMES("P4") -}; - -// Numbering order: buttons, then axes, then hats -const char* PC_GetJoystickKeyName(int portnum, int keynum) -{ - int keycode = (portnum*JOY_MAX_INPUTS) + keynum; - int firstAxis = joysticks[portnum].NumButtons; - int firstHat = firstAxis + (2*joysticks[portnum].NumAxes); - int firstUnknown = firstHat + (4*joysticks[portnum].NumHats); - - if (keynum < firstAxis+1) return JoystickButtonNames[keycode]; - else if (keynum < firstHat+1) return JoystickAxisNames[keycode-firstAxis]; - else if (keynum < firstUnknown+1) return JoystickHatNames[keycode-firstHat]; - else return JoystickUnknownNames[keycode-firstUnknown]; -} - -#ifdef OPENDINGUX -char* OPENDINGUX_GetKeyName(int keycode) -{ - if (keycode == OPENDINGUX_BUTTON_UP) return "Up"; - else if (keycode == OPENDINGUX_BUTTON_DOWN) return "Down"; - else if (keycode == OPENDINGUX_BUTTON_LEFT) return "Left"; - else if (keycode == OPENDINGUX_BUTTON_RIGHT) return "Right"; - else if (keycode == OPENDINGUX_BUTTON_A) return "A"; - else if (keycode == OPENDINGUX_BUTTON_B) return "B"; - else if (keycode == OPENDINGUX_BUTTON_X) return "X"; - else if (keycode == OPENDINGUX_BUTTON_Y) return "Y"; - else if (keycode == OPENDINGUX_BUTTON_L) return "L"; - else if (keycode == OPENDINGUX_BUTTON_R) return "R"; - else if (keycode == OPENDINGUX_BUTTON_START) return "Start"; - else if (keycode == OPENDINGUX_BUTTON_SELECT) return "Select"; - else return "..."; -} -#endif - -char* JOY_GetKeyName(int keycode) -{ -#ifdef OPENDINGUX - return OPENDINGUX_GetKeyName(keycode); -#elif ANDROID || DARWIN || SDL2 - return (char*)SDL_GetScancodeName(keycode); -#else - return (char*)SDL_GetKeyName(keycode); -#endif -} diff --git a/engine/sdl/joysticks.h b/engine/sdl/joysticks.h deleted file mode 100644 index 912ba69e4..000000000 --- a/engine/sdl/joysticks.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * OpenBOR - http://www.chronocrash.com - * ----------------------------------------------------------------------- - * All rights reserved, see LICENSE in OpenBOR root for details. - * - * Copyright (c) 2004 - 2014 OpenBOR Team - */ - -#ifndef JOYSTICKS_H -#define JOYSTICKS_H - -#define JOY_UNKNOWN_NAME "UNKNOWN" - -#define JOY_TYPE_DEFAULT 0 -#define JOY_TYPE_GAMEPARK 1 -#define JOY_AXIS_X 0 -#define JOY_AXIS_Y 1 -#define JOY_MAX_INPUTS 64 -#define JOY_LIST_FIRST 600 -#define JOY_LIST_TOTAL 4 -#define JOY_LIST_LAST JOY_LIST_FIRST + JOY_MAX_INPUTS * JOY_LIST_TOTAL -#define JOY_NAME_SIZE 1 + 1 + JOY_MAX_INPUTS * JOY_LIST_TOTAL - -#ifdef OPENDINGUX -#define OPENDINGUX_BUTTON_UP SDLK_UP -#define OPENDINGUX_BUTTON_DOWN SDLK_DOWN -#define OPENDINGUX_BUTTON_RIGHT SDLK_RIGHT -#define OPENDINGUX_BUTTON_LEFT SDLK_LEFT -#define OPENDINGUX_BUTTON_R SDLK_BACKSPACE -#define OPENDINGUX_BUTTON_L SDLK_TAB -#define OPENDINGUX_BUTTON_A SDLK_LCTRL -#define OPENDINGUX_BUTTON_B SDLK_LALT -#define OPENDINGUX_BUTTON_X SDLK_SPACE -#define OPENDINGUX_BUTTON_Y SDLK_LSHIFT -#define OPENDINGUX_BUTTON_SELECT SDLK_ESCAPE -#define OPENDINGUX_BUTTON_START SDLK_RETURN -#endif - -/* Real-Time Joystick Data */ -typedef struct{ - char Name[MAX_BUFFER_LEN]; - char KeyName[JOY_MAX_INPUTS + 1][MAX_BUFFER_LEN]; - int Type; - int NumHats; - int NumAxes; - int NumButtons; - u32 Hats; - u32 Axes; - u32 Buttons; - u64 Data; -}s_joysticks; -extern s_joysticks joysticks[JOY_LIST_TOTAL]; - - -extern const char *JoystickKeyName[JOY_NAME_SIZE]; -extern const char *GameparkKeyName[JOY_NAME_SIZE]; -extern const u64 JoystickBits[JOY_MAX_INPUTS + 1]; - -const char* PC_GetJoystickKeyName(int portnum, int keynum); -char* JOY_GetKeyName(int keycode); - - -#endif diff --git a/engine/sdl/menu.c b/engine/sdl/menu.c index 65e85ad70..de60c0c2e 100644 --- a/engine/sdl/menu.c +++ b/engine/sdl/menu.c @@ -548,11 +548,10 @@ static void drawMenu() printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "J: View Logs"); printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "S: Quit Game"); #else - //Kratus (13-03-21) changed the function "control_getkeyname" (Windows) to a direct string, because it will always use the default keys and can't be changed - printText((isWide ? 23 : 4),(isWide ? 251 : 226), WHITE, 0, 0, "A: Start Game"); - printText((isWide ? 150 : 84),(isWide ? 251 : 226), WHITE, 0, 0, "S: BGM Player"); - printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "D: View Logs"); - printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "F: Quit Game"); + printText((isWide ? 23 : 4),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Start Game", control_getmappedkeyname(0, SDID_ATTACK)); + printText((isWide ? 150 : 84),(isWide ? 251 : 226), WHITE, 0, 0, "%s: BGM Player", control_getmappedkeyname(0, SDID_ATTACK2)); + printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "%s: View Logs", control_getmappedkeyname(0, SDID_JUMP)); + printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Quit Game", control_getmappedkeyname(0, SDID_SPECIAL)); #endif //CRxTRDude - Fixed the placement of these texts and appropriately changed the site for Chrono Crash printText((isWide ? 320 : 188),(isWide ? 175 : 158), BLACK, 0, 0, "www.chronocrash.com"); @@ -611,11 +610,10 @@ static void drawBGMPlayer() printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "J: %s", bgmCycle ? "Cycle On" : "Cycle Off"); printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "S: Exit Player"); #else - //Kratus (13-03-21) changed the function "control_getkeyname" (Windows) to a direct string, because it will always use the default keys and can't be changed - printText((isWide ? 23 : 4),(isWide ? 251 : 226), WHITE, 0, 0, "A: %s", bgmPlay ? "Stop" : "Play"); - printText((isWide ? 150 : 84),(isWide ? 251 : 226), WHITE, 0, 0, "S: %s", bgmLoop ? "Repeat On" : "Repeat Off"); - printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "D: %s", bgmCycle ? "Cycle On" : "Cycle Off"); - printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "F: Exit Player"); + printText((isWide ? 23 : 4),(isWide ? 251 : 226), WHITE, 0, 0, "%s: %s", control_getmappedkeyname(0, SDID_ATTACK), bgmPlay ? "Stop" : "Play"); + printText((isWide ? 150 : 84),(isWide ? 251 : 226), WHITE, 0, 0, "%s: %s", control_getmappedkeyname(0, SDID_ATTACK2), bgmLoop ? "Repeat On" : "Repeat Off"); + printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "%s: %s", control_getmappedkeyname(0, SDID_JUMP), bgmCycle ? "Cycle On" : "Cycle Off"); + printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Exit Player", control_getmappedkeyname(0, SDID_SPECIAL)); #endif //CRxTRDude - Fixed the placement of these texts and appropriately changed the site for Chrono Crash printText((isWide ? 320 : 188),(isWide ? 175 : 158), BLACK, 0, 0, "www.chronocrash.com"); diff --git a/engine/sdl/video.c b/engine/sdl/video.c index f3565c915..0f13f308d 100644 --- a/engine/sdl/video.c +++ b/engine/sdl/video.c @@ -41,7 +41,7 @@ int brightness = 0; void initSDL() { SDL_DisplayMode video_info; - int init_flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC; + int init_flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC; /*#if EE_CURRENT_PLATFORM == EE_PLATFORM_WINDOWS SDL_setenv("SDL_AUDIODRIVER", "directsound", true); diff --git a/engine/source/utils.c b/engine/source/utils.c index 8a0dcfc7e..f9e071e69 100644 --- a/engine/source/utils.c +++ b/engine/source/utils.c @@ -361,6 +361,9 @@ void getPakName(char *name, int type) case 4: strcat(mod, ".cfg"); break; + case 5: + strcat(mod, ".controls"); + break; default: // Loose extension! break; diff --git a/engine/wii/control.c b/engine/wii/control.c index 305d0dbd3..d4b568cfd 100644 --- a/engine/wii/control.c +++ b/engine/wii/control.c @@ -1,415 +1,605 @@ /* - * OpenBOR - http://www.LavaLit.com + * OpenBOR - http://www.chronocrash.com * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in OpenBOR root for details. + * All rights reserved, see LICENSE in OpenBOR root for details. * - * Copyright (c) 2004 - 2011 OpenBOR Team + * Copyright (c) 2004 - 2019 OpenBOR Team */ +// Generic control stuff (keyboard+joystick) + +#include +#include +#include #include #include #include #include -#include -#include "wupc/wupc.h" -#include "wiiport.h" -#include "version.h" +#include "globals.h" #include "control.h" -#undef MIN -#undef MAX #include "openbor.h" - -#define PAD_START 1 -#define MAX_PADS 4 -#define PAD_END (MAX_BUTTONS*MAX_PADS) - -static int usejoy; -static int initialized; -static int hwbutton = 0; -static int using_gc[MAX_PADS]; -static int lastkey[MAX_PADS]; -static int rumbling[MAX_PADS]; -static long long unsigned rumble_msec[MAX_PADS]; -static long long unsigned time2rumble[MAX_PADS]; - -static const char *padnames[PAD_END+1+1] = { - "...", -#define CONTROLNAMES(x) \ - x" Up", \ - x" Right", \ - x" Down", \ - x" Left", \ - x" 1/A", \ - x" 2/B", \ - x" A/Y/X", \ - x" B/X/Y", \ - x" -/Menu", \ - x" +/Start", \ - x" Home/Z", \ - x" R-Trigger", \ - x" L-Trigger", \ - x" ZR", \ - x" ZL", \ - x" Z/L", \ - x" C/R", \ - x" Substick Up", \ - x" Substick Right", \ - x" Substick Down", \ - x" Substick Left", - CONTROLNAMES("P1") - CONTROLNAMES("P2") - CONTROLNAMES("P3") - CONTROLNAMES("P4") - "undefined" +#include "List.h" + +/*#define NUNCHUK_STICK_UP (0x0004 << 16) +#define NUNCHUK_STICK_DOWN (0x0008 << 16) +#define NUNCHUK_STICK_LEFT (0x0010 << 16) +#define NUNCHUK_STICK_RIGHT (0x0020 << 16)*/ +#define LEFT_STICK_UP -1 +#define LEFT_STICK_DOWN -2 +#define LEFT_STICK_LEFT -3 +#define LEFT_STICK_RIGHT -4 + +typedef enum { + DEVICE_TYPE_NONE, + DEVICE_TYPE_WII_REMOTE, + DEVICE_TYPE_WIIMOTE_NUNCHUK, + DEVICE_TYPE_CLASSIC_CONTROLLER, + DEVICE_TYPE_PRO_CONTROLLER, + DEVICE_TYPE_GAMECUBE_CONTROLLER, +} DeviceType; + +typedef struct { + DeviceType deviceType; + char name[CONTROL_DEVICE_NAME_SIZE]; + int mappings[SDID_COUNT]; + int port; + // TODO: rumble +} InputDevice; + +static InputDevice devices[MAX_DEVICES]; +static bool controlInited = false; + +static int wiimoteIDs[4] = {-1, -1, -1, -1}; + +// if non-null, device is being remapped in the input settings menu +static InputDevice *remapDevice = NULL; +static int remapKeycode = -1; + +// each list member is an array of SDID_COUNT ints, dynamically allocated +static List savedMappings; +static bool savedMappingsInited = false; + +static const char *deviceTypeNames[] = { + "None", + "Wii Remote", + "Remote+Nunchuk", + "Classic Controller", + "Wii U Pro Controller", + "GameCube Controller", }; -void poweroff() +static void handle_events(); + +// update the mappings for a device in the save data +static void update_saved_mapping(int deviceID) { - hwbutton = WII_SHUTDOWN; + InputDevice *device = &devices[deviceID]; + if (device->deviceType == DEVICE_TYPE_NONE) return; + + if (List_FindByName(&savedMappings, device->name)) + { + memcpy(List_Retrieve(&savedMappings), device->mappings, SDID_COUNT * sizeof(int)); + } + else + { + int *mappings = malloc(SDID_COUNT * sizeof(int)); + memcpy(mappings, device->mappings, SDID_COUNT * sizeof(int)); + List_InsertAfter(&savedMappings, mappings, device->name); + } } -void reset() +// set the mappings for a device to the saved settings +static void load_from_saved_mapping(int deviceID) { - hwbutton = WII_RESET; + InputDevice *device = &devices[deviceID]; + if (device->deviceType == DEVICE_TYPE_NONE) return; + + if (List_FindByName(&savedMappings, device->name)) + { + memcpy(device->mappings, List_Retrieve(&savedMappings), SDID_COUNT * sizeof(int)); + } + else + { + control_resetmappings(deviceID); + } } -void wiimote_poweroff(int playernum) +static void clear_saved_mappings() { - hwbutton = WII_SHUTDOWN; + if (!savedMappingsInited) + { + List_Init(&savedMappings); + savedMappingsInited = true; + } + + int numMappings = List_GetSize(&savedMappings); + List_Reset(&savedMappings); + for (int i = 0; i < numMappings; i++) + { + free(List_Retrieve(&savedMappings)); + List_GotoNext(&savedMappings); + } + List_Clear(&savedMappings); } -// Resets or powers off the Wii if the corresponding buttons are pressed. -// Resetting returns to the Homebrew Channel. -void respondToPowerReset() +static void setup_device(int deviceID, DeviceType type, const char *name, int port) { - borShutdown(hwbutton, DEFAULT_SHUTDOWN_MESSAGE); + devices[deviceID].deviceType = type; + devices[deviceID].port = port; + snprintf(devices[deviceID].name, sizeof(devices[deviceID].name), "%s #%i", name, port+1); + load_from_saved_mapping(deviceID); + printf("Set up device: %s\n", devices[deviceID].name); } -static int flag_to_index(unsigned long flag) +void control_init() { - int index = 0; - unsigned long bit = 1; - while(!((bit<deviceType = DEVICE_TYPE_NONE; + } + + remapDevice = NULL; + remapKeycode = -1; + controlInited = false; } -void control_init(int joy_enable) +static void set_default_wiimote_mappings(InputDevice *device) { - int i; - if(initialized) return; - for(i=0; imappings[SDID_MOVEUP] = WPAD_BUTTON_RIGHT; + device->mappings[SDID_MOVEDOWN] = WPAD_BUTTON_LEFT; + device->mappings[SDID_MOVELEFT] = WPAD_BUTTON_UP; + device->mappings[SDID_MOVERIGHT] = WPAD_BUTTON_DOWN; + device->mappings[SDID_ATTACK] = WPAD_BUTTON_1; + device->mappings[SDID_ATTACK2] = WPAD_BUTTON_A; + device->mappings[SDID_ATTACK3] = WPAD_BUTTON_HOME; + device->mappings[SDID_ATTACK4] = 0; + device->mappings[SDID_JUMP] = WPAD_BUTTON_2; + device->mappings[SDID_SPECIAL] = WPAD_BUTTON_B; + device->mappings[SDID_START] = WPAD_BUTTON_PLUS; + device->mappings[SDID_SCREENSHOT] = WPAD_BUTTON_MINUS; + device->mappings[SDID_ESC] = WPAD_BUTTON_1; +} - // set callbacks for power/reset buttons - SYS_SetResetCallback(reset); - SYS_SetPowerCallback(poweroff); - WPAD_SetPowerButtonCallback(wiimote_poweroff); +static void set_default_wiimote_nunchuk_mappings(InputDevice *device) +{ + device->mappings[SDID_MOVEUP] = LEFT_STICK_UP; + device->mappings[SDID_MOVEDOWN] = LEFT_STICK_DOWN; + device->mappings[SDID_MOVELEFT] = LEFT_STICK_LEFT; + device->mappings[SDID_MOVERIGHT] = LEFT_STICK_RIGHT; + device->mappings[SDID_ATTACK] = WPAD_BUTTON_A; + device->mappings[SDID_ATTACK2] = WPAD_NUNCHUK_BUTTON_C; + device->mappings[SDID_ATTACK3] = WPAD_BUTTON_1; + device->mappings[SDID_ATTACK4] = WPAD_BUTTON_2; + device->mappings[SDID_JUMP] = WPAD_BUTTON_B; + device->mappings[SDID_SPECIAL] = WPAD_NUNCHUK_BUTTON_Z; + device->mappings[SDID_START] = WPAD_BUTTON_PLUS; + device->mappings[SDID_SCREENSHOT] = WPAD_BUTTON_MINUS; + device->mappings[SDID_ESC] = WPAD_BUTTON_B; +} - initialized = 1; +static void set_default_classic_controller_mappings(InputDevice *device) +{ + device->mappings[SDID_MOVEUP] = WPAD_CLASSIC_BUTTON_UP; + device->mappings[SDID_MOVEDOWN] = WPAD_CLASSIC_BUTTON_DOWN; + device->mappings[SDID_MOVELEFT] = WPAD_CLASSIC_BUTTON_LEFT; + device->mappings[SDID_MOVERIGHT] = WPAD_CLASSIC_BUTTON_RIGHT; + device->mappings[SDID_ATTACK] = WPAD_CLASSIC_BUTTON_A; + device->mappings[SDID_ATTACK2] = WPAD_CLASSIC_BUTTON_Y; + device->mappings[SDID_ATTACK3] = WPAD_CLASSIC_BUTTON_FULL_R; + device->mappings[SDID_ATTACK4] = WPAD_CLASSIC_BUTTON_FULL_L; + device->mappings[SDID_JUMP] = WPAD_CLASSIC_BUTTON_B; + device->mappings[SDID_SPECIAL] = WPAD_CLASSIC_BUTTON_X; + device->mappings[SDID_START] = WPAD_CLASSIC_BUTTON_PLUS; + device->mappings[SDID_SCREENSHOT] = WPAD_CLASSIC_BUTTON_MINUS; + device->mappings[SDID_ESC] = WPAD_CLASSIC_BUTTON_B; } -int control_usejoy(int enable) +void control_resetmappings(int deviceID) { - usejoy = enable; - return 0; + if (deviceID < 0) return; + + InputDevice *device = &devices[deviceID]; + switch (device->deviceType) + { + case DEVICE_TYPE_WII_REMOTE: + set_default_wiimote_mappings(device); + break; + case DEVICE_TYPE_WIIMOTE_NUNCHUK: + set_default_wiimote_nunchuk_mappings(device); + break; + case DEVICE_TYPE_CLASSIC_CONTROLLER: + set_default_classic_controller_mappings(device); + break; + default: + memset(device->mappings, 0, sizeof(device->mappings)); + break; + } } -int control_getjoyenabled() +static DeviceType device_type_for_expansion_type(int expansion) { - return usejoy; + switch (expansion) + { + case WPAD_EXP_NUNCHUK: + return DEVICE_TYPE_WIIMOTE_NUNCHUK; + case WPAD_EXP_CLASSIC: + return DEVICE_TYPE_CLASSIC_CONTROLLER; + case WPAD_EXP_NONE: + default: + return DEVICE_TYPE_WII_REMOTE; + } } -int keyboard_getlastkey(void) +// handle controller connected/disconnected or Wiimote expansion plugged/unplugged +static void handle_events() { - int i, ret=0; - for(i=0; iexp.type); + + if (wiimoteIDs[port] == -1) // wiimote connected + { + for (size_t i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType == DEVICE_TYPE_NONE) + { + wiimoteIDs[port] = i; + break; + } + } + + // MAX_DEVICES is 32 and there are a maximum of 12 devices supported, so this should be safe + assert(wiimoteIDs[port] != -1); + } + + if (newType != devices[wiimoteIDs[port]].deviceType) // wiimote connected or expansion type changed + { + setup_device(wiimoteIDs[port], newType, deviceTypeNames[newType], port); + } + } + } } -void control_setkey(s_playercontrols * pcontrols, unsigned int flag, int key) +// Returns 1 if key is pressed, 0 if not +static unsigned int is_key_pressed(InputDevice *device, int keycode) { - if(!pcontrols) return; - pcontrols->settings[flag_to_index(flag)] = key; - pcontrols->keyflags = pcontrols->newkeyflags = 0; + if (device->deviceType == DEVICE_TYPE_WII_REMOTE) + { + WPADData *wpad = WPAD_Data(device->port); + return !!(wpad->btns_h & keycode); + } + else if (device->deviceType == DEVICE_TYPE_WIIMOTE_NUNCHUK) + { + WPADData *wpad = WPAD_Data(device->port); + switch (keycode) + { + case LEFT_STICK_UP: return (wpad->exp.nunchuk.js.pos.y >= 0xB0); + case LEFT_STICK_DOWN: return (wpad->exp.nunchuk.js.pos.y <= 0x40); + case LEFT_STICK_LEFT: return (wpad->exp.nunchuk.js.pos.x <= 0x40); + case LEFT_STICK_RIGHT: return (wpad->exp.nunchuk.js.pos.x >= 0xB0); + default: return !!(wpad->btns_h & keycode); + } + } + else if (device->deviceType == DEVICE_TYPE_CLASSIC_CONTROLLER) + { + // TODO: analog sticks + WPADData *wpad = WPAD_Data(device->port); + return !!(wpad->btns_h & keycode); + } + + return 0; } -// Scan input for newly-pressed keys. -// Return value: -// 0 = no key was pressed -// >0 = key code for pressed key -// <0 = error -int control_scankey() +void control_update_player(s_playercontrols *playerControls) { - static unsigned ready = 0; - unsigned i, k=0; + uint32_t keyflags = 0; + InputDevice *device = &devices[playerControls->deviceID]; - for(i=0; imappings[i]) << i); + } + + playerControls->newkeyflags = keyflags & (~playerControls->keyflags); + playerControls->keyflags = keyflags; } -char * control_getkeyname(unsigned keycode) +void control_update(s_playercontrols **playerControls, int numPlayers) { - if(keycode >= PAD_START && keycode <= PAD_END) return (char*)padnames[keycode]; - return "..."; + handle_events(); + + for (int i = 0; i < numPlayers; i++) + { + control_update_player(playerControls[i]); + } } -void control_update(s_playercontrols ** playercontrols, int numplayers) +void control_remapdevice(int deviceID) { - unsigned long k; - unsigned long i; - int player; - int t; - s_playercontrols * pcontrols; - unsigned port[MAX_PADS]; - long long unsigned msec = 0; - for(i=0; i time2rumble[i]+rumble_msec[i]) - { - rumbling[i] = 0; - WPAD_Rumble(i, 0); - WUPC_Rumble(i, false); - PAD_ControlMotor(i, 0); - } - } - } - for(player=0; playersettings[i]; - if(t >= PAD_START && t <= PAD_END) - { - int portnum = (t-1) / MAX_BUTTONS; - int shiftby = (t-1) % MAX_BUTTONS; - if(portnum >= 0 && portnum <= 3) - { - if((port[portnum] >> shiftby) & 1) k |= (1<kb_break = 0; - pcontrols->newkeyflags = k & (~pcontrols->keyflags); - pcontrols->keyflags = k; - } - - if (hwbutton) respondToPowerReset(); + if (deviceID < 0) + { + // done remapping; reset globals to default values + remapDevice = NULL; + remapKeycode = -1; + } + else + { + assert(devices[deviceID].deviceType != DEVICE_TYPE_NONE); + remapDevice = &devices[deviceID]; + remapKeycode = -1; + } } -void control_rumble(int port, int ratio, int msec) +int control_getremappedkey() { - WPADData *wpad; - struct WUPCData *wupc; - wpad = WPAD_Data(port); - wupc = WUPC_Data(port); - - rumbling[port] = 1; - rumble_msec[port] = msec * 3; - time2rumble[port] = ticks_to_millisecs(gettime()); - - if (using_gc[port]) PAD_ControlMotor(port, 1); - else if(wupc != NULL) WUPC_Rumble(port, true); - else if (wpad->exp.type != WPAD_EXP_CLASSIC) WPAD_Rumble(port, 1); + return remapKeycode; } -unsigned long getPad(int port) +int *control_getmappings(int deviceID) { - unsigned long btns = 0; - unsigned short gcbtns; - WPADData *wpad; - struct WUPCData *wupc; - - // necessary to detect GC controllers plugged in while OpenBOR is running - PAD_Init(); - - PAD_ScanPads(); - gcbtns = PAD_ButtonsDown(port) | PAD_ButtonsHeld(port); - WUPC_UpdateButtonStats(); - WPAD_ScanPads(); - wpad = WPAD_Data(port); - wupc = WUPC_Data(port); - - if (gcbtns) using_gc[port] = 1; - else if (wpad->btns_h) using_gc[port] = 0; - - - if(wpad->exp.type == WPAD_EXP_CLASSIC) - { - // Left thumb stick - if(wpad->exp.classic.ljs.mag >= 0.3) - { - if (wpad->exp.classic.ljs.ang >= 310 || - wpad->exp.classic.ljs.ang <= 50) btns |= WII_UP; - if (wpad->exp.classic.ljs.ang >= 130 && - wpad->exp.classic.ljs.ang <= 230) btns |= WII_DOWN; - if (wpad->exp.classic.ljs.ang >= 220 && - wpad->exp.classic.ljs.ang <= 320) btns |= WII_LEFT; - if (wpad->exp.classic.ljs.ang >= 40 && - wpad->exp.classic.ljs.ang <= 140) btns |= WII_RIGHT; - } - - // Right thumb stick - if(wpad->exp.classic.rjs.mag >= 0.3) - { - if (wpad->exp.classic.rjs.ang >= 310 || - wpad->exp.classic.rjs.ang <= 50) btns |= WII_SUB_UP; - if (wpad->exp.classic.rjs.ang >= 130 && - wpad->exp.classic.rjs.ang <= 230) btns |= WII_SUB_DOWN; - if (wpad->exp.classic.rjs.ang >= 220 && - wpad->exp.classic.rjs.ang <= 320) btns |= WII_SUB_LEFT; - if (wpad->exp.classic.rjs.ang >= 40 && - wpad->exp.classic.rjs.ang <= 140) btns |= WII_SUB_RIGHT; - } - - // D-pad - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_UP) btns |= WII_UP; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_DOWN) btns |= WII_DOWN; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_LEFT) btns |= WII_LEFT; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_RIGHT) btns |= WII_RIGHT; - } - else if (wupc != NULL) // Pro Controller - { - if(wupc->button & WPAD_CLASSIC_BUTTON_UP) btns |= WII_UP; - if(wupc->button & WPAD_CLASSIC_BUTTON_DOWN) btns |= WII_DOWN; - if(wupc->button & WPAD_CLASSIC_BUTTON_LEFT) btns |= WII_LEFT; - if(wupc->button & WPAD_CLASSIC_BUTTON_RIGHT) btns |= WII_RIGHT; - if(wupc->button & WPAD_CLASSIC_BUTTON_PLUS) btns |= WII_PLUS_START; - if(wupc->button & WPAD_CLASSIC_BUTTON_MINUS) btns |= WII_MINUS; - if(wupc->button & WPAD_CLASSIC_BUTTON_HOME) btns |= WII_HOME; - if(wupc->button & WPAD_CLASSIC_BUTTON_A) btns |= WII_1_A; - if(wupc->button & WPAD_CLASSIC_BUTTON_B) btns |= WII_2_B; - if(wupc->button & WPAD_CLASSIC_BUTTON_Y) btns |= WII_A_Y_X; - if(wupc->button & WPAD_CLASSIC_BUTTON_X) btns |= WII_B_X_Y; - if(wupc->button & WPAD_CLASSIC_BUTTON_FULL_R) btns |= WII_C_R; - if(wupc->button & WPAD_CLASSIC_BUTTON_FULL_L) btns |= WII_Z_L; - if(wupc->button & WPAD_CLASSIC_BUTTON_ZL) btns |= WII_ZL; - if(wupc->button & WPAD_CLASSIC_BUTTON_ZR) btns |= WII_ZR; - - //analog sticks - if(wupc->yAxisL > 200) btns |= WII_UP; - if(wupc->yAxisL < -200) btns |= WII_DOWN; - if(wupc->xAxisL > 200) btns |= WII_RIGHT; - if(wupc->xAxisL < -200) btns |= WII_LEFT; - - if(wupc->yAxisR > 200) btns |= WII_SUB_UP; - if(wupc->yAxisR < -200) btns |= WII_SUB_DOWN; - if(wupc->xAxisR > 200) btns |= WII_SUB_RIGHT; - if(wupc->xAxisR < -200) btns |= WII_SUB_LEFT; - - - } - else if((wpad->exp.type == WPAD_EXP_NUNCHUK) && usejoy) // Nunchuck - { - if(wpad->exp.nunchuk.js.pos.y >= 0xB0) btns |= WII_UP; - if(wpad->exp.nunchuk.js.pos.y <= 0x40) btns |= WII_DOWN; - if(wpad->exp.nunchuk.js.pos.x <= 0x40) btns |= WII_LEFT; - if(wpad->exp.nunchuk.js.pos.x >= 0xB0) btns |= WII_RIGHT; - } - else // Wiimote - { - if(wpad->btns_h & WPAD_BUTTON_UP) btns |= WII_LEFT; - if(wpad->btns_h & WPAD_BUTTON_DOWN) btns |= WII_RIGHT; - if(wpad->btns_h & WPAD_BUTTON_LEFT) btns |= WII_DOWN; - if(wpad->btns_h & WPAD_BUTTON_RIGHT) btns |= WII_UP; - } - - // GameCube analog stick - if(PAD_StickY(port) > 18) btns |= WII_UP; - if(PAD_StickY(port) < -18) btns |= WII_DOWN; - if(PAD_StickX(port) < -18) btns |= WII_LEFT; - if(PAD_StickX(port) > 18) btns |= WII_RIGHT; - - // GameCube C-stick - if(PAD_SubStickY(port) > 18) btns |= WII_SUB_UP; - if(PAD_SubStickY(port) < -18) btns |= WII_SUB_DOWN; - if(PAD_SubStickX(port) < -18) btns |= WII_SUB_LEFT; - if(PAD_SubStickX(port) > 18) btns |= WII_SUB_RIGHT; - - // GameCube D-pad - if(gcbtns & PAD_BUTTON_UP) btns |= WII_UP; - if(gcbtns & PAD_BUTTON_DOWN) btns |= WII_DOWN; - if(gcbtns & PAD_BUTTON_LEFT) btns |= WII_LEFT; - if(gcbtns & PAD_BUTTON_RIGHT) btns |= WII_RIGHT; - - if(wpad->exp.type == WPAD_EXP_CLASSIC) // Classic Controller - { - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_A) btns |= WII_1_A; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_B) btns |= WII_2_B; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_Y) btns |= WII_A_Y_X; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_X) btns |= WII_B_X_Y; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_MINUS) btns |= WII_MINUS; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_PLUS) btns |= WII_PLUS_START; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME) btns |= WII_HOME; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_FULL_R) btns |= WII_C_R; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_FULL_L) btns |= WII_Z_L; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_ZL) btns |= WII_ZL; - if(wpad->btns_h & WPAD_CLASSIC_BUTTON_ZR) btns |= WII_ZR; - - } - else // Wiimote or Wiimote + Nunchuk + return devices[deviceID].mappings; +} + +const char *control_getkeyname(int deviceID, int keycode) +{ + if (deviceID < 0) return "None"; + + if (devices[deviceID].deviceType == DEVICE_TYPE_WII_REMOTE) + { + const char *buttonNames[] = { + "2", + "1", + "B", + "A", + "-", + "???", + "???", + "Home", + "Down", + "Up", + "Left", + "Right", + "+", + }; + + for (size_t i = 0; i < sizeof(buttonNames) / sizeof(buttonNames[0]); i++) + { + if (keycode == (1 << i)) + { + return buttonNames[i]; + } + } + } + else if (devices[deviceID].deviceType == DEVICE_TYPE_WIIMOTE_NUNCHUK) + { + const char *buttonNames[] = { + "2", + "1", + "B", + "A", + "-", + "Home", + "D-Pad Left", + "D-Pad Right", + "D-Pad Down", + "D-Pad Up", + "+", + "???", + "???", + "???", + "Z", + "C", + }; + + for (size_t i = 0; i < sizeof(buttonNames) / sizeof(buttonNames[0]); i++) + { + if (keycode == (1 << i)) + { + return buttonNames[i]; + } + } + + // if it's not a button, it's an analog stick direction + switch (keycode) + { + case LEFT_STICK_UP: return "Analog Stick Up"; + case LEFT_STICK_DOWN: return "Analog Stick Down"; + case LEFT_STICK_LEFT: return "Analog Stick Left"; + case LEFT_STICK_RIGHT: return "Analog Stick Right"; + } + } + else if (devices[deviceID].deviceType == DEVICE_TYPE_CLASSIC_CONTROLLER) + { + const char *buttonNames[] = { + "D-Pad Up", + "D-Pad Left", + "ZR", + "X", + "A", + "Y", + "B", + "ZL", + "R", + "+", + "Home", + "-", + "L", + "Down", + "Right", + }; + + for (size_t i = 0; i < sizeof(buttonNames) / sizeof(buttonNames[0]); i++) + { + if (keycode == (0x10000 << i)) + { + return buttonNames[i]; + } + } + } + + return "None"; +} + +bool control_isvaliddevice(int deviceID) +{ + return deviceID >= 0 && devices[deviceID].deviceType != DEVICE_TYPE_NONE; +} + +const char *control_getdevicename(int deviceID) +{ + return devices[deviceID].deviceType == DEVICE_TYPE_NONE ? "None" : devices[deviceID].name; +} + +void control_rumble(int deviceID, int ratio, int msec) +{ + // TODO +} + +#define MAPPINGS_FILE_SENTINEL 0x9cf232d4 + +bool control_loadmappings(const char *filename) +{ + FILE *fp = fopen(filename, "rb"); + if (!fp) + { + return false; + } + + clear_saved_mappings(); + + while (!feof(fp) && !ferror(fp)) + { + char name[CONTROL_DEVICE_NAME_SIZE]; + int *mapping = malloc(SDID_COUNT * sizeof(int)); + int sentinel; + if (fread(name, 1, sizeof(name), fp) != sizeof(name) || + fread(mapping, sizeof(int), SDID_COUNT, fp) != SDID_COUNT || + fread(&sentinel, sizeof(int), 1, fp) != 1) + { + free(mapping); + break; + } + else if (sentinel != MAPPINGS_FILE_SENTINEL) + { + free(mapping); + fclose(fp); + return false; + } + + name[sizeof(name)-1] = '\0'; // just in case + printf("Loaded mapping for %s\n", name); + List_InsertAfter(&savedMappings, mapping, name); + } + + fclose(fp); + + // update all current device mappings with the newly loaded mappings + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType != DEVICE_TYPE_NONE) + { + load_from_saved_mapping(i); + } + } + + return true; +} + +bool control_savemappings(const char *filename) +{ + // update savedMappings with all current device mappings + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType != DEVICE_TYPE_NONE) + { + update_saved_mapping(i); + } + } + + FILE *fp = fopen(filename, "wb"); + if (!fp) + { + return false; + } + + int numMappings = List_GetSize(&savedMappings); + List_Reset(&savedMappings); + for (int i = 0; i < numMappings; i++) { - if(wpad->btns_h & WPAD_BUTTON_1) btns |= WII_1_A; - if(wpad->btns_h & WPAD_BUTTON_2) btns |= WII_2_B; - if(wpad->btns_h & WPAD_BUTTON_A) btns |= WII_A_Y_X; - if(wpad->btns_h & WPAD_BUTTON_B) btns |= WII_B_X_Y; - if(wpad->btns_h & WPAD_BUTTON_MINUS) btns |= WII_MINUS; - if(wpad->btns_h & WPAD_BUTTON_PLUS) btns |= WII_PLUS_START; - if(wpad->btns_h & WPAD_BUTTON_HOME) btns |= WII_HOME; - if(wpad->btns_h & WPAD_NUNCHUK_BUTTON_Z) btns |= WII_Z_L; - if(wpad->btns_h & WPAD_NUNCHUK_BUTTON_C) btns |= WII_C_R; - } - - if(gcbtns & PAD_BUTTON_X) btns |= WII_A_Y_X; - if(gcbtns & PAD_BUTTON_Y) btns |= WII_B_X_Y; - if(gcbtns & PAD_BUTTON_A) btns |= WII_1_A; - if(gcbtns & PAD_BUTTON_B) btns |= WII_2_B; - if(gcbtns & PAD_BUTTON_START) btns |= WII_PLUS_START; - if(gcbtns & PAD_TRIGGER_R) btns |= WII_C_R; - if(gcbtns & PAD_TRIGGER_L) btns |= WII_Z_L; - if(gcbtns & PAD_TRIGGER_Z) btns |= WII_HOME; - - return lastkey[port] = btns; + char name[CONTROL_DEVICE_NAME_SIZE]; + snprintf(name, sizeof(name), "%s", List_GetName(&savedMappings)); + int *mapping = List_Retrieve(&savedMappings); + const int sentinel = MAPPINGS_FILE_SENTINEL; + if (fwrite(name, 1, sizeof(name), fp) != sizeof(name) || + fwrite(mapping, sizeof(int), SDID_COUNT, fp) != SDID_COUNT || + fwrite(&sentinel, sizeof(int), 1, fp) != 1) + { + fclose(fp); + return false; + } + + List_GotoNext(&savedMappings); + } + + fclose(fp); + return true; +} + +void control_clearmappings() +{ + clear_saved_mappings(); + + for (int i = 0; i < MAX_DEVICES; i++) + { + if (devices[i].deviceType != DEVICE_TYPE_NONE) + { + control_resetmappings(i); + } + } } + diff --git a/engine/wii/control.h b/engine/wii/control.h index 4e83537ea..dde267852 100644 --- a/engine/wii/control.h +++ b/engine/wii/control.h @@ -1,116 +1,62 @@ /* - * OpenBOR - http://www.LavaLit.com + * OpenBOR - http://www.chronocrash.com * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in OpenBOR root for details. + * All rights reserved, see LICENSE in OpenBOR root for details. * - * Copyright (c) 2004 - 2011 OpenBOR Team + * Copyright (c) 2004 - 2019 OpenBOR Team */ #ifndef CONTROL_H #define CONTROL_H +// Generic control stuff (keyboard+joystick). -#define MAX_BUTTONS 21 - -#define WII_UP 0x00000001 -#define WII_RIGHT 0x00000002 -#define WII_DOWN 0x00000004 -#define WII_LEFT 0x00000008 -#define WII_1_A 0x00000010 -#define WII_2_B 0x00000020 -#define WII_A_Y_X 0x00000040 -#define WII_B_X_Y 0x00000080 -#define WII_MINUS 0x00000100 -#define WII_PLUS_START 0x00000200 -#define WII_HOME 0x00000400 -#define WII_R_TRIGGER 0x00000800 -#define WII_L_TRIGGER 0x00001000 -#define WII_ZR 0x00002000 -#define WII_ZL 0x00004000 -#define WII_C_R 0x00008000 -#define WII_Z_L 0x00010000 -#define WII_SUB_UP 0x00020000 -#define WII_SUB_RIGHT 0x00040000 -#define WII_SUB_DOWN 0x00080000 -#define WII_SUB_LEFT 0x00100000 - -#define CONTROL_ESC 11 - -#define CONTROL_DEFAULT1_UP 1 -#define CONTROL_DEFAULT1_RIGHT 2 -#define CONTROL_DEFAULT1_DOWN 3 -#define CONTROL_DEFAULT1_LEFT 4 -#define CONTROL_DEFAULT1_FIRE1 5 -#define CONTROL_DEFAULT1_FIRE2 7 -#define CONTROL_DEFAULT1_FIRE3 16 -#define CONTROL_DEFAULT1_FIRE4 17 -#define CONTROL_DEFAULT1_FIRE5 6 -#define CONTROL_DEFAULT1_FIRE6 8 -#define CONTROL_DEFAULT1_START 10 -#define CONTROL_DEFAULT1_SCREENSHOT 9 - -#define CONTROL_DEFAULT2_UP (1+MAX_BUTTONS) -#define CONTROL_DEFAULT2_RIGHT (2+MAX_BUTTONS) -#define CONTROL_DEFAULT2_DOWN (3+MAX_BUTTONS) -#define CONTROL_DEFAULT2_LEFT (4+MAX_BUTTONS) -#define CONTROL_DEFAULT2_FIRE1 (5+MAX_BUTTONS) -#define CONTROL_DEFAULT2_FIRE2 (7+MAX_BUTTONS) -#define CONTROL_DEFAULT2_FIRE3 (16+MAX_BUTTONS) -#define CONTROL_DEFAULT2_FIRE4 (17+MAX_BUTTONS) -#define CONTROL_DEFAULT2_FIRE5 (6+MAX_BUTTONS) -#define CONTROL_DEFAULT2_FIRE6 (8+MAX_BUTTONS) -#define CONTROL_DEFAULT2_START (10+MAX_BUTTONS) -#define CONTROL_DEFAULT2_SCREENSHOT (9+MAX_BUTTONS) - -#define CONTROL_DEFAULT3_UP (1+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_RIGHT (2+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_DOWN (3+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_LEFT (4+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_FIRE1 (5+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_FIRE2 (7+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_FIRE3 (16+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_FIRE4 (17+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_FIRE5 (6+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_FIRE6 (8+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_START (10+(MAX_BUTTONS*2)) -#define CONTROL_DEFAULT3_SCREENSHOT (9+(MAX_BUTTONS*2)) - -#define CONTROL_DEFAULT4_UP (1+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_RIGHT (2+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_DOWN (3+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_LEFT (4+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_FIRE1 (5+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_FIRE2 (7+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_FIRE3 (16+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_FIRE4 (17+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_FIRE5 (6+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_FIRE6 (8+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_START (10+(MAX_BUTTONS*3)) -#define CONTROL_DEFAULT4_SCREENSHOT (9+(MAX_BUTTONS*3)) +#include + +// 32 is an arbitrary number larger than the number of input devices that will ever be available +#define MAX_DEVICES 32 +#define CONTROL_DEVICE_NAME_SIZE 64 #define CONTROL_NONE (1+(MAX_BUTTONS*99)) //Kratus (20-04-21) value used to clear all keys #define WII_SHUTDOWN -1 #define WII_RESET -2 -typedef struct -{ - int settings[32]; - unsigned long keyflags, newkeyflags; - int kb_break; -} -s_playercontrols; +typedef struct { + int deviceID; + uint32_t keyflags; + uint32_t newkeyflags; +} s_playercontrols; +void control_init(); void control_exit(); -void control_init(int joy_enable); -int control_usejoy(int enable); -int control_getjoyenabled(); -int keyboard_getlastkey(); -void control_setkey(s_playercontrols * pcontrols, unsigned int flag, int key); -int control_scankey(); -char* control_getkeyname(unsigned int keycode); -void control_update(s_playercontrols ** playercontrols, int numplayers); -void control_rumble(int port, int ratio, int msec); -unsigned long getPad(int port); - -#endif + +/* Listen to input from deviceID. The first input from deviceID will be returned by the next call to + control_getremappedkey(). Call with deviceID=-1 to finish remapping. */ +void control_remapdevice(int deviceID); + +// Returns the keycode of the first key pressed on the device being remapped, or -1 if nothing has been pressed yet +int control_getremappedkey(); + +// Returns an array of size SDID_COUNT +int *control_getmappings(int deviceID); + +// Resets mappings for device to default +void control_resetmappings(int deviceID); +void control_update(s_playercontrols **allPlayerControls, int numPlayers); +void control_update_keyboard(s_playercontrols *keyboardControls); +const char *control_getkeyname(int deviceID, int keycode); +bool control_isvaliddevice(int deviceID); +const char *control_getdevicename(int deviceID); +void control_rumble(int deviceID, int ratio, int msec); + +bool control_loadmappings(const char *filename); +bool control_savemappings(const char *filename); + +// clears saved mappings and resets every device's mappings to defaults +void control_clearmappings(); + + +#define control_getmappedkeyname(deviceID, key) control_getkeyname(deviceID, control_getmappings(deviceID)[key]) + +#endif /* defined(CONTROL_H) */ diff --git a/engine/wii/menu.c b/engine/wii/menu.c index 424f458b7..bbe719e9c 100644 --- a/engine/wii/menu.c +++ b/engine/wii/menu.c @@ -621,11 +621,11 @@ void drawMenu() printText((isWide ? 26 : 5), (isWide ? 11 : 4), WHITE, 0, 0, "OpenBoR %s", VERSION); printText((isWide ? 392 : 261),(isWide ? 11 : 4), WHITE, 0, 0, __DATE__); - printText((isWide ? 23 : 4),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Start Game", control_getkeyname(savedata.keys[0][SDID_ATTACK])); - printText((isWide ? 150 : 84),(isWide ? 251 : 226), WHITE, 0, 0, "%s: BGM Player", control_getkeyname(savedata.keys[0][SDID_ATTACK2])); - printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "%s: View Logs", control_getkeyname(savedata.keys[0][SDID_JUMP])); - printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Quit Game", control_getkeyname(savedata.keys[0][SDID_SPECIAL])); - printText((isWide ? 330 : 197),(isWide ? 170 : 155), BLACK, 0, 0, "www.LavaLit.com"); + printText((isWide ? 23 : 4),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Start Game", control_getmappedkeyname(0, SDID_ATTACK)); + printText((isWide ? 150 : 84),(isWide ? 251 : 226), WHITE, 0, 0, "%s: BGM Player", control_getmappedkeyname(0, SDID_ATTACK2)); + printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "%s: View Logs", control_getmappedkeyname(0, SDID_JUMP)); + printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Quit Game", control_getmappedkeyname(0, SDID_SPECIAL)); + printText((isWide ? 330 : 197),(isWide ? 170 : 155), BLACK, 0, 0, "www.ChronoCrash.com"); printText((isWide ? 322 : 190),(isWide ? 180 : 165), BLACK, 0, 0, "www.SenileTeam.com"); #ifdef SPK_SUPPORTED