From 6dfa449e52fd3622f2de438dbb68807bc9fe533c Mon Sep 17 00:00:00 2001 From: MartinCajiao Date: Sun, 27 Sep 2026 19:58:38 -0500 Subject: [PATCH] fix(input): handle UTF-8 BOM and duplicate bindings --- core/libs/prx/libSceVideoOut/src/InputMapping.cpp | 8 +++++++- docs/INPUT_MAPPING.md | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/libs/prx/libSceVideoOut/src/InputMapping.cpp b/core/libs/prx/libSceVideoOut/src/InputMapping.cpp index 3b925fc91..33df257b3 100644 --- a/core/libs/prx/libSceVideoOut/src/InputMapping.cpp +++ b/core/libs/prx/libSceVideoOut/src/InputMapping.cpp @@ -143,6 +143,7 @@ std::vector Pad::LoadInputMapping() { std::size_t lineNumber = 0; while (std::getline(file, line)) { ++lineNumber; + if (lineNumber == 1 && line.starts_with("\xEF\xBB\xBF")) line.erase(0, 3); const auto comment = line.find_first_of("#;"); const std::string_view content = trim(std::string_view(line).substr(0, comment)); if (content.empty()) continue; @@ -161,7 +162,12 @@ std::vector Pad::LoadInputMapping() { if (overriddenActions.insert(normalizedAction).second) { std::erase_if(bindings, [action](const InputBinding& existing) { return matchesAction(existing, *action); }); } - bindings.push_back(binding); + const bool duplicate = std::any_of(bindings.begin(), bindings.end(), [&binding](const InputBinding& existing) { + return existing.key == binding.key && existing.mouseButton == binding.mouseButton && + existing.control == binding.control && existing.button == binding.button && + existing.wheelDirection == binding.wheelDirection; + }); + if (!duplicate) bindings.push_back(binding); } catch (const std::runtime_error& error) { invalidLine(path, lineNumber, error.what()); } diff --git a/docs/INPUT_MAPPING.md b/docs/INPUT_MAPPING.md index 3904986f9..e79ffd25a 100644 --- a/docs/INPUT_MAPPING.md +++ b/docs/INPUT_MAPPING.md @@ -2,7 +2,7 @@ AnyPS5 uses its built-in keyboard and mouse bindings when no configuration file is present. To change selected bindings, create `anyps5-input.ini` in the game's working directory. Set `ANYPS5_INPUT_CONFIG` to use a file at another path. -Each non-empty line has the form `Action = Type:Value`. Action names are case-insensitive. A `#` or `;` starts a comment. The first line for an action replaces its built-in bindings; later lines for the same action add alternate inputs. Actions omitted from the file keep their built-in bindings. +Each non-empty line has the form `Action = Type:Value`. Action names are case-insensitive. A `#` or `;` starts a comment. The first line for an action replaces its built-in bindings; later lines for the same action add alternate inputs. Duplicate entries for the same action are ignored. Actions omitted from the file keep their built-in bindings. UTF-8 files with or without a byte-order mark are supported. Supported input sources are: @@ -12,10 +12,11 @@ Supported input sources are: Supported actions are `Cross`, `Circle`, `Triangle`, `Square`, `L1`, `R1`, `L2`, `R2`, `L3`, `R3`, `Options`, `Up`, `Right`, `Down`, `Left`, `LeftStickLeft`, `LeftStickRight`, `LeftStickUp`, `LeftStickDown`, `RightStickLeft`, `RightStickRight`, `RightStickUp`, `RightStickDown`, `TouchLeft`, `TouchRight`, `ToggleMouse`, and `ToggleFullscreen`. -For example, this changes Cross to F, adds IJKL alternatives for the left stick, uses the mouse buttons for Square and R2, and keeps all other built-in bindings: +For example, this changes Cross to F or Space, moves the left stick to IJKL, uses the mouse buttons for Square and R2, and keeps all other built-in bindings: ```ini Cross = KEY:F +Cross = KEY:Space LeftStickLeft = KEY:J LeftStickRight = KEY:L LeftStickUp = KEY:I