From: Daniel Karbach Date: Fri, 14 Aug 2015 12:16:56 +0000 (+0200) Subject: make buttons configurable X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=82ec71079e4763f2b2d66c0c210e37df40c89034;p=blank.git make buttons configurable --- diff --git a/running b/running index 26a0f9e..8638f43 100644 --- a/running +++ b/running @@ -88,3 +88,10 @@ Press N to toggle player/world collision. F1 toggles UI rendering. F3 toggles a display telling how long on average it takes to compute a frame. F4 toggles audio. + +Controls are interpreted by scancode, meaning you don't have to break your +fingers when you're on an AZERTY. WSAD will be ZSQD there and the above +description is just wrong. + +Also I've added a plethora of alternate keys that can be used, like arrow +keys for movement, ins/del for placing/removing blocks, etc. diff --git a/src/app/Environment.hpp b/src/app/Environment.hpp index b9dcc29..4c935d8 100644 --- a/src/app/Environment.hpp +++ b/src/app/Environment.hpp @@ -6,6 +6,7 @@ #include "StateControl.hpp" #include "../audio/Audio.hpp" #include "../graphics/Viewport.hpp" +#include "../ui/Keymap.hpp" #include @@ -21,6 +22,7 @@ struct Environment { Window &window; Assets assets; + Keymap keymap; FrameCounter counter; StateControl state; diff --git a/src/app/WorldState.hpp b/src/app/WorldState.hpp index 6ab613f..04bf6a8 100644 --- a/src/app/WorldState.hpp +++ b/src/app/WorldState.hpp @@ -31,6 +31,7 @@ public: void Render(Viewport &) override; World &GetWorld() noexcept { return world; } + Interface &GetInterface() noexcept { return interface; } private: Environment &env; diff --git a/src/app/runtime.cpp b/src/app/runtime.cpp index 72a51da..d77cf47 100644 --- a/src/app/runtime.cpp +++ b/src/app/runtime.cpp @@ -4,10 +4,12 @@ #include "WorldState.hpp" #include "init.hpp" +#include "../io/filesystem.hpp" #include "../io/WorldSave.hpp" #include #include +#include #include #include @@ -51,6 +53,7 @@ Environment::Environment(Window &win, const string &asset_path) , counter() { viewport.Clear(); window.Flip(); + keymap.LoadDefault(); } @@ -232,6 +235,16 @@ int Runtime::Execute() { Environment env(init.window, config.asset_path); env.viewport.VSync(config.vsync); + std::string keys_path = config.save_path + "keys.conf"; + if (!is_file(keys_path)) { + std::ofstream file(keys_path); + env.keymap.Save(file); + } else { + std::ifstream file(keys_path); + env.keymap.Load(file); + } + + WorldSave save(config.save_path + config.world_name + '/'); if (save.Exists()) { save.Read(config.world); diff --git a/src/io/token.cpp b/src/io/token.cpp index 5e734ad..db5c986 100644 --- a/src/io/token.cpp +++ b/src/io/token.cpp @@ -191,6 +191,9 @@ TokenStreamReader::TokenStreamReader(istream &in) bool TokenStreamReader::HasMore() { + if (cached) { + return true; + } while (in.HasMore()) { if (in.Next().type != Token::COMMENT) { cached = true; diff --git a/src/ui/Keymap.hpp b/src/ui/Keymap.hpp new file mode 100644 index 0000000..e96179a --- /dev/null +++ b/src/ui/Keymap.hpp @@ -0,0 +1,72 @@ +#ifndef BLANK_UI_KEYMAP_HPP_ +#define BLANK_UI_KEYMAP_HPP_ + +#include +#include +#include + + +namespace blank { + +class Keymap { + +public: + enum Action { + NONE, + + MOVE_FORWARD, + MOVE_BACKWARD, + MOVE_LEFT, + MOVE_RIGHT, + MOVE_UP, + MOVE_DOWN, + + BLOCK_FACE, + BLOCK_TURN, + BLOCK_NEXT, + BLOCK_PREV, + + BLOCK_PLACE, + BLOCK_PICK, + BLOCK_REMOVE, + + TOGGLE_COLLISION, + TOGGLE_AUDIO, + TOGGLE_VISUAL, + TOGGLE_DEBUG, + + PRINT_BLOCK, + PRINT_CHUNK, + PRINT_LIGHT, + PRINT_SELECTION, + + EXIT, + }; + + static constexpr unsigned int MAX_SCANCODE = 0xFF; + static constexpr unsigned int NUM_SCANCODES = MAX_SCANCODE + 1; + +public: + Keymap(); + + void Map(SDL_Scancode scancode, Action); + Action Lookup(SDL_Scancode scancode); + Action Lookup(const SDL_Keysym &s) { return Lookup(s.scancode); } + Action Lookup(const SDL_KeyboardEvent &e) { return Lookup(e.keysym); } + + void LoadDefault(); + + void Load(std::istream &); + void Save(std::ostream &); + + static const char *ActionToString(Action); + static Action StringToAction(const std::string &); + +private: + Action codemap[NUM_SCANCODES]; + +}; + +} + +#endif diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 6dfe516..ef005f6 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -1,5 +1,6 @@ #include "HUD.hpp" #include "Interface.hpp" +#include "Keymap.hpp" #include "../app/Assets.hpp" #include "../app/Environment.hpp" @@ -8,6 +9,7 @@ #include "../audio/Audio.hpp" #include "../graphics/Font.hpp" #include "../graphics/Viewport.hpp" +#include "../io/TokenStreamReader.hpp" #include "../model/shapes.hpp" #include "../world/World.hpp" @@ -140,84 +142,110 @@ Interface::Interface( void Interface::HandlePress(const SDL_KeyboardEvent &event) { if (config.keyboard_disabled) return; - switch (event.keysym.sym) { - case SDLK_w: + switch (env.keymap.Lookup(event)) { + case Keymap::MOVE_FORWARD: rev.z = 1; break; - case SDLK_s: + case Keymap::MOVE_BACKWARD: fwd.z = 1; break; - case SDLK_a: + case Keymap::MOVE_LEFT: rev.x = 1; break; - case SDLK_d: + case Keymap::MOVE_RIGHT: fwd.x = 1; break; - case SDLK_SPACE: + case Keymap::MOVE_UP: fwd.y = 1; break; - case SDLK_LSHIFT: + case Keymap::MOVE_DOWN: rev.y = 1; break; - case SDLK_q: + case Keymap::BLOCK_FACE: FaceBlock(); break; - case SDLK_e: + case Keymap::BLOCK_TURN: TurnBlock(); break; + case Keymap::BLOCK_NEXT: + SelectNext(); + break; + case Keymap::BLOCK_PREV: + SelectPrevious(); + break; + + case Keymap::BLOCK_PLACE: + PlaceBlock(); + break; + case Keymap::BLOCK_PICK: + PickBlock(); + break; + case Keymap::BLOCK_REMOVE: + RemoveBlock(); + break; - case SDLK_n: + case Keymap::TOGGLE_COLLISION: ToggleCollision(); break; - case SDLK_b: + case Keymap::PRINT_BLOCK: PrintBlockInfo(); break; - case SDLK_c: + case Keymap::PRINT_CHUNK: PrintChunkInfo(); break; - case SDLK_l: + case Keymap::PRINT_LIGHT: PrintLightInfo(); break; - case SDLK_p: + case Keymap::PRINT_SELECTION: PrintSelectionInfo(); break; - case SDLK_F1: + case Keymap::TOGGLE_VISUAL: ToggleVisual(); break; - case SDLK_F3: + case Keymap::TOGGLE_DEBUG: ToggleDebug(); break; - case SDLK_F4: + case Keymap::TOGGLE_AUDIO: ToggleAudio(); break; + + case Keymap::EXIT: + env.state.Pop(); + break; + + default: + break; } } void Interface::HandleRelease(const SDL_KeyboardEvent &event) { if (config.keyboard_disabled) return; - switch (event.keysym.sym) { - case SDLK_w: + switch (env.keymap.Lookup(event)) { + case Keymap::MOVE_FORWARD: rev.z = 0; break; - case SDLK_s: + case Keymap::MOVE_BACKWARD: fwd.z = 0; break; - case SDLK_a: + case Keymap::MOVE_LEFT: rev.x = 0; break; - case SDLK_d: + case Keymap::MOVE_RIGHT: fwd.x = 0; break; - case SDLK_SPACE: + case Keymap::MOVE_UP: fwd.y = 0; break; - case SDLK_LSHIFT: + case Keymap::MOVE_DOWN: rev.y = 0; break; + + default: + break; } } @@ -555,4 +583,217 @@ void Interface::Render(Viewport &viewport) noexcept { hud.Render(viewport); } + +Keymap::Keymap() +: codemap{ NONE } { + +} + +void Keymap::Map(SDL_Scancode scancode, Action action) { + if (scancode > MAX_SCANCODE) { + throw std::runtime_error("refusing to map scancode: too damn high"); + } + codemap[scancode] = action; +} + +Keymap::Action Keymap::Lookup(SDL_Scancode scancode) { + if (scancode < NUM_SCANCODES) { + return codemap[scancode]; + } else { + return NONE; + } +} + + +void Keymap::LoadDefault() { + Map(SDL_SCANCODE_UP, MOVE_FORWARD); + Map(SDL_SCANCODE_W, MOVE_FORWARD); + Map(SDL_SCANCODE_DOWN, MOVE_BACKWARD); + Map(SDL_SCANCODE_S, MOVE_BACKWARD); + Map(SDL_SCANCODE_LEFT, MOVE_LEFT); + Map(SDL_SCANCODE_A, MOVE_LEFT); + Map(SDL_SCANCODE_RIGHT, MOVE_RIGHT); + Map(SDL_SCANCODE_D, MOVE_RIGHT); + Map(SDL_SCANCODE_SPACE, MOVE_UP); + Map(SDL_SCANCODE_RSHIFT, MOVE_UP); + Map(SDL_SCANCODE_LSHIFT, MOVE_DOWN); + Map(SDL_SCANCODE_LCTRL, MOVE_DOWN); + Map(SDL_SCANCODE_RCTRL, MOVE_DOWN); + + Map(SDL_SCANCODE_Q, BLOCK_FACE); + Map(SDL_SCANCODE_E, BLOCK_TURN); + Map(SDL_SCANCODE_TAB, BLOCK_NEXT); + Map(SDL_SCANCODE_RIGHTBRACKET, BLOCK_NEXT); + Map(SDL_SCANCODE_LEFTBRACKET, BLOCK_PREV); + + Map(SDL_SCANCODE_INSERT, BLOCK_PLACE); + Map(SDL_SCANCODE_RETURN, BLOCK_PLACE); + Map(SDL_SCANCODE_MENU, BLOCK_PICK); + Map(SDL_SCANCODE_DELETE, BLOCK_REMOVE); + Map(SDL_SCANCODE_BACKSPACE, BLOCK_REMOVE); + + Map(SDL_SCANCODE_N, TOGGLE_COLLISION); + Map(SDL_SCANCODE_F1, TOGGLE_VISUAL); + Map(SDL_SCANCODE_F3, TOGGLE_DEBUG); + Map(SDL_SCANCODE_F4, TOGGLE_AUDIO); + + Map(SDL_SCANCODE_B, PRINT_BLOCK); + Map(SDL_SCANCODE_C, PRINT_CHUNK); + Map(SDL_SCANCODE_L, PRINT_LIGHT); + Map(SDL_SCANCODE_P, PRINT_SELECTION); + + Map(SDL_SCANCODE_ESCAPE, EXIT); +} + + +void Keymap::Load(std::istream &is) { + TokenStreamReader in(is); + std::string key_name; + std::string action_name; + SDL_Scancode key; + Action action; + while (in.HasMore()) { + if (in.Peek().type == Token::STRING) { + in.ReadString(key_name); + key = SDL_GetScancodeFromName(key_name.c_str()); + } else { + key = SDL_Scancode(in.GetInt()); + } + in.Skip(Token::EQUALS); + in.ReadIdentifier(action_name); + action = StringToAction(action_name); + if (in.HasMore() && in.Peek().type == Token::SEMICOLON) { + in.Skip(Token::SEMICOLON); + } + Map(key, action); + } +} + +void Keymap::Save(std::ostream &out) { + for (unsigned int i = 0; i < NUM_SCANCODES; ++i) { + if (codemap[i] == NONE) continue; + + const char *str = SDL_GetScancodeName(SDL_Scancode(i)); + if (str && *str) { + out << '"'; + while (*str) { + if (*str == '"') { + out << "\\\""; + } else { + out << *str; + } + ++str; + } + out << '"'; + } else { + out << i; + } + + out << " = " << ActionToString(codemap[i]) << std::endl;; + } +} + + +const char *Keymap::ActionToString(Action action) { + switch (action) { + default: + case NONE: + return "none"; + case MOVE_FORWARD: + return "move_forward"; + case MOVE_BACKWARD: + return "move_backward"; + case MOVE_LEFT: + return "move_left"; + case MOVE_RIGHT: + return "move_right"; + case MOVE_UP: + return "move_up"; + case MOVE_DOWN: + return "move_down"; + case BLOCK_FACE: + return "block_face"; + case BLOCK_TURN: + return "block_turn"; + case BLOCK_NEXT: + return "block_next"; + case BLOCK_PREV: + return "block_prev"; + case BLOCK_PLACE: + return "block_place"; + case BLOCK_PICK: + return "block_pick"; + case BLOCK_REMOVE: + return "block_remove"; + case TOGGLE_COLLISION: + return "toggle_collision"; + case TOGGLE_AUDIO: + return "toggle_audio"; + case TOGGLE_VISUAL: + return "toggle_visual"; + case TOGGLE_DEBUG: + return "toggle_debug"; + case PRINT_BLOCK: + return "print_block"; + case PRINT_CHUNK: + return "print_chunk"; + case PRINT_LIGHT: + return "print_light"; + case PRINT_SELECTION: + return "print_selection"; + case EXIT: + return "exit"; + } +} + +Keymap::Action Keymap::StringToAction(const std::string &str) { + if (str == "move_forward") { + return MOVE_FORWARD; + } else if (str == "move_backward") { + return MOVE_BACKWARD; + } else if (str == "move_left") { + return MOVE_LEFT; + } else if (str == "move_right") { + return MOVE_RIGHT; + } else if (str == "move_up") { + return MOVE_UP; + } else if (str == "move_down") { + return MOVE_DOWN; + } else if (str == "block_face") { + return BLOCK_FACE; + } else if (str == "block_turn") { + return BLOCK_TURN; + } else if (str == "block_next") { + return BLOCK_NEXT; + } else if (str == "block_prev") { + return BLOCK_PREV; + } else if (str == "block_place") { + return BLOCK_PLACE; + } else if (str == "block_pick") { + return BLOCK_PICK; + } else if (str == "block_remove") { + return BLOCK_REMOVE; + } else if (str == "toggle_collision") { + return TOGGLE_COLLISION; + } else if (str == "toggle_audio") { + return TOGGLE_AUDIO; + } else if (str == "toggle_visual") { + return TOGGLE_VISUAL; + } else if (str == "toggle_debug") { + return TOGGLE_DEBUG; + } else if (str == "print_block") { + return PRINT_BLOCK; + } else if (str == "print_chunk") { + return PRINT_CHUNK; + } else if (str == "print_light") { + return PRINT_LIGHT; + } else if (str == "print_selection") { + return PRINT_SELECTION; + } else if (str == "exit") { + return EXIT; + } else { + return NONE; + } +} + }