diff --git a/.github/workflows/build_3ds.yml b/.github/workflows/build_3ds.yml index 4b7b2f37f..0cf704a73 100644 --- a/.github/workflows/build_3ds.yml +++ b/.github/workflows/build_3ds.yml @@ -7,6 +7,7 @@ concurrency: jobs: build-3DS: + if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: devkitpro/devkitarm:latest diff --git a/.github/workflows/build_haiku.yml b/.github/workflows/build_haiku.yml index 336f2040e..c5aa81421 100644 --- a/.github/workflows/build_haiku.yml +++ b/.github/workflows/build_haiku.yml @@ -7,6 +7,7 @@ concurrency: jobs: build-haiku: + if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: haiku/cross-compiler:x86_64-r1beta4 diff --git a/.github/workflows/build_psp.yml b/.github/workflows/build_psp.yml index fc325a001..ddadbc569 100644 --- a/.github/workflows/build_psp.yml +++ b/.github/workflows/build_psp.yml @@ -7,6 +7,7 @@ concurrency: jobs: build-PSP: + if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: pspdev/pspdev:latest diff --git a/.github/workflows/build_wiigc.yml b/.github/workflows/build_wiigc.yml index 3c021c672..d311e2b1b 100644 --- a/.github/workflows/build_wiigc.yml +++ b/.github/workflows/build_wiigc.yml @@ -7,6 +7,7 @@ concurrency: jobs: build: + if: github.ref_name == github.event.repository.default_branch runs-on: ubuntu-latest container: image: devkitpro/devkitppc:latest diff --git a/src/Entity.c b/src/Entity.c index b2a1deefa..5d514e7cb 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -820,8 +820,8 @@ static void LocalPlayer_InputSet(int key, cc_bool pressed) { struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; if (pressed && !hacks->Enabled) return; - if (key == KeyBinds[KEYBIND_SPEED]) hacks->Speeding = pressed; - if (key == KeyBinds[KEYBIND_HALF_SPEED]) hacks->HalfSpeeding = pressed; + if (KeyBind_Claims(KEYBIND_SPEED, key)) hacks->Speeding = pressed; + if (KeyBind_Claims(KEYBIND_HALF_SPEED, key)) hacks->HalfSpeeding = pressed; } static void LocalPlayer_InputDown(void* obj, int key, cc_bool was) { diff --git a/src/Input.c b/src/Input.c index 4b4e35214..7ce09ab19 100644 --- a/src/Input.c +++ b/src/Input.c @@ -321,15 +321,16 @@ void Pointer_SetPosition(int idx, int x, int y) { /*########################################################################################################################* *---------------------------------------------------------Keybinds--------------------------------------------------------* *#########################################################################################################################*/ -cc_uint8 KeyBinds[KEYBIND_COUNT]; -/* TODO find a better way than this. maybe alternative keybinds? */ +cc_uint8 KeyBinds_Gamepad[KEYBIND_COUNT]; +cc_uint8 KeyBinds_Normal[KEYBIND_COUNT]; + const cc_uint8 KeyBind_GamepadDefaults[KEYBIND_COUNT] = { CCPAD_UP, CCPAD_DOWN, CCPAD_LEFT, CCPAD_RIGHT, /* Movement */ CCPAD_A, 0, CCPAD_START, CCPAD_Y, /* Jump, SetSpawn, OpenChat */ CCPAD_X, 0, CCPAD_START, 0, /* Inventory, EnterChat */ - CCKEY_LSHIFT, 'X', 'Z', 'Q', 'E', /* Hacks */ - 0, 0, 0, 0, - CCKEY_F5, 0, 0, 0, + 0, 0, 0, 0, 0, /* Hacks */ + 0, 0, 0, 0, /* LAlt - F11 */ + 0, 0, 0, 0, /* F5 - C */ 0, CCPAD_L, 0, CCPAD_R, 0, 0, 0, 0,0,0, 0,0,0,0, @@ -368,49 +369,45 @@ static const char* const keybindNames[KEYBIND_COUNT] = { "HotbarLeft", "HotbarRight" }; -cc_bool KeyBind_IsPressed(KeyBind binding) { return Input.Pressed[KeyBinds[binding]]; } +cc_bool KeyBind_IsPressed(KeyBind binding) { + return Input.Pressed[KeyBinds_Normal[binding]] || + Input.Pressed[KeyBinds_Gamepad[binding]]; +} -static void KeyBind_Load(void) { +static void KeyBind_Load(const char* prefix, cc_uint8* keybinds, const cc_uint8* defaults) { cc_string name; char nameBuffer[STRING_SIZE + 1]; - const cc_uint8* defaults; - int mapping; - int i; + int mapping, i; - defaults = KeyBind_GetDefaults(); String_InitArray_NT(name, nameBuffer); for (i = 0; i < KEYBIND_COUNT; i++) { name.length = 0; - String_Format1(&name, "key-%c", keybindNames[i]); + String_Format1(&name, prefix, keybindNames[i]); name.buffer[name.length] = '\0'; mapping = Options_GetEnum(name.buffer, defaults[i], storageNames, INPUT_COUNT); - if (mapping != CCKEY_ESCAPE) KeyBinds[i] = mapping; + if (mapping == CCKEY_ESCAPE) mapping = defaults[i]; + + keybinds[i] = mapping; } } -void KeyBind_Set(KeyBind binding, int key) { +void KeyBind_Set(KeyBind binding, int key, cc_uint8* binds) { cc_string name; char nameBuffer[STRING_SIZE]; cc_string value; String_InitArray(name, nameBuffer); - String_Format1(&name, "key-%c", keybindNames[binding]); + String_Format1(&name, binds == KeyBinds_Gamepad ? "pad-%c" : "key-%c", + keybindNames[binding]); value = String_FromReadonly(storageNames[key]); Options_SetString(&name, &value); - KeyBinds[binding] = key; + binds[binding] = key; } /* Initialises and loads key bindings from options */ static void KeyBind_Init(void) { - const cc_uint8* defaults; - int i; - - defaults = KeyBind_GetDefaults(); - for (i = 0; i < KEYBIND_COUNT; i++) - { - KeyBinds[i] = defaults[i]; - } - KeyBind_Load(); + KeyBind_Load("key-%c", KeyBinds_Normal, KeyBind_NormalDefaults); + KeyBind_Load("pad-%c", KeyBinds_Gamepad, KeyBind_GamepadDefaults); } @@ -904,13 +901,13 @@ static void InputHandler_CheckZoomFov(void* obj) { static cc_bool HandleBlockKey(int key) { if (Gui.InputGrab) return false; - if (key == KeyBinds[KEYBIND_DELETE_BLOCK]) { + if (KeyBind_Claims(KEYBIND_DELETE_BLOCK, key)) { MouseStatePress(MOUSE_LEFT); InputHandler_DeleteBlock(); - } else if (key == KeyBinds[KEYBIND_PLACE_BLOCK]) { + } else if (KeyBind_Claims(KEYBIND_PLACE_BLOCK, key)) { MouseStatePress(MOUSE_RIGHT); InputHandler_PlaceBlock(); - } else if (key == KeyBinds[KEYBIND_PICK_BLOCK]) { + } else if (KeyBind_Claims(KEYBIND_PICK_BLOCK, key)) { MouseStatePress(MOUSE_MIDDLE); InputHandler_PickBlock(); } else { @@ -920,32 +917,32 @@ static cc_bool HandleBlockKey(int key) { } static cc_bool HandleNonClassicKey(int key) { - if (key == KeyBinds[KEYBIND_HIDE_GUI]) { + if (KeyBind_Claims(KEYBIND_HIDE_GUI, key)) { Game_HideGui = !Game_HideGui; - } else if (key == KeyBinds[KEYBIND_SMOOTH_CAMERA]) { + } else if (KeyBind_Claims(KEYBIND_SMOOTH_CAMERA, key)) { InputHandler_Toggle(key, &Camera.Smooth, " &eSmooth camera is &aenabled", " &eSmooth camera is &cdisabled"); - } else if (key == KeyBinds[KEYBIND_AXIS_LINES]) { + } else if (KeyBind_Claims(KEYBIND_AXIS_LINES, key)) { InputHandler_Toggle(key, &AxisLinesRenderer_Enabled, " &eAxis lines (&4X&e, &2Y&e, &1Z&e) now show", " &eAxis lines no longer show"); - } else if (key == KeyBinds[KEYBIND_AUTOROTATE]) { + } else if (KeyBind_Claims(KEYBIND_AUTOROTATE, key)) { InputHandler_Toggle(key, &AutoRotate_Enabled, " &eAuto rotate is &aenabled", " &eAuto rotate is &cdisabled"); - } else if (key == KeyBinds[KEYBIND_THIRD_PERSON]) { + } else if (KeyBind_Claims(KEYBIND_THIRD_PERSON, key)) { Camera_CycleActive(); - } else if (key == KeyBinds[KEYBIND_DROP_BLOCK]) { + } else if (KeyBind_Claims(KEYBIND_DROP_BLOCK, key)) { if (Inventory_CheckChangeSelected() && Inventory_SelectedBlock != BLOCK_AIR) { /* Don't assign SelectedIndex directly, because we don't want held block switching positions if they already have air in their inventory hotbar. */ Inventory_Set(Inventory.SelectedIndex, BLOCK_AIR); Event_RaiseVoid(&UserEvents.HeldBlockChanged); } - } else if (key == KeyBinds[KEYBIND_IDOVERLAY]) { + } else if (KeyBind_Claims(KEYBIND_IDOVERLAY, key)) { TexIdsOverlay_Show(); - } else if (key == KeyBinds[KEYBIND_BREAK_LIQUIDS]) { + } else if (KeyBind_Claims(KEYBIND_BREAK_LIQUIDS, key)) { InputHandler_Toggle(key, &Game_BreakableLiquids, " &eBreakable liquids is &aenabled", " &eBreakable liquids is &cdisabled"); @@ -956,11 +953,11 @@ static cc_bool HandleNonClassicKey(int key) { } static cc_bool HandleCoreKey(int key) { - if (key == KeyBinds[KEYBIND_HIDE_FPS]) { + if (KeyBind_Claims(KEYBIND_HIDE_FPS, key)) { Gui.ShowFPS = !Gui.ShowFPS; - } else if (key == KeyBinds[KEYBIND_FULLSCREEN]) { + } else if (KeyBind_Claims(KEYBIND_FULLSCREEN, key)) { Game_ToggleFullscreen(); - } else if (key == KeyBinds[KEYBIND_FOG]) { + } else if (KeyBind_Claims(KEYBIND_FOG, key)) { Game_CycleViewDistance(); } else if (key == CCKEY_F5 && Game_ClassicMode) { int weather = Env.Weather == WEATHER_SUNNY ? WEATHER_RAINY : WEATHER_SUNNY; @@ -989,15 +986,15 @@ static void HandleHotkeyDown(int key) { } static cc_bool HandleLocalPlayerKey(int key) { - if (key == KeyBinds[KEYBIND_RESPAWN]) { + if (KeyBind_Claims(KEYBIND_RESPAWN, key)) { return LocalPlayer_HandleRespawn(); - } else if (key == KeyBinds[KEYBIND_SET_SPAWN]) { + } else if (KeyBind_Claims(KEYBIND_SET_SPAWN, key)) { return LocalPlayer_HandleSetSpawn(); - } else if (key == KeyBinds[KEYBIND_FLY]) { + } else if (KeyBind_Claims(KEYBIND_FLY, key)) { return LocalPlayer_HandleFly(); - } else if (key == KeyBinds[KEYBIND_NOCLIP]) { + } else if (KeyBind_Claims(KEYBIND_NOCLIP, key)) { return LocalPlayer_HandleNoclip(); - } else if (key == KeyBinds[KEYBIND_JUMP]) { + } else if (KeyBind_Claims(KEYBIND_JUMP, key)) { return LocalPlayer_HandleJump(); } return false; @@ -1091,7 +1088,7 @@ static void OnInputDown(void* obj, int key, cc_bool was) { if (InputHandler_IsShutdown(key)) { /* TODO: Do we need a separate exit function in Game class? */ Window_Close(); return; - } else if (key == KeyBinds[KEYBIND_SCREENSHOT] && !was) { + } else if (KeyBind_Claims(KEYBIND_SCREENSHOT, key) && !was) { Game_ScreenshotRequested = true; return; } @@ -1101,7 +1098,7 @@ static void OnInputDown(void* obj, int key, cc_bool was) { if (s->VTABLE->HandlesInputDown(s, key)) return; } - if ((Input_IsEscapeButton(key) || key == CCKEY_PAUSE) && !Gui.InputGrab) { + if (Input_IsPauseButton(key) && !Gui.InputGrab) { #ifdef CC_BUILD_WEB /* Can't do this in KeyUp, because pressing escape without having */ /* explicitly disabled mouse lock means a KeyUp event isn't sent. */ @@ -1125,7 +1122,7 @@ static void OnInputUp(void* obj, int key) { struct Screen* s; int i; - if (key == KeyBinds[KEYBIND_ZOOM_SCROLL]) Camera_SetFov(Camera.DefaultFov); + if (KeyBind_Claims(KEYBIND_ZOOM_SCROLL, key)) Camera_SetFov(Camera.DefaultFov); #ifdef CC_BUILD_WEB /* When closing menus (which reacquires mouse focus) in key down, */ /* this still leaves the cursor visible. But if this is instead */ @@ -1143,9 +1140,9 @@ static void OnInputUp(void* obj, int key) { } if (Gui.InputGrab) return; - if (key == KeyBinds[KEYBIND_DELETE_BLOCK]) MouseStateRelease(MOUSE_LEFT); - if (key == KeyBinds[KEYBIND_PLACE_BLOCK]) MouseStateRelease(MOUSE_RIGHT); - if (key == KeyBinds[KEYBIND_PICK_BLOCK]) MouseStateRelease(MOUSE_MIDDLE); + if (KeyBind_Claims(KEYBIND_DELETE_BLOCK, key)) MouseStateRelease(MOUSE_LEFT); + if (KeyBind_Claims(KEYBIND_PLACE_BLOCK, key)) MouseStateRelease(MOUSE_RIGHT); + if (KeyBind_Claims(KEYBIND_PICK_BLOCK, key)) MouseStateRelease(MOUSE_MIDDLE); } static void OnFocusChanged(void* obj) { if (!WindowInfo.Focused) Input_Clear(); } diff --git a/src/Input.h b/src/Input.h index 82891f5b1..8fc789b07 100644 --- a/src/Input.h +++ b/src/Input.h @@ -62,14 +62,17 @@ extern struct _InputState { cc_bool Pressed[INPUT_COUNT]; /* Whether raw mouse/touch input is currently being listened for */ cc_bool RawMode; - /* Whether a gamepad is available as an input source */ - cc_bool GamepadSource; + /* Sources available for input (Mouse/Keyboard, Gamepad) */ + cc_uint8 Sources; /* Whether a gamepad joystick is being used to control player movement */ cc_bool JoystickMovement; /* Angle of the gamepad joystick being used to control player movement */ float JoystickAngle; } Input; +#define INPUT_SOURCE_NORMAL (1 << 0) +#define INPUT_SOURCE_GAMEPAD (1 << 1) + /* Sets Input_Pressed[key] to true and raises InputEvents.Down */ void Input_SetPressed(int key); /* Sets Input_Pressed[key] to false and raises InputEvents.Up */ @@ -90,7 +93,9 @@ void Input_Clear(void); #define Input_IsDownButton(btn) ((btn) == CCKEY_DOWN || (btn) == CCPAD_DOWN) #define Input_IsLeftButton(btn) ((btn) == CCKEY_LEFT || (btn) == CCPAD_LEFT) #define Input_IsRightButton(btn) ((btn) == CCKEY_RIGHT || (btn) == CCPAD_RIGHT) + #define Input_IsEnterButton(btn) ((btn) == CCKEY_ENTER || (btn) == CCPAD_START || (btn) == CCKEY_KP_ENTER) +#define Input_IsPauseButton(btn) ((btn) == CCKEY_ESCAPE || (btn) == CCPAD_START || (btn) == CCKEY_PAUSE) #define Input_IsEscapeButton(btn) ((btn) == CCKEY_ESCAPE || (btn) == CCPAD_SELECT) #if defined CC_BUILD_HAIKU @@ -159,18 +164,22 @@ enum KeyBind_ { }; typedef int KeyBind; -/* The keys that are bound to each key binding. */ -extern cc_uint8 KeyBinds[KEYBIND_COUNT]; +/* The keyboard/mouse buttons that are bound to each key binding */ +extern cc_uint8 KeyBinds_Normal[KEYBIND_COUNT]; +/* The gamepad buttons that are bound to each key binding */ +extern cc_uint8 KeyBinds_Gamepad[KEYBIND_COUNT]; /* Default keyboard/mouse button that each key binding is bound to */ extern const cc_uint8 KeyBind_NormalDefaults[KEYBIND_COUNT]; /* Default gamepad button that each key binding is bound to */ extern const cc_uint8 KeyBind_GamepadDefaults[KEYBIND_COUNT]; #define KeyBind_GetDefaults() (Input.GamepadSource ? KeyBind_GamepadDefaults : KeyBind_NormalDefaults) +/* Whether the given keyboard/mouse or gamepad button is bound to the given keybinding */ +#define KeyBind_Claims(binding, btn) (KeyBinds_Normal[binding] == (btn) || KeyBinds_Gamepad[binding] == (btn)) /* Gets whether the key bound to the given key binding is pressed. */ CC_API cc_bool KeyBind_IsPressed(KeyBind binding); /* Set the key that the given key binding is bound to. (also updates options list) */ -void KeyBind_Set(KeyBind binding, int key); +void KeyBind_Set(KeyBind binding, int key, cc_uint8* binds); /* whether to leave text input open for user to enter further input */ #define HOTKEY_FLAG_STAYS_OPEN 0x01 diff --git a/src/LScreens.c b/src/LScreens.c index eaa4f5808..d65634f0e 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -20,8 +20,8 @@ #include "Http.h" #define LAYOUTS static const struct LLayout -#define IsEnterButton(btn) (Input_IsEnterButton(btn) || btn == CCPAD_A) -#define IsEscapeButton(btn) (Input_IsEscapeButton(btn) || btn == CCPAD_B) +#define IsEnterButton(btn) (btn == CCKEY_ENTER || btn == CCPAD_START || btn == CCPAD_A || btn == CCKEY_KP_ENTER) +#define IsBackButton(btn) (btn == CCKEY_ESCAPE || btn == CCPAD_SELECT || btn == CCPAD_B) /*########################################################################################################################* *---------------------------------------------------------Screen base-----------------------------------------------------* @@ -109,7 +109,7 @@ static void LScreen_KeyDown(struct LScreen* s, int key, cc_bool was) { LScreen_CycleSelected(s, -1); } else if (Input_IsDownButton(key)) { LScreen_CycleSelected(s, 1); - } else if (IsEscapeButton(key) && s->onEscapeWidget) { + } else if (IsBackButton(key) && s->onEscapeWidget) { s->onEscapeWidget->OnClick(s->onEscapeWidget); } } diff --git a/src/Menus.c b/src/Menus.c index 64422954c..e0ee1965c 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -209,6 +209,7 @@ static void Menu_SwitchBindsHacks(void* a, void* b) { HacksBindingsScreen static void Menu_SwitchBindsOther(void* a, void* b) { OtherBindingsScreen_Show(); } static void Menu_SwitchBindsMouse(void* a, void* b) { MouseBindingsScreen_Show(); } static void Menu_SwitchBindsHotbar(void* a, void* b) { HotbarBindingsScreen_Show(); } +static void SwitchBindsMain(void* s, void* w); static void Menu_SwitchMisc(void* a, void* b) { MiscOptionsScreen_Show(); } static void Menu_SwitchChat(void* a, void* b) { ChatOptionsScreen_Show(); } @@ -696,7 +697,7 @@ static const struct SimpleButtonDesc optsGroup_btns[8] = { { -160, -100, "Misc options...", Menu_SwitchMisc }, { -160, -50, "Gui options...", Menu_SwitchGui }, { -160, 0, "Graphics options...", Menu_SwitchGfx }, - { -160, 50, "Controls...", Menu_SwitchBindsNormal }, + { -160, 50, "Controls...", SwitchBindsMain }, { 160, -100, "Chat options...", Menu_SwitchChat }, { 160, -50, "Hacks settings...", Menu_SwitchHacks }, { 160, 0, "Env settings...", Menu_SwitchEnv }, @@ -1812,6 +1813,93 @@ void LoadLevelScreen_Show(void) { } + +/*########################################################################################################################* +*----------------------------------------------------EditHotkeyScreen-----------------------------------------------------* +*#########################################################################################################################*/ +static struct BindsSourceScreen { + Screen_Body + struct ButtonWidget btns[2], cancel; +} BindsSourceScreen; +static int binds_gamepad; /* Default to Normal (Keyboard/Mouse) */ + +static struct Widget* bindsSource_widgets[] = { + (struct Widget*)&BindsSourceScreen.btns[0], (struct Widget*)&BindsSourceScreen.btns[1], + (struct Widget*)&BindsSourceScreen.cancel +}; +#define BINDSSOURCE_MAX_VERTICES (BUTTONWIDGET_MAX * 3) + +static void BindsSourceScreen_ModeNormal(void* screen, void* b) { + binds_gamepad = false; + NormalBindingsScreen_Show(); +} + +static void BindsSourceScreen_ModeGamepad(void* screen, void* b) { + binds_gamepad = true; + NormalBindingsScreen_Show(); +} + +static void BindsSourceScreen_ContextRecreated(void* screen) { + struct BindsSourceScreen* s = (struct BindsSourceScreen*)screen; + struct FontDesc font; + Gui_MakeTitleFont(&font); + Screen_UpdateVb(screen); + + ButtonWidget_SetConst(&s->btns[0], "Keyboard/Mouse", &font); + ButtonWidget_SetConst(&s->btns[1], "Gamepad/Controller", &font); + ButtonWidget_SetConst(&s->cancel, "Cancel", &font); + Font_Free(&font); +} + +static void BindsSourceScreen_Layout(void* screen) { + struct BindsSourceScreen* s = (struct BindsSourceScreen*)screen; + Widget_SetLocation(&s->btns[0], ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -25); + Widget_SetLocation(&s->btns[1], ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 25); + Menu_LayoutBack(&s->cancel); +} + +static void BindsSourceScreen_Init(void* screen) { + struct BindsSourceScreen* s = (struct BindsSourceScreen*)screen; + + s->widgets = bindsSource_widgets; + s->numWidgets = Array_Elems(bindsSource_widgets); + s->selectedI = -1; + s->maxVertices = BINDSSOURCE_MAX_VERTICES; + + ButtonWidget_Init(&s->btns[0], 300, BindsSourceScreen_ModeNormal); + ButtonWidget_Init(&s->btns[1], 300, BindsSourceScreen_ModeGamepad); + ButtonWidget_Init(&s->cancel, 400, Menu_SwitchPause); +} + +static const struct ScreenVTABLE BindsSourceScreen_VTABLE = { + BindsSourceScreen_Init, Screen_NullUpdate, Screen_NullFunc, + MenuScreen_Render2, Screen_BuildMesh, + Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, + Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, + BindsSourceScreen_Layout, Screen_ContextLost, BindsSourceScreen_ContextRecreated +}; +void BindsSourceScreen_Show(void) { + struct BindsSourceScreen* s = &BindsSourceScreen; + s->grabsInput = true; + s->closable = true; + s->VTABLE = &BindsSourceScreen_VTABLE; + Gui_Add((struct Screen*)s, GUI_PRIORITY_MENU); +} + +static void SwitchBindsMain(void* s, void* w) { + if (Input.Sources == (INPUT_SOURCE_NORMAL | INPUT_SOURCE_GAMEPAD)) { + /* User needs to decide whether to configure mouse/keyboard or gamepad */ + BindsSourceScreen_Show(); + } else if (Input.Sources == INPUT_SOURCE_GAMEPAD) { + binds_gamepad = true; + NormalBindingsScreen_Show(); + } else { + binds_gamepad = false; + NormalBindingsScreen_Show(); + } +} + + /*########################################################################################################################* *---------------------------------------------------KeyBindsScreen-----------------------------------------------------* *#########################################################################################################################*/ @@ -1844,10 +1932,13 @@ static struct Widget* key_widgets[KEYBINDS_MAX_BTNS + 5] = { static void KeyBindsScreen_Update(struct KeyBindsScreen* s, int i) { cc_string text; char textBuffer[STRING_SIZE]; + const cc_uint8* curBinds; + String_InitArray(text, textBuffer); + curBinds = binds_gamepad ? KeyBinds_Gamepad : KeyBinds_Normal; String_Format2(&text, s->curI == i ? "> %c: %c <" : "%c: %c", - s->descs[i], Input_DisplayNames[KeyBinds[s->binds[i]]]); + s->descs[i], Input_DisplayNames[curBinds[s->binds[i]]]); ButtonWidget_Set(&s->buttons[i], &text, &s->titleFont); s->dirty = true; } @@ -1866,15 +1957,17 @@ static void KeyBindsScreen_OnBindingClick(void* screen, void* widget) { static int KeyBindsScreen_KeyDown(void* screen, int key) { struct KeyBindsScreen* s = (struct KeyBindsScreen*)screen; const cc_uint8* defaults; + cc_uint8* curBinds; KeyBind bind; int idx; if (s->curI == -1) return Menu_InputDown(s, key); - defaults = KeyBind_GetDefaults(); + curBinds = binds_gamepad ? KeyBinds_Gamepad : KeyBinds_Normal; + defaults = binds_gamepad ? KeyBind_GamepadDefaults : KeyBind_NormalDefaults; bind = s->binds[s->curI]; if (Input_IsEscapeButton(key)) key = defaults[bind]; - KeyBind_Set(bind, key); + KeyBind_Set(bind, key, curBinds); idx = s->curI; s->curI = -1; @@ -2000,7 +2093,8 @@ static void KeyBindsScreen_Show(int bindsCount, const cc_uint8* binds, const cha void ClassicBindingsScreen_Show(void) { static const cc_uint8 binds[] = { KEYBIND_FORWARD, KEYBIND_BACK, KEYBIND_JUMP, KEYBIND_CHAT, KEYBIND_SET_SPAWN, KEYBIND_LEFT, KEYBIND_RIGHT, KEYBIND_INVENTORY, KEYBIND_FOG, KEYBIND_RESPAWN }; static const char* const descs[] = { "Forward", "Back", "Jump", "Chat", "Save location", "Left", "Right", "Build", "Toggle fog", "Load location" }; - + binds_gamepad = false; + if (Game_ClassicHacks) { KeyBindsScreen_Reset(NULL, Menu_SwitchBindsClassicHacks, 260); } else { @@ -2018,6 +2112,7 @@ void ClassicBindingsScreen_Show(void) { void ClassicHacksBindingsScreen_Show(void) { static const cc_uint8 binds[6] = { KEYBIND_SPEED, KEYBIND_NOCLIP, KEYBIND_HALF_SPEED, KEYBIND_FLY, KEYBIND_FLY_UP, KEYBIND_FLY_DOWN }; static const char* const descs[6] = { "Speed", "Noclip", "Half speed", "Fly", "Fly up", "Fly down" }; + binds_gamepad = false; KeyBindsScreen_Reset(Menu_SwitchBindsClassic, NULL, 260); KeyBindsScreen_SetLayout(-90, -40, 3); @@ -3582,7 +3677,7 @@ static void TexIdsOverlay_Render(void* screen, double delta) { static int TexIdsOverlay_KeyDown(void* screen, int key) { struct Screen* s = (struct Screen*)screen; - if (key == KeyBinds[KEYBIND_IDOVERLAY]) { Gui_Remove(s); return true; } + if (KeyBind_Claims(KEYBIND_IDOVERLAY, key)) { Gui_Remove(s); return true; } return false; } diff --git a/src/Program.c b/src/Program.c index e16043dbb..96e7b55f6 100644 --- a/src/Program.c +++ b/src/Program.c @@ -77,8 +77,8 @@ static int RunProgram(int argc, char** argv) { #ifdef _MSC_VER /* NOTE: Make sure to comment this out before pushing a commit */ //cc_string rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565"); - //cc_string rawArgs = String_FromConst("UnknownShadow200"); - //argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4); + cc_string rawArgs = String_FromConst("UnknownShadow200"); + argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4); #endif if (argsCount == 0) { diff --git a/src/Screens.c b/src/Screens.c index 1acc13574..e4d5e2c76 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -708,7 +708,7 @@ static int TabListOverlay_PointerDown(void* screen, int id, int x, int y) { static void TabListOverlay_KeyUp(void* screen, int key) { struct TabListOverlay* s = (struct TabListOverlay*)screen; - if (key != KeyBinds[KEYBIND_TABLIST] || s->staysOpen) return; + if (!KeyBind_Claims(KEYBIND_TABLIST, key) || s->staysOpen) return; Gui_Remove((struct Screen*)s); } @@ -1206,10 +1206,10 @@ static int ChatScreen_TextChanged(void* screen, const cc_string* str) { static int ChatScreen_KeyDown(void* screen, int key) { static const cc_string slash = String_FromConst("/"); struct ChatScreen* s = (struct ChatScreen*)screen; - int playerListKey = KeyBinds[KEYBIND_TABLIST]; - cc_bool handlesList = playerListKey != CCKEY_TAB || !Gui.TabAutocomplete || !s->grabsInput; + int playerListKey = KeyBinds_Normal[KEYBIND_TABLIST]; + cc_bool handlesList = playerListKey != CCKEY_TAB || !Gui.TabAutocomplete || !s->grabsInput; - if (key == playerListKey && handlesList) { + if (KeyBind_Claims(KEYBIND_TABLIST, key) && handlesList) { if (!tablist_active && !Server.IsSinglePlayer) { TabListOverlay_Show(); } @@ -1221,10 +1221,10 @@ static int ChatScreen_KeyDown(void* screen, int key) { if (s->grabsInput) { #ifdef CC_BUILD_WEB /* See reason for this in HandleInputUp */ - if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == CCKEY_KP_ENTER) { + if (KeyBind_Claims(KEYBIND_SEND_CHAT, key) || key == CCKEY_KP_ENTER) { ChatScreen_EnterChatInput(s, false); #else - if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == CCKEY_KP_ENTER || Input_IsEscapeButton(key)) { + if (KeyBind_Claims(KEYBIND_SEND_CHAT, key) || key == CCKEY_KP_ENTER || Input_IsEscapeButton(key)) { ChatScreen_EnterChatInput(s, Input_IsEscapeButton(key)); #endif } else if (key == CCKEY_PAGEUP) { @@ -1237,11 +1237,11 @@ static int ChatScreen_KeyDown(void* screen, int key) { return key < CCKEY_F1 || key > CCKEY_F24; } - if (key == KeyBinds[KEYBIND_CHAT]) { + if (KeyBind_Claims(KEYBIND_CHAT, key)) { ChatScreen_OpenInput(&String_Empty); } else if (key == CCKEY_SLASH) { ChatScreen_OpenInput(&slash); - } else if (key == KeyBinds[KEYBIND_INVENTORY]) { + } else if (KeyBind_Claims(KEYBIND_INVENTORY, key)) { InventoryScreen_Show(); } else { return false; @@ -1263,7 +1263,7 @@ static void ChatScreen_KeyUp(void* screen, int key) { if (key == CCKEY_ESCAPE) ChatScreen_EnterChatInput(s, true); #endif - if (Server.SupportsFullCP437 && key == KeyBinds[KEYBIND_EXT_INPUT]) { + if (Server.SupportsFullCP437 && KeyBind_Claims(KEYBIND_EXT_INPUT, key)) { if (!WindowInfo.Focused) return; ChatScreen_ToggleAltInput(s); } @@ -1592,7 +1592,7 @@ static int InventoryScreen_KeyDown(void* screen, int key) { struct InventoryScreen* s = (struct InventoryScreen*)screen; struct TableWidget* table = &s->table; - if (key == KeyBinds[KEYBIND_INVENTORY] && s->releasedInv) { + if (KeyBind_Claims(KEYBIND_INVENTORY, key) && s->releasedInv) { Gui_Remove((struct Screen*)s); } else if (Input_IsEnterButton(key) && table->selectedIndex != -1) { Inventory_SetSelectedBlock(table->blocks[table->selectedIndex]); @@ -1612,7 +1612,7 @@ static cc_bool InventoryScreen_IsHotbarActive(void) { static void InventoryScreen_KeyUp(void* screen, int key) { struct InventoryScreen* s = (struct InventoryScreen*)screen; - if (key == KeyBinds[KEYBIND_INVENTORY]) s->releasedInv = true; + if (KeyBind_Claims(KEYBIND_INVENTORY, key)) s->releasedInv = true; } static int InventoryScreen_PointerDown(void* screen, int id, int x, int y) { @@ -2151,7 +2151,7 @@ static void TouchScreen_HalfClick(void* s, void* w) { static void TouchScreen_BindClick(void* screen, void* widget) { struct TouchScreen* s = (struct TouchScreen*)screen; int i = Screen_Index(screen, widget) - ONSCREEN_MAX_BTNS; - Input_Set(KeyBinds[s->descs[i].bind], true); + Input_Set(KeyBinds_Normal[s->descs[i].bind], true); } static const struct TouchButtonDesc onscreenDescs[ONSCREEN_MAX_BTNS] = { @@ -2283,7 +2283,7 @@ static void TouchScreen_PointerUp(void* screen, int id, int x, int y) { if (!(s->btns[i].active & id)) continue; if (s->descs[i].bind < KEYBIND_COUNT) { - Input_Set(KeyBinds[s->descs[i].bind], false); + Input_Set(KeyBinds_Normal[s->descs[i].bind], false); } s->btns[i].active &= ~id; return; diff --git a/src/Widgets.c b/src/Widgets.c index aa660b48f..c999a0a5d 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -512,7 +512,7 @@ static int HotbarWidget_MapKey(int key) { int i; for (i = 0; i < INVENTORY_BLOCKS_PER_HOTBAR; i++) { - if (key == KeyBinds[KEYBIND_HOTBAR_1 + i]) return i; + if (KeyBind_Claims(KEYBIND_HOTBAR_1 + i, key)) return i; } return -1; } @@ -532,9 +532,9 @@ static int HotbarWidget_KeyDown(void* widget, int key) { int index = HotbarWidget_MapKey(key); if (index == -1) { - if (key == KeyBinds[KEYBIND_HOTBAR_LEFT]) + if (KeyBind_Claims(KEYBIND_HOTBAR_LEFT, key)) return HotbarWidget_CycleIndex(-1); - if (key == KeyBinds[KEYBIND_HOTBAR_RIGHT]) + if (KeyBind_Claims(KEYBIND_HOTBAR_RIGHT, key)) return HotbarWidget_CycleIndex(+1); return false; } @@ -555,7 +555,7 @@ static void HotbarWidget_InputUp(void* widget, int key) { a) user presses alt then number b) user presses alt We only do case b) if case a) did not happen */ - if (key != KeyBinds[KEYBIND_HOTBAR_SWITCH]) return; + if (!KeyBind_Claims(KEYBIND_HOTBAR_SWITCH, key)) return; if (w->altHandled) { w->altHandled = false; return; } /* handled already */ /* Don't switch hotbar when alt+tabbing to another window */ diff --git a/src/Window_3DS.c b/src/Window_3DS.c index 66f382db6..9be979e10 100644 --- a/src/Window_3DS.c +++ b/src/Window_3DS.c @@ -50,8 +50,8 @@ void Window_Init(void) { WindowInfo.Focused = true; WindowInfo.Exists = true; - Input.GamepadSource = true; - irrst_result = irrstInit(); + Input.Sources = INPUT_SOURCE_GAMEPAD; + irrst_result = irrstInit(); } void Window_Create2D(int width, int height) { launcherMode = true; } diff --git a/src/Window_Dreamcast.c b/src/Window_Dreamcast.c index 61fbd5f2b..35ad02573 100644 --- a/src/Window_Dreamcast.c +++ b/src/Window_Dreamcast.c @@ -31,7 +31,7 @@ void Window_Init(void) { WindowInfo.Focused = true; WindowInfo.Exists = true; - Input.GamepadSource = true; + Input.Sources = INPUT_SOURCE_GAMEPAD; } void Window_Create2D(int width, int height) { diff --git a/src/Window_GCWii.c b/src/Window_GCWii.c index 4603698a5..03de52098 100644 --- a/src/Window_GCWii.c +++ b/src/Window_GCWii.c @@ -72,7 +72,7 @@ void Window_Init(void) { WindowInfo.Focused = true; WindowInfo.Exists = true; - Input.GamepadSource = true; + Input.Sources = INPUT_SOURCE_GAMEPAD; #if defined HW_RVL WPAD_Init(); WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC_IR); @@ -259,14 +259,14 @@ static void ProcessNunchuck_Game(int mods, double delta) { Input_SetNonRepeatable(CCPAD_START, mods & WPAD_BUTTON_HOME); Input_SetNonRepeatable(CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); - Input_SetNonRepeatable(KeyBinds[KEYBIND_FLY], mods & WPAD_BUTTON_LEFT); + Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_FLY], mods & WPAD_BUTTON_LEFT); if (mods & WPAD_BUTTON_RIGHT) { Mouse_ScrollWheel(1.0*delta); } - Input_SetNonRepeatable(KeyBinds[KEYBIND_THIRD_PERSON], mods & WPAD_BUTTON_UP); - Input_SetNonRepeatable(KeyBinds[KEYBIND_FLY_DOWN], mods & WPAD_BUTTON_DOWN); + Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_THIRD_PERSON], mods & WPAD_BUTTON_UP); + Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_FLY_DOWN], mods & WPAD_BUTTON_DOWN); const float ANGLE_DELTA = 50; bool nunchuckUp = (analog.ang > -ANGLE_DELTA) && (analog.ang < ANGLE_DELTA) && (analog.mag > 0.5); diff --git a/src/Window_PSP.c b/src/Window_PSP.c index 3c463f49f..cad37b32e 100644 --- a/src/Window_PSP.c +++ b/src/Window_PSP.c @@ -37,7 +37,7 @@ void Window_Init(void) { WindowInfo.Focused = true; WindowInfo.Exists = true; - Input.GamepadSource = true; + Input.Sources = INPUT_SOURCE_GAMEPAD; sceCtrlSetSamplingCycle(0); sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG); } diff --git a/src/Window_PSVita.c b/src/Window_PSVita.c index 33fd234fe..b5e10b82b 100644 --- a/src/Window_PSVita.c +++ b/src/Window_PSVita.c @@ -37,7 +37,7 @@ void Window_Init(void) { WindowInfo.Focused = true; WindowInfo.Exists = true; - Input.GamepadSource = true; + Input.Sources = INPUT_SOURCE_GAMEPAD; sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG); sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START); sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START); diff --git a/src/Window_Web.c b/src/Window_Web.c index 8ffc96614..237c2baa8 100644 --- a/src/Window_Web.c +++ b/src/Window_Web.c @@ -513,9 +513,7 @@ void Window_Close(void) { } extern void interop_RequestCanvasResize(void); -void Window_ProcessEvents(double delta) { - if (!needResize) return; - needResize = false; +static void ProcessPendingResize(void) { if (!WindowInfo.Exists) return; if (Window_GetWindowState() == WINDOW_STATE_FULLSCREEN) { @@ -527,6 +525,49 @@ void Window_ProcessEvents(double delta) { UpdateWindowBounds(); } +#define GetGamePadButton(i) i < numButtons ? ev->digitalButton[i] : 0 +static void ProcessGamePadInput(EmscriptenGamepadEvent* ev) { + int numButtons = ev->numButtons; + Input.Sources |= INPUT_SOURCE_GAMEPAD; + /* https://www.w3.org/TR/gamepad/#dfn-standard-gamepad */ + + Input_SetNonRepeatable(CCPAD_A, GetGamePadButton(0)); + Input_SetNonRepeatable(CCPAD_B, GetGamePadButton(1)); + Input_SetNonRepeatable(CCPAD_X, GetGamePadButton(2)); + Input_SetNonRepeatable(CCPAD_Y, GetGamePadButton(3)); + + Input_SetNonRepeatable(CCPAD_L, GetGamePadButton(4)); + Input_SetNonRepeatable(CCPAD_R, GetGamePadButton(5)); + + Input_SetNonRepeatable(CCPAD_SELECT, GetGamePadButton(8)); + Input_SetNonRepeatable(CCPAD_START, GetGamePadButton(9)); + + Input_SetNonRepeatable(CCPAD_UP, GetGamePadButton(12)); + Input_SetNonRepeatable(CCPAD_DOWN, GetGamePadButton(13)); + Input_SetNonRepeatable(CCPAD_LEFT, GetGamePadButton(14)); + Input_SetNonRepeatable(CCPAD_RIGHT, GetGamePadButton(15)); +} + +void Window_ProcessEvents(double delta) { + int i, res, count; + Input.Sources = INPUT_SOURCE_NORMAL; + + if (emscripten_sample_gamepad_data() == 0) { + count = emscripten_get_num_gamepads(); + + for (i = 0; i < count; i++) + { + EmscriptenGamepadEvent ev; + res = emscripten_get_gamepad_status(i, &ev); + if (res == 0) ProcessGamePadInput(&ev); + } + } + + if (!needResize) return; + needResize = false; + ProcessPendingResize(); +} + /* Not needed because browser provides relative mouse and touch events */ static void Cursor_GetRawPos(int* x, int* y) { *x = 0; *y = 0; } /* Not allowed to move cursor from javascript */ diff --git a/src/Window_Xbox.c b/src/Window_Xbox.c index 185033d07..700c5cd53 100644 --- a/src/Window_Xbox.c +++ b/src/Window_Xbox.c @@ -75,7 +75,7 @@ void Window_Init(void) { WindowInfo.Focused = true; WindowInfo.Exists = true; - Input.GamepadSource = true; + Input.Sources = INPUT_SOURCE_GAMEPAD; usbh_core_init(); usbh_xid_init();