diff --git a/src/Input.c b/src/Input.c index 1b22b32dd..999457f64 100644 --- a/src/Input.c +++ b/src/Input.c @@ -272,9 +272,11 @@ static cc_bool NormDevice_IsPressed(struct InputDevice* device, int key) { return Input.Pressed[key]; } -static cc_bool PadDevice_IsPressed(struct InputDevice* device, int key) { +static cc_bool PadDevice_IsPressed(struct InputDevice* device, int key) { + struct GamepadDevice* gamepad = (struct GamepadDevice*)device; if (!Input_IsPadButton(key)) return false; - return Gamepad_States[device->index].pressed[key - GAMEPAD_BEG_BTN]; + + return gamepad->pressed[key - GAMEPAD_BEG_BTN]; } static cc_bool TouchDevice_IsPressed(struct InputDevice* device, int key) { @@ -293,9 +295,9 @@ struct InputDevice NormDevice = { /* Launcher buttons */ CCKEY_TAB, /* Bindings */ - "key-%c", NULL, NULL + "key-%c", KeyBind_Defaults, KeyBind_Mappings }; -struct InputDevice PadDevice = { +static const struct InputDevice padDevice = { INPUT_DEVICE_GAMEPAD, 0, PadDevice_IsPressed, /* General buttons */ @@ -307,7 +309,7 @@ struct InputDevice PadDevice = { /* Launcher buttons */ CCPAD_3, /* Bindings */ - "pad-%c", NULL, NULL + "pad-%c", PadBind_Defaults, PadBind_Mappings }; struct InputDevice TouchDevice = { INPUT_DEVICE_TOUCH, 0, @@ -378,21 +380,20 @@ int Gamepad_AxisBehaviour[2] = { AXIS_BEHAVIOUR_MOVEMENT, AXIS_BEHAVIOUR_CAMER int Gamepad_AxisSensitivity[2] = { AXIS_SENSI_NORMAL, AXIS_SENSI_NORMAL }; static const float axis_sensiFactor[] = { 0.25f, 0.5f, 1.0f, 2.0f, 4.0f }; -struct GamepadState Gamepad_States[INPUT_MAX_GAMEPADS]; +struct GamepadDevice Gamepad_Devices[INPUT_MAX_GAMEPADS]; static void Gamepad_Apply(int port, int btn, cc_bool was, int pressed) { - struct InputDevice device = PadDevice; - device.index = port; - + struct InputDevice* device = &Gamepad_Devices[port].base; + if (pressed) { - Event_RaiseInput(&InputEvents.Down, btn + GAMEPAD_BEG_BTN, was, &device); + Event_RaiseInput(&InputEvents.Down, btn + GAMEPAD_BEG_BTN, was, device); } else { - Event_RaiseInput(&InputEvents.Up, btn + GAMEPAD_BEG_BTN, was, &device); + Event_RaiseInput(&InputEvents.Up, btn + GAMEPAD_BEG_BTN, was, device); } } static void Gamepad_Update(int port, float delta) { - struct GamepadState* pad = &Gamepad_States[port]; + struct GamepadDevice* pad = &Gamepad_Devices[port]; int btn; for (btn = 0; btn < GAMEPAD_BTN_COUNT; btn++) @@ -408,7 +409,7 @@ static void Gamepad_Update(int port, float delta) { } void Gamepad_SetButton(int port, int btn, int pressed) { - struct GamepadState* pad = &Gamepad_States[port]; + struct GamepadDevice* pad = &Gamepad_Devices[port]; btn -= GAMEPAD_BEG_BTN; /* Repeat down is handled in Gamepad_Update instead */ if (pressed && pad->pressed[btn]) return; @@ -421,8 +422,8 @@ void Gamepad_SetButton(int port, int btn, int pressed) { } void Gamepad_SetAxis(int port, int axis, float x, float y, float delta) { - Gamepad_States[port].axisX[axis] = x; - Gamepad_States[port].axisY[axis] = y; + Gamepad_Devices[port].axisX[axis] = x; + Gamepad_Devices[port].axisY[axis] = y; if (x == 0 && y == 0) return; int sensi = Gamepad_AxisSensitivity[axis]; @@ -445,10 +446,10 @@ int Gamepad_MapPort(long deviceID) { for (port = 0; port < INPUT_MAX_GAMEPADS; port++) { - if (Gamepad_States[port].deviceID == deviceID) return port; + if (Gamepad_Devices[port].deviceID == deviceID) return port; - if (Gamepad_States[port].deviceID != 0) continue; - Gamepad_States[port].deviceID = deviceID; + if (Gamepad_Devices[port].deviceID != 0) continue; + Gamepad_Devices[port].deviceID = deviceID; return port; } @@ -457,16 +458,163 @@ int Gamepad_MapPort(long deviceID) { } +/*########################################################################################################################* +*---------------------------------------------------------Keybinds--------------------------------------------------------* +*#########################################################################################################################*/ +BindMapping PadBind_Mappings[BIND_COUNT]; +BindMapping KeyBind_Mappings[BIND_COUNT]; + +const BindMapping PadBind_Defaults[BIND_COUNT] = { + { CCPAD_UP, 0 }, { CCPAD_DOWN, 0 }, /* BIND_FORWARD, BIND_BACK */ + { CCPAD_LEFT, 0 }, { CCPAD_RIGHT, 0 }, /* BIND_LEFT, BIND_RIGHT */ + { CCPAD_1, 0 }, { 0, 0 }, /* BIND_JUMP, BIND_RESPAWN */ + { CCPAD_START, 0 }, { CCPAD_4, 0 }, /* BIND_SET_SPAWN, BIND_CHAT */ + { CCPAD_3, 0 }, { 0, 0 }, /* BIND_INVENTORY, BIND_FOG */ + { CCPAD_START, 0 }, { 0, 0 }, /* BIND_SEND_CHAT, BIND_TABLIST */ + { CCPAD_2, CCPAD_L},{ CCPAD_2, CCPAD_3},/* BIND_SPEED, BIND_NOCLIP */ + { CCPAD_2, CCPAD_R }, /* BIND_FLY */ + {CCPAD_2,CCPAD_UP},{CCPAD_2,CCPAD_DOWN},/* BIND_FLY_UP, BIND_FLY_DOWN */ + { 0, 0 }, { 0, 0 }, /* BIND_EXT_INPUT, BIND_HIDE_FPS */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_SCREENSHOT, BIND_FULLSCREEN, BIND_THIRD_PERSON, BIND_HIDE_GUI */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_AXIS_LINES, BIND_ZOOM_SCROLL, BIND_HALF_SPEED */ + { CCPAD_L, 0 }, { 0, 0 },{ CCPAD_R, 0 },/* BIND_DELETE_BLOCK, BIND_PICK_BLOCK, BIND_PLACE_BLOCK */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_AUTOROTATE, BIND_HOTBAR_SWITCH, BIND_SMOOTH_CAMERA */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_DROP_BLOCK, BIND_IDOVERLAY, BIND_BREAK_LIQUIDS */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_LOOK_UP, BIND_LOOK_DOWN, BIND_LOOK_RIGHT, BIND_LOOK_LEFT */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_HOTBAR_1, BIND_HOTBAR_2, BIND_HOTBAR_3 */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_HOTBAR_4, BIND_HOTBAR_5, BIND_HOTBAR_6 */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_HOTBAR_7, BIND_HOTBAR_8, BIND_HOTBAR_9 */ + { CCPAD_ZL, 0 }, { CCPAD_ZR, 0 } /* BIND_HOTBAR_LEFT, BIND_HOTBAR_RIGHT */ +}; + +const BindMapping KeyBind_Defaults[BIND_COUNT] = { + { 'W', 0 }, { 'S', 0 }, { 'A', 0 }, { 'D', 0 }, /* BIND_FORWARD - BIND_RIGHT */ + { CCKEY_SPACE, 0 }, { 'R', 0 }, /* BIND_JUMP, BIND_RESPAWN */ + { CCKEY_ENTER, 0 }, { 'T', 0 }, /* BIND_SET_SPAWN, BIND_CHAT */ + { 'B', 0 }, { 'F', 0 }, /* BIND_INVENTORY, BIND_FOG */ + { CCKEY_ENTER, 0 }, { CCKEY_TAB, 0 }, /* BIND_SEND_CHAT, BIND_TABLIST */ + { CCKEY_LSHIFT, 0 }, { 'X', 0}, { 'Z', 0 }, /* BIND_SPEED, BIND_NOCLIP, BIND_FLY */ + { 'Q', 0 }, { 'E', 0 }, /* BIND_FLY_UP, BIND_FLY_DOWN */ + { CCKEY_LALT, 0 }, { CCKEY_F3, 0 }, /* BIND_EXT_INPUT, BIND_HIDE_FPS */ + { CCKEY_F12, 0 }, { CCKEY_F11, 0 }, /* BIND_SCREENSHOT, BIND_FULLSCREEN */ + { CCKEY_F5, 0 }, { CCKEY_F1, 0 }, /* BIND_THIRD_PERSON, BIND_HIDE_GUI */ + { CCKEY_F7, 0 }, { 'C', 0 }, { CCKEY_LCTRL, 0 },/* BIND_AXIS_LINES, BIND_ZOOM_SCROLL, BIND_HALF_SPEED */ + { CCMOUSE_L, 0},{ CCMOUSE_M, 0},{ CCMOUSE_R, 0},/* BIND_DELETE_BLOCK, BIND_PICK_BLOCK, BIND_PLACE_BLOCK */ + { CCKEY_F6, 0 }, { CCKEY_LALT, 0 }, /* BIND_AUTOROTATE, BIND_HOTBAR_SWITCH */ + { CCKEY_F8, 0 }, { 'G', 0 }, /* BIND_SMOOTH_CAMERA, BIND_DROP_BLOCK */ + { CCKEY_F10, 0 }, { 0, 0 }, /* BIND_IDOVERLAY, BIND_BREAK_LIQUIDS */ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_LOOK_UP, BIND_LOOK_DOWN, BIND_LOOK_RIGHT, BIND_LOOK_LEFT */ + { '1', 0 }, { '2', 0 }, { '3', 0 }, /* BIND_HOTBAR_1, BIND_HOTBAR_2, BIND_HOTBAR_3 */ + { '4', 0 }, { '5', 0 }, { '6', 0 }, /* BIND_HOTBAR_4, BIND_HOTBAR_5, BIND_HOTBAR_6 */ + { '7', 0 }, { '8', 0 }, { '9', 0 }, /* BIND_HOTBAR_7, BIND_HOTBAR_8, BIND_HOTBAR_9 */ + { 0, 0 }, { 0, 0 } /* BIND_HOTBAR_LEFT, BIND_HOTBAR_RIGHT */ +}; + +static const char* const bindNames[BIND_COUNT] = { + "Forward", "Back", "Left", "Right", + "Jump", "Respawn", "SetSpawn", "Chat", "Inventory", + "ToggleFog", "SendChat", "PlayerList", + "Speed", "NoClip", "Fly", "FlyUp", "FlyDown", + "ExtInput", "HideFPS", "Screenshot", "Fullscreen", + "ThirdPerson", "HideGUI", "AxisLines", "ZoomScrolling", + "HalfSpeed", "DeleteBlock", "PickBlock", "PlaceBlock", + "AutoRotate", "HotbarSwitching", "SmoothCamera", + "DropBlock", "IDOverlay", "BreakableLiquids", + "LookUp", "LookDown", "LookRight", "LookLeft", + "Hotbar1", "Hotbar2", "Hotbar3", + "Hotbar4", "Hotbar5", "Horbar6", + "Hotbar7", "Hotbar8", "Hotbar9", + "HotbarLeft", "HotbarRight" +}; + + +#define BindMapping2_Claims(mapping, btn) (device->IsPressed(device, (mapping)->button1) && (mapping)->button2 == btn) +cc_bool InputBind_Claims(InputBind binding, int btn, struct InputDevice* device) { + BindMapping* mappings = device->currentBinds; + BindMapping* bind = &mappings[binding]; + int i; + if (bind->button2) return BindMapping2_Claims(bind, btn); + + /* Two button mappings takes priority over one button mappings */ + for (i = 0; i < BIND_COUNT; i++) + { + if (mappings[i].button2 && BindMapping2_Claims(&mappings[i], btn)) return false; + } + return bind->button1 == btn; +} + +void InputBind_Load(const struct InputDevice* device) { + cc_string name; char nameBuffer[STRING_SIZE + 1]; + const BindMapping* defaults = device->defaultBinds; + BindMapping* keybinds = device->currentBinds; + BindMapping mapping; + cc_string str, part1, part2; + int i; + + String_InitArray_NT(name, nameBuffer); + for (i = 0; i < BIND_COUNT; i++) + { + name.length = 0; + String_Format1(&name, device->bindPrefix, bindNames[i]); + name.buffer[name.length] = '\0'; + + if (!Options_UNSAFE_Get(name.buffer, &str)) { + keybinds[i] = defaults[i]; + continue; + } + + String_UNSAFE_Separate(&str, ',', &part1, &part2); + mapping.button1 = Utils_ParseEnum(&part1, defaults[i].button1, Input_StorageNames, INPUT_COUNT); + mapping.button2 = Utils_ParseEnum(&part2, defaults[i].button2, Input_StorageNames, INPUT_COUNT); + + if (mapping.button1 == CCKEY_ESCAPE) keybinds[i] = defaults[i]; + keybinds[i] = mapping; + } +} + +void InputBind_Set(InputBind binding, int btn, const struct InputDevice* device) { + cc_string name; char nameBuffer[STRING_SIZE]; + cc_string value; + String_InitArray(name, nameBuffer); + + String_Format1(&name, device->bindPrefix, bindNames[binding]); + value = String_FromReadonly(Input_StorageNames[btn]); + Options_SetString(&name, &value); + + BindMapping_Set(&device->currentBinds[binding], btn, 0); +} + +void InputBind_Reset(InputBind binding, const struct InputDevice* device) { + cc_string name; char nameBuffer[STRING_SIZE]; + String_InitArray(name, nameBuffer); + + String_Format1(&name, device->bindPrefix, bindNames[binding]); + Options_SetString(&name, &String_Empty); + + device->currentBinds[binding] = device->defaultBinds[binding]; +} + + /*########################################################################################################################* *-----------------------------------------------------Base handlers-------------------------------------------------------* *#########################################################################################################################*/ static void OnFocusChanged(void* obj) { if (!Window_Main.Focused) Input_Clear(); } static void OnInit(void) { + int i; Event_Register_(&WindowEvents.FocusChanged, NULL, OnFocusChanged); /* Fix issue with Android where if you double click in server list to join, a touch */ /* pointer is stuck down when the game loads (so you instantly start deleting blocks) */ ClearTouches(); + + for (i = 0; i < INPUT_MAX_GAMEPADS; i++) + { + Mem_Copy(&Gamepad_Devices[i].base, &padDevice, sizeof(struct InputDevice)); + Gamepad_Devices[i].base.index = i; + } + + InputBind_Load(&NormDevice); + InputBind_Load(&padDevice); } static void OnFree(void) { diff --git a/src/Input.h b/src/Input.h index 126e5a835..42e93e193 100644 --- a/src/Input.h +++ b/src/Input.h @@ -118,7 +118,6 @@ struct InputDevice { #define INPUT_DEVICE_GAMEPAD 0x04 extern struct InputDevice NormDevice; -extern struct InputDevice PadDevice; extern struct InputDevice TouchDevice; #define InputDevice_IsEnter(key, dev) ((key) == (dev)->enterButton1 || (key) == (dev)->enterButton2) @@ -207,13 +206,57 @@ void Gamepad_Tick(float delta); #define GAMEPAD_BEG_BTN CCPAD_1 #define GAMEPAD_BTN_COUNT (INPUT_COUNT - GAMEPAD_BEG_BTN) -struct GamepadState { + +struct GamepadDevice { + struct InputDevice base; long deviceID; float axisX[2], axisY[2]; cc_bool pressed[GAMEPAD_BTN_COUNT]; float holdtime[GAMEPAD_BTN_COUNT]; }; -extern struct GamepadState Gamepad_States[INPUT_MAX_GAMEPADS]; +extern struct GamepadDevice Gamepad_Devices[INPUT_MAX_GAMEPADS]; int Gamepad_MapPort(long deviceID); + + +/* Enumeration of all input bindings. */ +enum InputBind_ { + BIND_FORWARD, BIND_BACK, BIND_LEFT, BIND_RIGHT, + BIND_JUMP, BIND_RESPAWN, BIND_SET_SPAWN, BIND_CHAT, + BIND_INVENTORY, BIND_FOG, BIND_SEND_CHAT, BIND_TABLIST, + BIND_SPEED, BIND_NOCLIP, BIND_FLY, BIND_FLY_UP, BIND_FLY_DOWN, + BIND_EXT_INPUT, BIND_HIDE_FPS, BIND_SCREENSHOT, BIND_FULLSCREEN, + BIND_THIRD_PERSON, BIND_HIDE_GUI, BIND_AXIS_LINES, BIND_ZOOM_SCROLL, + BIND_HALF_SPEED, BIND_DELETE_BLOCK, BIND_PICK_BLOCK, BIND_PLACE_BLOCK, + BIND_AUTOROTATE, BIND_HOTBAR_SWITCH, BIND_SMOOTH_CAMERA, + BIND_DROP_BLOCK, BIND_IDOVERLAY, BIND_BREAK_LIQUIDS, + BIND_LOOK_UP, BIND_LOOK_DOWN, BIND_LOOK_RIGHT, BIND_LOOK_LEFT, + BIND_HOTBAR_1, BIND_HOTBAR_2, BIND_HOTBAR_3, + BIND_HOTBAR_4, BIND_HOTBAR_5, BIND_HOTBAR_6, + BIND_HOTBAR_7, BIND_HOTBAR_8, BIND_HOTBAR_9, + BIND_HOTBAR_LEFT, BIND_HOTBAR_RIGHT, + BIND_COUNT +}; +typedef int InputBind; +typedef struct BindMapping_ { cc_uint8 button1, button2; } BindMapping; +#define BindMapping_Set(mapping, btn1, btn2) (mapping)->button1 = btn1; (mapping)->button2 = btn2; + +/* The keyboard/mouse buttons that are bound to each input binding */ +extern BindMapping KeyBind_Mappings[BIND_COUNT]; +/* The gamepad buttons that are bound to each input binding */ +extern BindMapping PadBind_Mappings[BIND_COUNT]; +/* Default keyboard/mouse button that each input binding is bound to */ +extern const BindMapping KeyBind_Defaults[BIND_COUNT]; +/* Default gamepad button that each input binding is bound to */ +extern const BindMapping PadBind_Defaults[BIND_COUNT]; + +/* Whether the given binding should be triggered in response to given input button being pressed */ +cc_bool InputBind_Claims(InputBind binding, int btn, struct InputDevice* device); + +/* Sets the button that the given input binding is bound to */ +void InputBind_Set(InputBind binding, int btn, const struct InputDevice* device); +/* Resets the button that the given input binding is bound to */ +void InputBind_Reset(InputBind binding, const struct InputDevice* device); +/* Loads the bindings for the given device from either options or its defaults */ +void InputBind_Load(const struct InputDevice* device); #endif diff --git a/src/InputHandler.c b/src/InputHandler.c index 0b6bb8f7d..463244d10 100644 --- a/src/InputHandler.c +++ b/src/InputHandler.c @@ -36,164 +36,6 @@ static cc_bool suppressEscape; enum MouseButton_ { MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE }; -/*########################################################################################################################* -*---------------------------------------------------------Keybinds--------------------------------------------------------* -*#########################################################################################################################*/ -BindMapping PadBind_Mappings[BIND_COUNT]; -BindMapping KeyBind_Mappings[BIND_COUNT]; -BindTriggered Bind_OnTriggered[BIND_COUNT]; -BindReleased Bind_OnReleased[BIND_COUNT]; -cc_uint8 Bind_IsTriggered[BIND_COUNT]; - -const BindMapping PadBind_Defaults[BIND_COUNT] = { - { CCPAD_UP, 0 }, { CCPAD_DOWN, 0 }, /* BIND_FORWARD, BIND_BACK */ - { CCPAD_LEFT, 0 }, { CCPAD_RIGHT, 0 }, /* BIND_LEFT, BIND_RIGHT */ - { CCPAD_1, 0 }, { 0, 0 }, /* BIND_JUMP, BIND_RESPAWN */ - { CCPAD_START, 0 }, { CCPAD_4, 0 }, /* BIND_SET_SPAWN, BIND_CHAT */ - { CCPAD_3, 0 }, { 0, 0 }, /* BIND_INVENTORY, BIND_FOG */ - { CCPAD_START, 0 }, { 0, 0 }, /* BIND_SEND_CHAT, BIND_TABLIST */ - { CCPAD_2, CCPAD_L},{ CCPAD_2, CCPAD_3},/* BIND_SPEED, BIND_NOCLIP */ - { CCPAD_2, CCPAD_R }, /* BIND_FLY */ - {CCPAD_2,CCPAD_UP},{CCPAD_2,CCPAD_DOWN},/* BIND_FLY_UP, BIND_FLY_DOWN */ - { 0, 0 }, { 0, 0 }, /* BIND_EXT_INPUT, BIND_HIDE_FPS */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_SCREENSHOT, BIND_FULLSCREEN, BIND_THIRD_PERSON, BIND_HIDE_GUI */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_AXIS_LINES, BIND_ZOOM_SCROLL, BIND_HALF_SPEED */ - { CCPAD_L, 0 }, { 0, 0 },{ CCPAD_R, 0 },/* BIND_DELETE_BLOCK, BIND_PICK_BLOCK, BIND_PLACE_BLOCK */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_AUTOROTATE, BIND_HOTBAR_SWITCH, BIND_SMOOTH_CAMERA */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_DROP_BLOCK, BIND_IDOVERLAY, BIND_BREAK_LIQUIDS */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_LOOK_UP, BIND_LOOK_DOWN, BIND_LOOK_RIGHT, BIND_LOOK_LEFT */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_HOTBAR_1, BIND_HOTBAR_2, BIND_HOTBAR_3 */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_HOTBAR_4, BIND_HOTBAR_5, BIND_HOTBAR_6 */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_HOTBAR_7, BIND_HOTBAR_8, BIND_HOTBAR_9 */ - { CCPAD_ZL, 0 }, { CCPAD_ZR, 0 } /* BIND_HOTBAR_LEFT, BIND_HOTBAR_RIGHT */ -}; - -const BindMapping KeyBind_Defaults[BIND_COUNT] = { - { 'W', 0 }, { 'S', 0 }, { 'A', 0 }, { 'D', 0 }, /* BIND_FORWARD - BIND_RIGHT */ - { CCKEY_SPACE, 0 }, { 'R', 0 }, /* BIND_JUMP, BIND_RESPAWN */ - { CCKEY_ENTER, 0 }, { 'T', 0 }, /* BIND_SET_SPAWN, BIND_CHAT */ - { 'B', 0 }, { 'F', 0 }, /* BIND_INVENTORY, BIND_FOG */ - { CCKEY_ENTER, 0 }, { CCKEY_TAB, 0 }, /* BIND_SEND_CHAT, BIND_TABLIST */ - { CCKEY_LSHIFT, 0 }, { 'X', 0}, { 'Z', 0 }, /* BIND_SPEED, BIND_NOCLIP, BIND_FLY */ - { 'Q', 0 }, { 'E', 0 }, /* BIND_FLY_UP, BIND_FLY_DOWN */ - { CCKEY_LALT, 0 }, { CCKEY_F3, 0 }, /* BIND_EXT_INPUT, BIND_HIDE_FPS */ - { CCKEY_F12, 0 }, { CCKEY_F11, 0 }, /* BIND_SCREENSHOT, BIND_FULLSCREEN */ - { CCKEY_F5, 0 }, { CCKEY_F1, 0 }, /* BIND_THIRD_PERSON, BIND_HIDE_GUI */ - { CCKEY_F7, 0 }, { 'C', 0 }, { CCKEY_LCTRL, 0 },/* BIND_AXIS_LINES, BIND_ZOOM_SCROLL, BIND_HALF_SPEED */ - { CCMOUSE_L, 0},{ CCMOUSE_M, 0},{ CCMOUSE_R, 0},/* BIND_DELETE_BLOCK, BIND_PICK_BLOCK, BIND_PLACE_BLOCK */ - { CCKEY_F6, 0 }, { CCKEY_LALT, 0 }, /* BIND_AUTOROTATE, BIND_HOTBAR_SWITCH */ - { CCKEY_F8, 0 }, { 'G', 0 }, /* BIND_SMOOTH_CAMERA, BIND_DROP_BLOCK */ - { CCKEY_F10, 0 }, { 0, 0 }, /* BIND_IDOVERLAY, BIND_BREAK_LIQUIDS */ - { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* BIND_LOOK_UP, BIND_LOOK_DOWN, BIND_LOOK_RIGHT, BIND_LOOK_LEFT */ - { '1', 0 }, { '2', 0 }, { '3', 0 }, /* BIND_HOTBAR_1, BIND_HOTBAR_2, BIND_HOTBAR_3 */ - { '4', 0 }, { '5', 0 }, { '6', 0 }, /* BIND_HOTBAR_4, BIND_HOTBAR_5, BIND_HOTBAR_6 */ - { '7', 0 }, { '8', 0 }, { '9', 0 }, /* BIND_HOTBAR_7, BIND_HOTBAR_8, BIND_HOTBAR_9 */ - { 0, 0 }, { 0, 0 } /* BIND_HOTBAR_LEFT, BIND_HOTBAR_RIGHT */ -}; - -static const char* const bindNames[BIND_COUNT] = { - "Forward", "Back", "Left", "Right", - "Jump", "Respawn", "SetSpawn", "Chat", "Inventory", - "ToggleFog", "SendChat", "PlayerList", - "Speed", "NoClip", "Fly", "FlyUp", "FlyDown", - "ExtInput", "HideFPS", "Screenshot", "Fullscreen", - "ThirdPerson", "HideGUI", "AxisLines", "ZoomScrolling", - "HalfSpeed", "DeleteBlock", "PickBlock", "PlaceBlock", - "AutoRotate", "HotbarSwitching", "SmoothCamera", - "DropBlock", "IDOverlay", "BreakableLiquids", - "LookUp", "LookDown", "LookRight", "LookLeft", - "Hotbar1", "Hotbar2", "Hotbar3", - "Hotbar4", "Hotbar5", "Horbar6", - "Hotbar7", "Hotbar8", "Hotbar9", - "HotbarLeft", "HotbarRight" -}; - - -#define BindMapping2_Claims(mapping, btn) (device->IsPressed(device, (mapping)->button1) && (mapping)->button2 == btn) -static cc_bool Mappings_DoesClaim(InputBind binding, int btn, BindMapping* mappings, struct InputDevice* device) { - BindMapping* bind = &mappings[binding]; - int i; - if (bind->button2) return BindMapping2_Claims(bind, btn); - - /* Two button mapping takes priority over one button mapping */ - for (i = 0; i < BIND_COUNT; i++) - { - if (mappings[i].button2 && BindMapping2_Claims(&mappings[i], btn)) return false; - } - return bind->button1 == btn; -} - - -cc_bool InputBind_Claims(InputBind binding, int btn, struct InputDevice* device) { - return Mappings_DoesClaim(binding, btn, KeyBind_Mappings, device) || - Mappings_DoesClaim(binding, btn, PadBind_Mappings, device); -} - -cc_bool KeyBind_IsPressed(InputBind binding) { return Bind_IsTriggered[binding]; } - -static void KeyBind_Load(struct InputDevice* device) { - cc_string name; char nameBuffer[STRING_SIZE + 1]; - const BindMapping* defaults = device->defaultBinds; - BindMapping* keybinds = device->currentBinds; - BindMapping mapping; - cc_string str, part1, part2; - int i; - - String_InitArray_NT(name, nameBuffer); - for (i = 0; i < BIND_COUNT; i++) - { - name.length = 0; - String_Format1(&name, device->bindPrefix, bindNames[i]); - name.buffer[name.length] = '\0'; - - if (!Options_UNSAFE_Get(name.buffer, &str)) { - keybinds[i] = defaults[i]; - continue; - } - - String_UNSAFE_Separate(&str, ',', &part1, &part2); - mapping.button1 = Utils_ParseEnum(&part1, defaults[i].button1, Input_StorageNames, INPUT_COUNT); - mapping.button2 = Utils_ParseEnum(&part2, defaults[i].button2, Input_StorageNames, INPUT_COUNT); - - if (mapping.button1 == CCKEY_ESCAPE) keybinds[i] = defaults[i]; - keybinds[i] = mapping; - } -} - -void InputBind_Set(InputBind binding, int btn, struct InputDevice* device) { - cc_string name; char nameBuffer[STRING_SIZE]; - cc_string value; - String_InitArray(name, nameBuffer); - - String_Format1(&name, device->bindPrefix, bindNames[binding]); - value = String_FromReadonly(Input_StorageNames[btn]); - Options_SetString(&name, &value); - - BindMapping_Set(&device->currentBinds[binding], btn, 0); -} - -void InputBind_Reset(InputBind binding, struct InputDevice* device) { - cc_string name; char nameBuffer[STRING_SIZE]; - String_InitArray(name, nameBuffer); - - String_Format1(&name, device->bindPrefix, bindNames[binding]); - Options_SetString(&name, &String_Empty); - - device->currentBinds[binding] = device->defaultBinds[binding]; -} - -/* Initialises and loads input bindings from options */ -static void KeyBind_Init(void) { - NormDevice.defaultBinds = KeyBind_Defaults; - PadDevice.defaultBinds = PadBind_Defaults; - NormDevice.currentBinds = KeyBind_Mappings; - PadDevice.currentBinds = PadBind_Mappings; - - KeyBind_Load(&NormDevice); - KeyBind_Load(&PadDevice); -} - - /*########################################################################################################################* *---------------------------------------------------------Gamepad---------------------------------------------------------* *#########################################################################################################################*/ @@ -201,8 +43,8 @@ static void PlayerInputPad(int port, int axis, struct LocalPlayer* p, float* xMo float x, y, angle; if (Gamepad_AxisBehaviour[axis] != AXIS_BEHAVIOUR_MOVEMENT) return; - x = Gamepad_States[port].axisX[axis]; - y = Gamepad_States[port].axisY[axis]; + x = Gamepad_Devices[port].axisX[axis]; + y = Gamepad_Devices[port].axisY[axis]; if (x != 0 || y != 0) { angle = Math_Atan2f(x, y); @@ -895,6 +737,16 @@ static void HookInputBinds(void) { } +/*########################################################################################################################* +*---------------------------------------------------------Keybinds--------------------------------------------------------* +*#########################################################################################################################*/ +BindTriggered Bind_OnTriggered[BIND_COUNT]; +BindReleased Bind_OnReleased[BIND_COUNT]; +cc_uint8 Bind_IsTriggered[BIND_COUNT]; + +cc_bool KeyBind_IsPressed(InputBind binding) { return Bind_IsTriggered[binding]; } + + /*########################################################################################################################* *-----------------------------------------------------Base handlers-------------------------------------------------------* *#########################################################################################################################*/ @@ -1101,7 +953,6 @@ static void OnInit(void) { Event_Register_(&InputEvents.Up, NULL, OnInputUp); Event_Register_(&UserEvents.HackPermsChanged, NULL, InputHandler_CheckZoomFov); - KeyBind_Init(); StoredHotkeys_LoadAll(); Bind_OnTriggered[BIND_FORWARD] = Player_TriggerUp; diff --git a/src/InputHandler.h b/src/InputHandler.h index fbaf24f69..abde5217c 100644 --- a/src/InputHandler.h +++ b/src/InputHandler.h @@ -1,6 +1,6 @@ #ifndef CC_INPUTHANDLER_H #define CC_INPUTHANDLER_H -#include "Core.h" +#include "Input.h" /* Manages base game input handling Copyright 2014-2023 ClassiCube | Licensed under BSD-3 @@ -11,56 +11,6 @@ struct InputDevice; extern struct IGameComponent InputHandler_Component; -/* Enumeration of all input bindings. */ -enum InputBind_ { - BIND_FORWARD, BIND_BACK, BIND_LEFT, BIND_RIGHT, - BIND_JUMP, BIND_RESPAWN, BIND_SET_SPAWN, BIND_CHAT, - BIND_INVENTORY, BIND_FOG, BIND_SEND_CHAT, BIND_TABLIST, - BIND_SPEED, BIND_NOCLIP, BIND_FLY, BIND_FLY_UP, BIND_FLY_DOWN, - BIND_EXT_INPUT, BIND_HIDE_FPS, BIND_SCREENSHOT, BIND_FULLSCREEN, - BIND_THIRD_PERSON, BIND_HIDE_GUI, BIND_AXIS_LINES, BIND_ZOOM_SCROLL, - BIND_HALF_SPEED, BIND_DELETE_BLOCK, BIND_PICK_BLOCK, BIND_PLACE_BLOCK, - BIND_AUTOROTATE, BIND_HOTBAR_SWITCH, BIND_SMOOTH_CAMERA, - BIND_DROP_BLOCK, BIND_IDOVERLAY, BIND_BREAK_LIQUIDS, - BIND_LOOK_UP, BIND_LOOK_DOWN, BIND_LOOK_RIGHT, BIND_LOOK_LEFT, - BIND_HOTBAR_1, BIND_HOTBAR_2, BIND_HOTBAR_3, - BIND_HOTBAR_4, BIND_HOTBAR_5, BIND_HOTBAR_6, - BIND_HOTBAR_7, BIND_HOTBAR_8, BIND_HOTBAR_9, - BIND_HOTBAR_LEFT, BIND_HOTBAR_RIGHT, - BIND_COUNT -}; -typedef int InputBind; -typedef struct BindMapping_ { cc_uint8 button1, button2; } BindMapping; -typedef cc_bool (*BindTriggered)(int key, struct InputDevice* device); -typedef void (*BindReleased)(int key, struct InputDevice* device); -#define BindMapping_Set(mapping, btn1, btn2) (mapping)->button1 = btn1; (mapping)->button2 = btn2; - -/* The keyboard/mouse buttons that are bound to each input binding */ -extern BindMapping KeyBind_Mappings[BIND_COUNT]; -/* The gamepad buttons that are bound to each input binding */ -extern BindMapping PadBind_Mappings[BIND_COUNT]; -/* Default keyboard/mouse button that each input binding is bound to */ -extern const BindMapping KeyBind_Defaults[BIND_COUNT]; -/* Default gamepad button that each input binding is bound to */ -extern const BindMapping PadBind_Defaults[BIND_COUNT]; -/* Callback behaviour for when the given input binding is triggered */ -extern BindTriggered Bind_OnTriggered[BIND_COUNT]; -/* Callback behaviour for when the given input binding is released */ -extern BindReleased Bind_OnReleased[BIND_COUNT]; -/* Whether the given input binding is activated by one or more devices */ -extern cc_uint8 Bind_IsTriggered[BIND_COUNT]; - -/* Whether the given binding should be triggered in response to given input button being pressed */ -cc_bool InputBind_Claims(InputBind binding, int btn, struct InputDevice* device); -/* Gets whether the given input binding is currently being triggered */ -CC_API cc_bool KeyBind_IsPressed(InputBind binding); - -/* Sets the button that the given input binding is bound to */ -void InputBind_Set(InputBind binding, int btn, struct InputDevice* device); -/* Resets the button that the given input binding is bound to */ -void InputBind_Reset(InputBind binding, struct InputDevice* device); - - /* whether to leave text input open for user to enter further input */ #define HOTKEY_FLAG_STAYS_OPEN 0x01 /* Whether the hotkey was auto defined (e.g. by server) */ @@ -100,4 +50,17 @@ cc_bool InputHandler_SetFOV(int fov); cc_bool Input_HandleMouseWheel(float delta); void InputHandler_Tick(void); void InputHandler_OnScreensChanged(void); + + +typedef cc_bool (*BindTriggered)(int key, struct InputDevice* device); +typedef void (*BindReleased)(int key, struct InputDevice* device); +/* Gets whether the given input binding is currently being triggered */ +CC_API cc_bool KeyBind_IsPressed(InputBind binding); + +/* Callback behaviour for when the given input binding is triggered */ +extern BindTriggered Bind_OnTriggered[BIND_COUNT]; +/* Callback behaviour for when the given input binding is released */ +extern BindReleased Bind_OnReleased[BIND_COUNT]; +/* Whether the given input binding is activated by one or more devices */ +extern cc_uint8 Bind_IsTriggered[BIND_COUNT]; #endif diff --git a/src/Menus.c b/src/Menus.c index 2e50f0447..7a7701d55 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -1863,7 +1863,7 @@ static void BindsSourceScreen_ModeNormal(void* screen, void* b) { } static void BindsSourceScreen_ModeGamepad(void* screen, void* b) { - bind_device = &PadDevice; + bind_device = &Gamepad_Devices[0].base; NormalBindingsScreen_Show(); } @@ -1921,7 +1921,7 @@ static void SwitchBindsMain(void* s, void* w) { /* User needs to decide whether to configure mouse/keyboard or gamepad */ BindsSourceScreen_Show(); } else if (Input.Sources == INPUT_SOURCE_GAMEPAD) { - bind_device = &PadDevice; + bind_device = &Gamepad_Devices[0].base; NormalBindingsScreen_Show(); } else { bind_device = &NormDevice; @@ -2131,7 +2131,7 @@ static void KeyBindsScreen_Show(int bindsCount, const cc_uint8* binds, const cha void ClassicBindingsScreen_Show(void) { static const cc_uint8 binds[] = { BIND_FORWARD, BIND_BACK, BIND_JUMP, BIND_CHAT, BIND_SET_SPAWN, BIND_LEFT, BIND_RIGHT, BIND_INVENTORY, BIND_FOG, BIND_RESPAWN }; static const char* const descs[] = { "Forward", "Back", "Jump", "Chat", "Save location", "Left", "Right", "Build", "Toggle fog", "Load location" }; - bind_device = Input.Sources == INPUT_SOURCE_GAMEPAD ? &PadDevice : &NormDevice; + bind_device = Input.Sources == INPUT_SOURCE_GAMEPAD ? &Gamepad_Devices[0].base : &NormDevice; if (Game_ClassicHacks) { KeyBindsScreen_Reset(NULL, Menu_SwitchBindsClassicHacks, 260); @@ -2150,7 +2150,7 @@ void ClassicBindingsScreen_Show(void) { void ClassicHacksBindingsScreen_Show(void) { static const cc_uint8 binds[6] = { BIND_SPEED, BIND_NOCLIP, BIND_HALF_SPEED, BIND_FLY, BIND_FLY_UP, BIND_FLY_DOWN }; static const char* const descs[6] = { "Speed", "Noclip", "Half speed", "Fly", "Fly up", "Fly down" }; - bind_device = Input.Sources == INPUT_SOURCE_GAMEPAD ? &PadDevice : &NormDevice; + bind_device = Input.Sources == INPUT_SOURCE_GAMEPAD ? &Gamepad_Devices[0].base : &NormDevice; KeyBindsScreen_Reset(Menu_SwitchBindsClassic, NULL, 260); KeyBindsScreen_SetLayout(-90, -40, 3);