redefinir tecles
This commit is contained in:
@@ -74,10 +74,10 @@ namespace Gamepad {
|
||||
pad_ = nullptr;
|
||||
pad_id_ = 0;
|
||||
// Neteja qualsevol tecla virtual que poguera estar premuda
|
||||
JI_SetVirtualKey(SDL_SCANCODE_UP, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_DOWN, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_LEFT, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_RIGHT, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_UP, JI_VSRC_GAMEPAD, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_DOWN, JI_VSRC_GAMEPAD, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_LEFT, JI_VSRC_GAMEPAD, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_RIGHT, JI_VSRC_GAMEPAD, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,16 +140,16 @@ namespace Gamepad {
|
||||
if (b && !prev_b_) pushKey(SDL_SCANCODE_BACKSPACE);
|
||||
|
||||
// Assegura que el joc no rep tecles de moviment mentre el menú està obert
|
||||
JI_SetVirtualKey(SDL_SCANCODE_UP, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_DOWN, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_LEFT, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_RIGHT, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_UP, JI_VSRC_GAMEPAD, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_DOWN, JI_VSRC_GAMEPAD, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_LEFT, JI_VSRC_GAMEPAD, false);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_RIGHT, JI_VSRC_GAMEPAD, false);
|
||||
} else {
|
||||
// Moviment al joc — level-triggered (polling)
|
||||
JI_SetVirtualKey(SDL_SCANCODE_UP, up);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_DOWN, dn);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_LEFT, lt);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_RIGHT, rt);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_UP, JI_VSRC_GAMEPAD, up);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_DOWN, JI_VSRC_GAMEPAD, dn);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_LEFT, JI_VSRC_GAMEPAD, lt);
|
||||
JI_SetVirtualKey(SDL_SCANCODE_RIGHT, JI_VSRC_GAMEPAD, rt);
|
||||
// Botó A al joc: emet Enter per avançar seqüències (JI_AnyKey)
|
||||
if (a && !prev_a_) pushKey(SDL_SCANCODE_RETURN);
|
||||
}
|
||||
|
||||
27
source/core/input/key_remap.cpp
Normal file
27
source/core/input/key_remap.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "core/input/key_remap.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "core/jail/jinput.hpp"
|
||||
#include "game/options.hpp"
|
||||
|
||||
namespace KeyRemap {
|
||||
|
||||
static void mirror(SDL_Scancode custom, SDL_Scancode standard, const bool* ks) {
|
||||
if (custom == standard || custom == SDL_SCANCODE_UNKNOWN) {
|
||||
JI_SetVirtualKey(standard, JI_VSRC_REMAP, false);
|
||||
return;
|
||||
}
|
||||
JI_SetVirtualKey(standard, JI_VSRC_REMAP, ks[custom]);
|
||||
}
|
||||
|
||||
void update() {
|
||||
const bool* ks = SDL_GetKeyboardState(nullptr);
|
||||
if (!ks) return;
|
||||
mirror(Options::keys_game.up, SDL_SCANCODE_UP, ks);
|
||||
mirror(Options::keys_game.down, SDL_SCANCODE_DOWN, ks);
|
||||
mirror(Options::keys_game.left, SDL_SCANCODE_LEFT, ks);
|
||||
mirror(Options::keys_game.right, SDL_SCANCODE_RIGHT, ks);
|
||||
}
|
||||
|
||||
} // namespace KeyRemap
|
||||
8
source/core/input/key_remap.hpp
Normal file
8
source/core/input/key_remap.hpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// Remapeja tecles del joc: llig les tecles personalitzades de l'usuari
|
||||
// (Options::keys_game) i les reflecteix a les tecles estàndard virtuals
|
||||
// que el joc polla (SDL_SCANCODE_UP/DOWN/LEFT/RIGHT).
|
||||
namespace KeyRemap {
|
||||
void update(); // cridat cada frame des del Director
|
||||
}
|
||||
@@ -20,12 +20,12 @@ void JI_SetInputBlocked(bool blocked) {
|
||||
input_blocked = blocked;
|
||||
}
|
||||
|
||||
static Uint8 virtual_keystates[SDL_SCANCODE_COUNT] = {0};
|
||||
static Uint8 virtual_keystates[JI_VSRC_COUNT][SDL_SCANCODE_COUNT] = {{0}};
|
||||
|
||||
void JI_SetVirtualKey(int scancode, bool pressed) {
|
||||
if (scancode >= 0 && scancode < SDL_SCANCODE_COUNT) {
|
||||
virtual_keystates[scancode] = pressed ? 1 : 0;
|
||||
}
|
||||
void JI_SetVirtualKey(int scancode, int source, bool pressed) {
|
||||
if (scancode < 0 || scancode >= SDL_SCANCODE_COUNT) return;
|
||||
if (source < 0 || source >= JI_VSRC_COUNT) return;
|
||||
virtual_keystates[source][scancode] = pressed ? 1 : 0;
|
||||
}
|
||||
|
||||
void JI_moveCheats(Uint8 new_key) {
|
||||
@@ -56,7 +56,11 @@ bool JI_KeyPressed(int key) {
|
||||
// ESC bloquejada pel Director (primera pulsació mostra notificació)
|
||||
if (key == SDL_SCANCODE_ESCAPE && Director::get()->isEscBlocked()) return false;
|
||||
if (key < 0 || key >= SDL_SCANCODE_COUNT) return false;
|
||||
return keystates[key] != 0 || virtual_keystates[key] != 0;
|
||||
if (keystates[key] != 0) return true;
|
||||
for (int src = 0; src < JI_VSRC_COUNT; src++) {
|
||||
if (virtual_keystates[src][key] != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JI_CheatActivated(const char* cheat_code) {
|
||||
|
||||
@@ -6,9 +6,15 @@ void JI_DisableKeyboard(Uint32 time);
|
||||
// Bloqueja tot l'input cap al joc (JI_KeyPressed retorna false per a tot)
|
||||
void JI_SetInputBlocked(bool blocked);
|
||||
|
||||
// Estableix l'estat d'una tecla virtual (p.ex. des del gamepad).
|
||||
// JI_KeyPressed retorna true si el teclat real O la virtual estan premudes.
|
||||
void JI_SetVirtualKey(int scancode, bool pressed);
|
||||
// Estableix l'estat d'una tecla virtual. Múltiples fonts (gamepad, remap)
|
||||
// s'agrupen per OR. JI_KeyPressed retorna true si el teclat real O qualsevol
|
||||
// font virtual està premuda.
|
||||
enum JI_VirtualSource {
|
||||
JI_VSRC_GAMEPAD = 0,
|
||||
JI_VSRC_REMAP = 1,
|
||||
JI_VSRC_COUNT
|
||||
};
|
||||
void JI_SetVirtualKey(int scancode, int source, bool pressed);
|
||||
|
||||
void JI_Update();
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace Menu {
|
||||
enum class ItemKind { Toggle,
|
||||
Cycle,
|
||||
IntRange,
|
||||
Submenu };
|
||||
Submenu,
|
||||
KeyBind };
|
||||
|
||||
struct Item {
|
||||
const char* label;
|
||||
@@ -49,6 +50,7 @@ namespace Menu {
|
||||
std::function<std::string()> getValue; // opcional
|
||||
std::function<void(int dir)> change; // per Toggle/Cycle/IntRange
|
||||
std::function<void()> enter; // per Submenu
|
||||
SDL_Scancode* scancode{nullptr}; // per KeyBind
|
||||
};
|
||||
|
||||
struct Page {
|
||||
@@ -62,6 +64,7 @@ namespace Menu {
|
||||
static std::unique_ptr<Text> font_;
|
||||
static float open_anim_{0.0F}; // 0 = tancat, 1 = obert
|
||||
static Uint32 last_ticks_{0};
|
||||
static SDL_Scancode* capturing_{nullptr}; // != null → esperant tecla per assignar
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
@@ -72,11 +75,13 @@ namespace Menu {
|
||||
|
||||
static Page buildVideo();
|
||||
static Page buildAudio();
|
||||
static Page buildControls();
|
||||
|
||||
static Page buildRoot() {
|
||||
Page p{"OPCIONS", {}, 0};
|
||||
p.items.push_back({"VIDEO", ItemKind::Submenu, nullptr, nullptr, [] { stack_.push_back(buildVideo()); }});
|
||||
p.items.push_back({"AUDIO", ItemKind::Submenu, nullptr, nullptr, [] { stack_.push_back(buildAudio()); }});
|
||||
p.items.push_back({"VIDEO", ItemKind::Submenu, nullptr, nullptr, [] { stack_.push_back(buildVideo()); }, nullptr});
|
||||
p.items.push_back({"AUDIO", ItemKind::Submenu, nullptr, nullptr, [] { stack_.push_back(buildAudio()); }, nullptr});
|
||||
p.items.push_back({"CONTROLS", ItemKind::Submenu, nullptr, nullptr, [] { stack_.push_back(buildControls()); }, nullptr});
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -137,6 +142,16 @@ namespace Menu {
|
||||
Options::applyAudio();
|
||||
}
|
||||
|
||||
static Page buildControls() {
|
||||
Page p{"CONTROLS", {}, 0};
|
||||
p.items.push_back({"MOU AMUNT", ItemKind::KeyBind, nullptr, nullptr, nullptr, &Options::keys_game.up});
|
||||
p.items.push_back({"MOU AVALL", ItemKind::KeyBind, nullptr, nullptr, nullptr, &Options::keys_game.down});
|
||||
p.items.push_back({"MOU ESQUERRA", ItemKind::KeyBind, nullptr, nullptr, nullptr, &Options::keys_game.left});
|
||||
p.items.push_back({"MOU DRETA", ItemKind::KeyBind, nullptr, nullptr, nullptr, &Options::keys_game.right});
|
||||
p.items.push_back({"TECLA MENU", ItemKind::KeyBind, nullptr, nullptr, nullptr, &Options::keys_gui.menu_toggle});
|
||||
return p;
|
||||
}
|
||||
|
||||
static Page buildAudio() {
|
||||
Page p{"AUDIO", {}, 0};
|
||||
|
||||
@@ -242,6 +257,22 @@ namespace Menu {
|
||||
void close() {
|
||||
stack_.clear();
|
||||
open_anim_ = 0.0F;
|
||||
capturing_ = nullptr;
|
||||
}
|
||||
|
||||
auto isCapturing() -> bool {
|
||||
return capturing_ != nullptr;
|
||||
}
|
||||
|
||||
void captureKey(SDL_Scancode sc) {
|
||||
if (!capturing_) return;
|
||||
if (sc == SDL_SCANCODE_ESCAPE) {
|
||||
// Cancel·la
|
||||
capturing_ = nullptr;
|
||||
return;
|
||||
}
|
||||
*capturing_ = sc;
|
||||
capturing_ = nullptr;
|
||||
}
|
||||
|
||||
void handleKey(SDL_Scancode sc) {
|
||||
@@ -279,6 +310,8 @@ namespace Menu {
|
||||
case SDL_SCANCODE_KP_ENTER:
|
||||
if (page.items[page.cursor].kind == ItemKind::Submenu) {
|
||||
if (page.items[page.cursor].enter) page.items[page.cursor].enter();
|
||||
} else if (page.items[page.cursor].kind == ItemKind::KeyBind) {
|
||||
capturing_ = page.items[page.cursor].scancode;
|
||||
} else if (page.items[page.cursor].change) {
|
||||
page.items[page.cursor].change(+1);
|
||||
}
|
||||
@@ -363,6 +396,13 @@ namespace Menu {
|
||||
int aw = font_->width(arrow);
|
||||
Uint32 ac = selected ? CURSOR_COLOR : VALUE_COLOR;
|
||||
font_->draw(pixel_data, box_x + BOX_W - ITEM_PAD_X - aw, y, arrow, ac);
|
||||
} else if (item.kind == ItemKind::KeyBind) {
|
||||
bool this_capturing = (capturing_ == item.scancode);
|
||||
const char* text = this_capturing ? "<PREM TECLA>" : (item.scancode ? SDL_GetScancodeName(*item.scancode) : "");
|
||||
if (!text || !*text) text = "---";
|
||||
int tw = font_->width(text);
|
||||
Uint32 tc = this_capturing ? 0xFF00FFFF : (selected ? CURSOR_COLOR : VALUE_COLOR);
|
||||
font_->draw(pixel_data, box_x + BOX_W - ITEM_PAD_X - tw, y, text, tc);
|
||||
} else if (item.getValue) {
|
||||
std::string value = item.getValue();
|
||||
int value_w = font_->width(value.c_str());
|
||||
|
||||
@@ -15,4 +15,8 @@ namespace Menu {
|
||||
|
||||
// Gestió d'input — cridat des del Director en KEY_DOWN
|
||||
void handleKey(SDL_Scancode sc);
|
||||
|
||||
// Mode de captura de tecla (per al menú de remapeig)
|
||||
[[nodiscard]] auto isCapturing() -> bool;
|
||||
void captureKey(SDL_Scancode sc); // assigna la tecla capturada (ESC cancel·la)
|
||||
} // namespace Menu
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "core/input/gamepad.hpp"
|
||||
#include "core/input/global_inputs.hpp"
|
||||
#include "core/input/key_remap.hpp"
|
||||
#include "core/input/mouse.hpp"
|
||||
#include "core/jail/jgame.hpp"
|
||||
#include "core/jail/jinput.hpp"
|
||||
@@ -54,6 +55,7 @@ void Director::run() {
|
||||
|
||||
handleEvents();
|
||||
Gamepad::update();
|
||||
KeyRemap::update();
|
||||
GlobalInputs::handle();
|
||||
Mouse::updateCursorVisibility();
|
||||
|
||||
@@ -117,11 +119,24 @@ void Director::handleEvents() {
|
||||
Gamepad::handleEvent(event);
|
||||
continue;
|
||||
}
|
||||
// Empassar-se el KEY_UP de qualsevol tecla que el menú va consumir en KEY_DOWN
|
||||
if (event.type == SDL_EVENT_KEY_UP && event.key.scancode >= 0 &&
|
||||
event.key.scancode < SDL_SCANCODE_COUNT && menu_keys_held_[event.key.scancode]) {
|
||||
menu_keys_held_[event.key.scancode] = false;
|
||||
continue;
|
||||
}
|
||||
// Captura de tecla (remapeig al menú): intercepta KEY_DOWN abans de tot
|
||||
if (Menu::isCapturing() && event.type == SDL_EVENT_KEY_DOWN && !event.key.repeat) {
|
||||
Menu::captureKey(event.key.scancode);
|
||||
menu_keys_held_[event.key.scancode] = true;
|
||||
continue;
|
||||
}
|
||||
// Menú: F12 (o tecla configurada) obre/tanca el menú flotant
|
||||
if (event.type == SDL_EVENT_KEY_DOWN && !event.key.repeat &&
|
||||
event.key.scancode == Options::keys_gui.menu_toggle) {
|
||||
Menu::toggle();
|
||||
JI_SetInputBlocked(Menu::isOpen());
|
||||
menu_keys_held_[event.key.scancode] = true;
|
||||
continue;
|
||||
}
|
||||
// Si el menú està obert, consumeix tot l'input de teclat
|
||||
@@ -133,7 +148,12 @@ void Director::handleEvents() {
|
||||
esc_swallow_until_release_ = true;
|
||||
} else {
|
||||
Menu::handleKey(event.key.scancode);
|
||||
// El menú pot haver-se tancat (p.ex. Backspace al nivell arrel)
|
||||
if (!Menu::isOpen()) {
|
||||
JI_SetInputBlocked(false);
|
||||
}
|
||||
}
|
||||
menu_keys_held_[event.key.scancode] = true;
|
||||
continue;
|
||||
}
|
||||
if (Menu::isOpen() && event.type == SDL_EVENT_KEY_UP) {
|
||||
|
||||
@@ -59,4 +59,7 @@ class Director {
|
||||
// Quan el menú tanca amb ESC, empassem-nos l'ESC fins que l'usuari la deixe anar,
|
||||
// per no fer eixir el joc al proper poll de JI_KeyPressed.
|
||||
std::atomic<bool> esc_swallow_until_release_{false};
|
||||
// Tecles consumides pel menú (KEY_DOWN): el KEY_UP associat cal empassar-lo
|
||||
// per evitar que el joc (JI_AnyKey / JI_moveCheats) les veja quan el menú tanca.
|
||||
bool menu_keys_held_[SDL_SCANCODE_COUNT]{};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user