// SPDX-License-Identifier: GPL-3.0-or-later #include "../gpu/shim/input/bindings.h" #include "../gpu/shim/input/mouse_turn.h" #include "../gpu/shim/input/pad.h" #include #include #include #include #include #include #include #include void host_log(const char*, ...) {} std::uint32_t menu_confirm_button() { return PadBits::kCross; } std::uint32_t menu_back_button() { return PadBits::kCircle; } namespace { struct Keyboard { bool keys[SDL_SCANCODE_COUNT] = {}; bool held[kBindCount] = {}; Keyboard& Down(SDL_Scancode sc, bool down = true) { keys[sc] = down; host_bindings_keys_held(keys, SDL_SCANCODE_COUNT, held); return *this; } }; PadState Pad(std::initializer_list actions, bool strong = false) { bool held[kBindCount] = {}; for (int a : actions) held[a] = true; PadState pad; host_bindings_apply(held, strong, pad); return pad; } std::string Described(int action) { char text[160]; host_binding_describe(action, text, sizeof text); return text; } void Defaults() { host_bindings_load_defaults(); assert(host_binding_key(kBindMoveF) == SDL_SCANCODE_W && host_binding_key(kBindWalk) == SDL_SCANCODE_LALT); assert(host_binding_key(kBindAttack) == 0 && host_binding_mouse(kBindAttack) == 1); assert(host_binding_ini_value(kBindAttack) == "Mouse1"); assert(host_binding_ini_value(kBindTransform) == "C, Mouse2"); assert(Described(kBindTransform) == "C / Middle Button"); assert(Described(kBindDebugMenu) == "` (backtick)"); assert(std::string(host_binding_info(kBindRoll).key) == "roll" && host_binding_info(kBindRoll).button == PadBits::kCircle); } void Movement() { host_bindings_load_defaults(); PadState p = Pad({kBindMoveF}); assert(p.lx == kStickRest && p.ly == kStickLow); p = Pad({kBindMoveF, kBindMoveR}); assert(p.lx == kStickHigh && p.ly == kStickLow); const PadState straight = Pad({kBindMoveF, kBindWalk}), diagonal = Pad({kBindMoveF, kBindMoveR, kBindWalk}); const float reach = float(kStickRest - straight.ly); assert(reach > 60 && reach < 90); assert(std::abs(std::hypot(float(diagonal.lx) - kStickRest, float(diagonal.ly) - kStickRest) - reach) <= 1.5f); Keyboard k; k.Down(SDL_SCANCODE_W).Down(SDL_SCANCODE_S); assert(!k.held[kBindMoveF] && !k.held[kBindMoveB]); k.Down(SDL_SCANCODE_S, false); assert(k.held[kBindMoveF]); } void Buttons() { host_bindings_load_defaults(); PadState p = Pad({kBindAttack}, true); assert(p.buttons == PadBits::kR2 && p.r2 == 255); p = Pad({kBindFirearm}); assert(p.buttons == PadBits::kL2 && p.l2 == 255); p = Pad({kBindConfirm, kBindBack}); assert(p.buttons == (PadBits::kCross | PadBits::kCircle)); p = Pad({kBindLookL, kBindLookD}); assert(p.rx == kStickLow && p.ry == kStickHigh); p = Pad({kBindGestures, kBindEffects}); assert(p.buttons == PadBits::kTouchPad && p.touch_count == 2); assert(p.touch[0].x < kTouchWidth / 2 && p.touch[1].x > kTouchWidth / 2 && p.touch[0].id == p.touch[1].id); p = Pad({kBindDebugMenu}); assert(p.buttons == 0); } void IniValues() { host_bindings_load_defaults(); assert(host_bindings_parse("attack", "E, Mouse2")); assert(host_binding_key(kBindAttack) == SDL_SCANCODE_E && host_binding_mouse(kBindAttack) == 2); assert(host_binding_ini_value(kBindAttack) == "E, Mouse2"); assert(host_bindings_parse("use_item", "F, Shift+E, Ctrl+Mouse4")); assert(host_binding_ini_value(kBindUseItem) == "F, Shift+E, Ctrl+Mouse4"); assert(Described(kBindUseItem) == "F / Shift+E / Ctrl+Button 4"); assert(host_bindings_parse("lock_on", " \"control+alt+Q\" , WheelDown ")); assert(host_binding_ini_value(kBindLockOn) == "Ctrl+Alt+Q, WheelDown"); assert(host_bindings_parse("interact", "E, NoSuchKey, Mouse5")); assert(host_binding_ini_value(kBindInteract) == "E, Mouse5"); assert(host_bindings_parse("blood_vial", "R, 1, 2, 3, 4, 5")); assert(host_binding_ini_value(kBindBloodVial) == "R, 1, 2, 3"); assert(host_bindings_parse("gestures", "none") && host_binding_ini_value(kBindGestures) == "none"); assert(Described(kBindGestures) == "Unbound"); assert(host_bindings_parse("dpad_down", "Z") && host_binding_key(kBindSwitchItem) == SDL_SCANCODE_Z); assert(!host_bindings_parse("jump", "Space")); } void Modifiers() { host_bindings_load_defaults(); assert(host_bindings_parse("use_item", "F, Shift+E, Ctrl+Mouse4")); assert(host_bindings_parse("interact", "E, Mouse5")); Keyboard k; k.Down(SDL_SCANCODE_E); assert(k.held[kBindInteract] && !k.held[kBindUseItem]); k.Down(SDL_SCANCODE_LSHIFT); assert(!k.held[kBindInteract] && k.held[kBindUseItem] && k.held[kBindStrongMod]); k.Down(SDL_SCANCODE_E, false).Down(SDL_SCANCODE_LSHIFT, false).Down(SDL_SCANCODE_RCTRL); bool mouse[kBindCount]; host_bindings_mouse_held(1u << 3, mouse); assert(mouse[kBindUseItem]); k.Down(SDL_SCANCODE_RCTRL, false); host_bindings_mouse_held(1u << 3, mouse); assert(!mouse[kBindUseItem]); assert(host_bindings_parse("walk", "Mouse5")); host_bindings_mouse_held(1u << 4, mouse); k.Down(SDL_SCANCODE_W); assert(k.held[kBindWalk]); host_bindings_mouse_held(0, mouse); k.Down(SDL_SCANCODE_W); assert(!k.held[kBindWalk]); } void Rebinding() { host_bindings_load_defaults(); const std::uint64_t serial = host_bindings_serial(); host_bind_capture_begin(kBindAttack); assert(host_bind_capturing() == kBindAttack && host_bind_capture_blocking()); assert(host_bind_capture_key(SDL_SCANCODE_F)); assert(host_bind_capturing() < 0 && host_bind_capture_take_done() == kBindAttack && host_bind_capture_take_done() < 0); assert(host_binding_key(kBindAttack) == SDL_SCANCODE_F && host_binding_key(kBindUseItem) == 0); assert(host_binding_mouse(kBindAttack) == 1 && host_bindings_serial() != serial); assert(host_bind_capture_blocking()); host_bind_capture_note_held(true); assert(host_bind_capture_blocking()); host_bind_capture_note_held(false); assert(!host_bind_capture_blocking()); host_bind_capture_begin(kBindAttack); host_bind_capture_key(SDL_SCANCODE_ESCAPE); assert(host_binding_ini_value(kBindAttack) == "F, Mouse1"); host_bind_capture_note_held(false); host_bind_capture_begin(kBindAttack); host_bind_capture_key(SDL_SCANCODE_DELETE); assert(host_binding_ini_value(kBindAttack) == "none"); host_bind_capture_note_held(false); assert(host_bindings_parse("attack", "F, Mouse1")); host_binding_clear(kBindAttack); assert(host_binding_ini_value(kBindAttack) == "none"); host_bind_capture_begin(kBindLockOn); assert(host_bind_capture_key(SDL_SCANCODE_LSHIFT, SDL_KMOD_LSHIFT) && host_bind_capturing() == kBindLockOn); assert(!host_bind_capture_key_up(SDL_SCANCODE_Q)); assert(host_bind_capture_key(SDL_SCANCODE_Q, SDL_KMOD_LSHIFT) && host_bind_capturing() < 0); assert(host_binding_ini_value(kBindLockOn) == "Shift+Q"); host_bind_capture_note_held(false); host_bind_capture_begin(kBindLockOn); host_bind_capture_key(SDL_SCANCODE_RSHIFT, SDL_KMOD_RSHIFT); assert(host_bind_capture_key_up(SDL_SCANCODE_RSHIFT) && host_binding_ini_value(kBindLockOn) == "Right Shift"); host_bind_capture_note_held(false); assert(!host_bind_capture_key(SDL_SCANCODE_K) && !host_bind_capture_mouse(1)); host_bind_capture_begin(kBindInteract); assert(host_bind_capture_mouse(2) && host_bind_capturing() == kBindInteract); std::this_thread::sleep_for(std::chrono::milliseconds(320)); assert(host_bind_capture_mouse(2) && host_bind_capturing() < 0); assert(host_binding_ini_value(kBindInteract) == "E, Mouse2" && host_binding_ini_value(kBindTransform) == "C"); host_bind_capture_note_held(false); host_bind_note_clear_key(); assert(host_bind_take_clear_key() && !host_bind_take_clear_key()); host_bindings_load_defaults(); } void MouseCameraTurn() { using MouseTurn::DegreesPerCount; assert(std::abs(DegreesPerCount(5) - 0.25f) < 1e-6f && std::abs(DegreesPerCount(0) - 0.1f) < 1e-6f); assert(std::abs(DegreesPerCount(-1) - 0.08f) < 1e-6f && std::abs(DegreesPerCount(20) - 0.7f) < 1e-6f); assert(DegreesPerCount(99) == DegreesPerCount(20) && DegreesPerCount(-99) == DegreesPerCount(-10)); assert(DegreesPerCount(-10) > 0 && DegreesPerCount(-10) < DegreesPerCount(-9)); const MouseTurn::Settings s{DegreesPerCount(5), false, false}; const auto turned = [&](int updates) { float pitch = 0, yaw = 0; for (int i = 0; i < updates; ++i) MouseTurn::Turn(120.0f / updates, 60.0f / updates, s, pitch, yaw, -1, 1); return std::pair{pitch, yaw}; }; const auto a = turned(30), b = turned(60), c = turned(90); assert(std::abs(a.first - b.first) < 1e-5f && std::abs(a.second - c.second) < 1e-5f); assert(std::abs(a.second - 120 * 0.25f * 0.0174532924f) < 1e-5f && a.first > 0); float pitch = 0, yaw = 0; assert(!MouseTurn::Turn(0, 0, s, pitch, yaw, -1, 1) && pitch == 0 && yaw == 0); const MouseTurn::Settings inverted{DegreesPerCount(5), true, true}; assert(MouseTurn::Turn(10, 10, inverted, pitch, yaw, -1, 1) && pitch < 0 && yaw < 0); MouseTurn::Turn(10000, 10000, s, pitch, yaw, -0.5f, 0.5f); assert(pitch == 0.5f && yaw >= -3.1416f && yaw <= 3.1416f); MouseTurn::Turn(0, -10000, s, pitch, yaw, -0.5f, 0.5f); assert(pitch == -0.5f); } } int main() { Defaults(); Movement(); Buttons(); IniValues(); Modifiers(); Rebinding(); MouseCameraTurn(); std::puts("PC input: PASS (defaults, movement and walking, buttons and touchpad, lantern.ini values, modifiers, " "rebinding, the mouse camera's turn)"); }