Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ add_executable(oopetris
src/service_provider.hpp
src/scenes/main_menu/main_menu.cpp
src/scenes/main_menu/main_menu.hpp
src/scenes/settings_menu/settings_menu.cpp
src/scenes/settings_menu/settings_menu.hpp
src/ui/button.hpp
src/ui/focus_group.hpp
src/ui/focusable.hpp
Expand Down
14 changes: 13 additions & 1 deletion src/application.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "application.hpp"
#include "capabilities.hpp"
#include "scenes/scene.hpp"
#include <fmt/format.h>
#include <fstream>
Expand Down Expand Up @@ -56,7 +57,18 @@ void Application::handle_event(const SDL_Event& event) {
for (usize i = 0; i < m_scene_stack.size(); ++i) {
const auto index = m_scene_stack.size() - i - 1;
if (m_scene_stack.at(index)->handle_event(event)) {
break;
return;
}
}

if (utils::device_supports_keys() && event.type == SDL_KEYDOWN) {

if (event.key.keysym.sym == SDLK_PLUS or event.key.keysym.sym == SDLK_KP_PLUS) {
m_music_manager.change_volume(1);
return;
} else if (event.key.keysym.sym == SDLK_MINUS or event.key.keysym.sym == SDLK_KP_MINUS) {
m_music_manager.change_volume(-1);
return;
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/capabilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,29 @@
return false;
#endif
}


[[nodiscard]] std::vector<i64> utils::get_bound_keys() {
std::vector<i64> bound_keys{};
for (const auto& [_, keys] : utils::key_map) {
for (const auto key : keys) {
bound_keys.push_back(key);
}
}
return bound_keys;
}


[[nodiscard]] std::vector<i64> utils::get_bound_keys(const std::vector<utils::CrossPlatformAction>& actions) {
std::vector<i64> bound_keys{};
for (const auto& [value, keys] : utils::key_map) {
if (std::find(actions.cbegin(), actions.cend(), static_cast<utils::CrossPlatformAction>(value))
== actions.cend()) {
continue;
}
for (const auto key : keys) {
bound_keys.push_back(key);
}
}
return bound_keys;
}
108 changes: 68 additions & 40 deletions src/capabilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#endif

/* should we replace this by using defines in here, that would be real compile time but I think it' more ugly
e.g
e.g
#if defined(__ANDROID__)
#define DEVICE_SUPPORTS_TOUCH
#undef DEVICE_SUPPORTS_KEYS
Expand All @@ -38,38 +38,63 @@ namespace utils {

// the PAUSE and UNPAUSE might be different (e.g on android, even if androids map is stub,
// it checks in the usage of these for the CrossPlatformAction!), so don't remove the duplication here!
enum class CrossPlatformAction : u8 { OK, PAUSE, UNPAUSE, EXIT, DOWN, UP };
enum class CrossPlatformAction : u8 {
OK,
PAUSE,
UNPAUSE,
EXIT,
DOWN,
UP,
LEFT,
RIGHT,
CLOSE,
OPEN_SETTINGS,
};

//TODO: support multiple keys
static std::unordered_map<u8, std::vector<i64>> key_map =
#if defined(__ANDROID__)
{
{ static_cast<u8>(CrossPlatformAction::OK), { 0 }},
{ static_cast<u8>(CrossPlatformAction::PAUSE), { 0 }},
{static_cast<u8>(CrossPlatformAction::UNPAUSE), { 0 }},
{ static_cast<u8>(CrossPlatformAction::EXIT), { 0 }},
{ static_cast<u8>(CrossPlatformAction::DOWN), { 0 }},
{ static_cast<u8>(CrossPlatformAction::UP), { 0 }}
{ static_cast<u8>(CrossPlatformAction::OK), { 0 }},
{ static_cast<u8>(CrossPlatformAction::PAUSE), { 0 }},
{ static_cast<u8>(CrossPlatformAction::UNPAUSE), { 0 }},
{ static_cast<u8>(CrossPlatformAction::EXIT), { 0 }},
{ static_cast<u8>(CrossPlatformAction::DOWN), { 0 }},
{ static_cast<u8>(CrossPlatformAction::UP), { 0 }},
{ static_cast<u8>(CrossPlatformAction::LEFT), { 0 }},
{ static_cast<u8>(CrossPlatformAction::RIGHT), { 0 }},
{ static_cast<u8>(CrossPlatformAction::CLOSE), { 0 }},
{static_cast<u8>(CrossPlatformAction::OPEN_SETTINGS), { 0 }}
};
#elif defined(__SWITCH__)
{
{ static_cast<u8>(CrossPlatformAction::OK), { JOYCON_A } },
{ static_cast<u8>(CrossPlatformAction::PAUSE), { JOYCON_PLUS } },
{ static_cast<u8>(CrossPlatformAction::UNPAUSE), { JOYCON_PLUS } },
{ static_cast<u8>(CrossPlatformAction::EXIT), { JOYCON_MINUS } },
{ static_cast<u8>(CrossPlatformAction::DOWN),
{ JOYCON_CROSS_DOWN, JOYCON_LDPAD_DOWN, JOYCON_RDPAD_DOWN } },
{ static_cast<u8>(CrossPlatformAction::UP), { JOYCON_CROSS_UP, JOYCON_LDPAD_UP, JOYCON_RDPAD_UP } }
};
{ static_cast<u8>(CrossPlatformAction::OK),{ JOYCON_A } },
{ static_cast<u8>(CrossPlatformAction::PAUSE), { JOYCON_PLUS }},
{ static_cast<u8>(CrossPlatformAction::UNPAUSE), { JOYCON_PLUS }},
{ static_cast<u8>(CrossPlatformAction::EXIT), { JOYCON_MINUS }},
{ static_cast<u8>(CrossPlatformAction::DOWN),
{ JOYCON_CROSS_DOWN, JOYCON_LDPAD_DOWN, JOYCON_RDPAD_DOWN } },
{ static_cast<u8>(CrossPlatformAction::UP), { JOYCON_CROSS_UP, JOYCON_LDPAD_UP, JOYCON_RDPAD_UP }},
{ static_cast<u8>(CrossPlatformAction::LEFT),
{ JOYCON_CROSS_LEFT, JOYCON_LDPAD_LEFT, JOYCON_RDPAD_LEFT } },
{ static_cast<u8>(CrossPlatformAction::RIGHT),
{ JOYCON_CROSS_RIGHT, JOYCON_LDPAD_RIGHT, JOYCON_RDPAD_RIGHT } },
{ static_cast<u8>(CrossPlatformAction::CLOSE), { JOYCON_MINUS }},
{static_cast<u8>(CrossPlatformAction::OPEN_SETTINGS), { JOYCON_Y }},
};
#else
{
{ static_cast<u8>(CrossPlatformAction::OK), { SDLK_RETURN, SDLK_SPACE } },
{ static_cast<u8>(CrossPlatformAction::PAUSE), { SDLK_ESCAPE } },
{ static_cast<u8>(CrossPlatformAction::UNPAUSE), { SDLK_ESCAPE } },
{ static_cast<u8>(CrossPlatformAction::EXIT), { SDLK_RETURN } },
{ static_cast<u8>(CrossPlatformAction::DOWN), { SDLK_DOWN, SDLK_s } },
{ static_cast<u8>(CrossPlatformAction::UP), { SDLK_UP, SDLK_w } }
};
{ static_cast<u8>(CrossPlatformAction::OK), { SDLK_RETURN, SDLK_SPACE }},
{ static_cast<u8>(CrossPlatformAction::PAUSE), { SDLK_ESCAPE }},
{ static_cast<u8>(CrossPlatformAction::UNPAUSE), { SDLK_ESCAPE }},
{ static_cast<u8>(CrossPlatformAction::EXIT), { SDLK_RETURN }},
{ static_cast<u8>(CrossPlatformAction::DOWN), { SDLK_DOWN, SDLK_s }},
{ static_cast<u8>(CrossPlatformAction::UP), { SDLK_UP, SDLK_w }},
{ static_cast<u8>(CrossPlatformAction::LEFT), { SDLK_LEFT, SDLK_a }},
{ static_cast<u8>(CrossPlatformAction::RIGHT), { SDLK_RIGHT, SDLK_d }},
{ static_cast<u8>(CrossPlatformAction::CLOSE), { SDLK_ESCAPE }},
{static_cast<u8>(CrossPlatformAction::OPEN_SETTINGS), { SDLK_p }},
};
#endif


Expand All @@ -93,54 +118,57 @@ namespace utils {

[[nodiscard]] bool event_is_action(const SDL_Event& event, CrossPlatformAction action);

[[nodiscard]] std::vector<i64> get_bound_keys();
[[nodiscard]] std::vector<i64> get_bound_keys(const std::vector<CrossPlatformAction>& actions);

[[nodiscard]] constexpr std::string_view action_description(CrossPlatformAction action) {
#if defined(__ANDROID__)
switch (action) {
case CrossPlatformAction::OK:
return "NOT POSSIBLE";
case CrossPlatformAction::PAUSE:
return "Back Button";
case CrossPlatformAction::UNPAUSE:
return "Tap anywhere";
case CrossPlatformAction::EXIT:
return "Back Button";
case CrossPlatformAction::DOWN:
return "NOT POSSIBLE";
case CrossPlatformAction::UP:
return "NOT POSSIBLE";
default:
utils::unreachable();
}
UNUSED(action);
return "NOT POSSIBLE";
#elif defined(__SWITCH__)
switch (action) {
case CrossPlatformAction::OK:
return "A";
case CrossPlatformAction::PAUSE:
case CrossPlatformAction::UNPAUSE:
return "PLUS";
case CrossPlatformAction::CLOSE:
case CrossPlatformAction::EXIT:
return "MINUS";
case CrossPlatformAction::DOWN:
return "Down";
case CrossPlatformAction::UP:
return "Up";
case CrossPlatformAction::LEFT:
return "Left";
case CrossPlatformAction::RIGHT:
return "Right";
case CrossPlatformAction::OPEN_SETTINGS:
return "Y";
default:
utils::unreachable();
}
#else
UNUSED(action);
switch (action) {
case CrossPlatformAction::OK:
return "Enter";
case CrossPlatformAction::PAUSE:
return "Esc";
case CrossPlatformAction::UNPAUSE:
case CrossPlatformAction::CLOSE:
return "Esc";
case CrossPlatformAction::EXIT:
return "Enter";
case CrossPlatformAction::DOWN:
return "Down";
case CrossPlatformAction::UP:
return "Up";
case CrossPlatformAction::LEFT:
return "Left";
case CrossPlatformAction::RIGHT:
return "Right";
case CrossPlatformAction::OPEN_SETTINGS:
return "E";
default:
utils::unreachable();
}
Expand Down
35 changes: 35 additions & 0 deletions src/controls.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include "capabilities.hpp"
#include "key_codes.hpp"
#include "magic_enum_wrapper.hpp"

struct KeyboardControls final {
KeyCode rotate_left = KeyCode::Left;
Expand All @@ -10,4 +12,37 @@ struct KeyboardControls final {
KeyCode move_down = KeyCode::S;
KeyCode drop = KeyCode::W;
KeyCode hold = KeyCode::Tab;

void validate() const {
std::vector<KeyCode> already_bound_keycodes{};
if (utils::device_supports_keys()) {
for (const auto& key : utils::get_bound_keys({ utils::CrossPlatformAction::PAUSE,
utils::CrossPlatformAction::OPEN_SETTINGS })) {
const auto key_code = from_sdl_keycode(static_cast<SDL_KeyCode>(key));
if (key_code == KeyCode::Unknown) {
throw std::runtime_error("Couldn't map bound key '" + std::to_string(key) + "'");
}

already_bound_keycodes.push_back(key_code);
}
}


const std::vector<KeyCode> to_use{ rotate_left, rotate_right, move_left, move_right, move_down, drop, hold };


for (const auto key_to_use : to_use) {

if (std::find(already_bound_keycodes.cbegin(), already_bound_keycodes.cend(), key_to_use)
!= already_bound_keycodes.cend()) {
std::string error_code = "KeyCode already bound: '";
error_code += magic_enum::enum_name(key_to_use);
error_code += "'";

throw std::runtime_error(error_code);
}

already_bound_keycodes.push_back(key_to_use);
}
}
};
Loading