-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/features' into work
- Loading branch information
Showing
38 changed files
with
1,000 additions
and
575 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
add_library(hotkeys OBJECT | ||
hotkeys.cpp | ||
) | ||
|
||
add_dependencies(hotkeys third_party config_emu) | ||
|
||
target_compile_definitions(hotkeys PUBLIC WIN32_LEAN_AND_MEAN) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#define __APICALL_EXTERN | ||
#include "hotkeys.h" | ||
#undef __APICALL_EXTERN | ||
|
||
#include "config_emu.h" | ||
|
||
#include <unordered_map> | ||
|
||
class Hotkeys: public IHotkeys { | ||
private: | ||
struct HkBacks { | ||
HkCommand cmd; | ||
HkFunc func; | ||
}; | ||
|
||
struct KBind { | ||
SDL_Keycode kc; | ||
uint16_t mod; | ||
}; | ||
|
||
std::vector<HkBacks> m_cbacks = {}; | ||
std::array<KBind, (size_t)HkCommand::COMMANDS_MAX> m_binds = {{SDLK_UNKNOWN, 0}}; | ||
uint32_t m_state = 0; | ||
|
||
HkCommand lookupCommand(SDL_Keycode kc, uint16_t mod) { | ||
for (uint32_t c = uint32_t(HkCommand::UNKNOWN); c < uint32_t(HkCommand::COMMANDS_MAX); ++c) { | ||
auto& bind = m_binds[(uint32_t)c]; | ||
if (kc == bind.kc && mod == bind.mod) return HkCommand(c); | ||
} | ||
|
||
return HkCommand::UNKNOWN; | ||
} | ||
|
||
public: | ||
Hotkeys() { | ||
static std::unordered_map<std::string, HkCommand> map = { | ||
{"gamereport.send", HkCommand::GAMEREPORT_SEND_REPORT}, | ||
{"overlay.open", HkCommand::OVERLAY_MENU}, | ||
|
||
{"controller.l3", HkCommand::CONTROLLER_L3}, | ||
{"controller.r3", HkCommand::CONTROLLER_R3}, | ||
{"controller.options", HkCommand::CONTROLLER_OPTIONS}, | ||
{"controller.dpad_up", HkCommand::CONTROLLER_DPAD_UP}, | ||
{"controller.dpad_right", HkCommand::CONTROLLER_DPAD_RIGHT}, | ||
{"controller.dpad_down", HkCommand::CONTROLLER_DPAD_DOWN}, | ||
{"controller.dpad_left", HkCommand::CONTROLLER_DPAD_LEFT}, | ||
{"controller.l2", HkCommand::CONTROLLER_L2}, | ||
{"controller.r2", HkCommand::CONTROLLER_R2}, | ||
{"controller.l1", HkCommand::CONTROLLER_L1}, | ||
{"controller.r1", HkCommand::CONTROLLER_R1}, | ||
{"controller.triangle", HkCommand::CONTROLLER_TRIANGLE}, | ||
{"controller.circle", HkCommand::CONTROLLER_CIRCLE}, | ||
{"controller.cross", HkCommand::CONTROLLER_CROSS}, | ||
{"controller.square", HkCommand::CONTROLLER_SQUARE}, | ||
{"controller.touchpad", HkCommand::CONTROLLER_TOUCH_PAD}, | ||
{"controller.lx+", HkCommand::CONTROLLER_LX_UP}, | ||
{"controller.lx-", HkCommand::CONTROLLER_LX_DOWN}, | ||
{"controller.ly+", HkCommand::CONTROLLER_LY_UP}, | ||
{"controller.ly-", HkCommand::CONTROLLER_LY_DOWN}, | ||
{"controller.rx+", HkCommand::CONTROLLER_RX_UP}, | ||
{"controller.rx-", HkCommand::CONTROLLER_RX_DOWN}, | ||
{"controller.ry+", HkCommand::CONTROLLER_RY_UP}, | ||
{"controller.ry-", HkCommand::CONTROLLER_RY_DOWN}, | ||
}; | ||
|
||
auto readBind = [](std::string& str, KBind* kb) -> bool { | ||
if (str.length() == 0) return false; | ||
auto delim = str.find_last_of("||"); | ||
if (delim != std::string::npos) { | ||
auto mod = str.substr(0, delim - 1); | ||
auto key = str.substr(delim + 1); | ||
kb->kc = SDL_GetScancodeFromName(key.c_str()); | ||
|
||
switch (SDL_GetScancodeFromName(mod.c_str())) { | ||
case SDL_SCANCODE_LALT: kb->mod = KMOD_LALT; return true; | ||
case SDL_SCANCODE_LCTRL: kb->mod = KMOD_LCTRL; return true; | ||
case SDL_SCANCODE_LSHIFT: kb->mod = KMOD_LSHIFT; return true; | ||
|
||
case SDL_SCANCODE_RALT: kb->mod = KMOD_RALT; return true; | ||
case SDL_SCANCODE_RCTRL: kb->mod = KMOD_RCTRL; return true; | ||
case SDL_SCANCODE_RSHIFT: kb->mod = KMOD_RSHIFT; return true; | ||
|
||
default: return false; | ||
} | ||
} | ||
|
||
if ((kb->kc = SDL_GetScancodeFromName(str.c_str())) != SDL_SCANCODE_UNKNOWN) { | ||
kb->mod = 0x0000; | ||
return true; | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
auto [lock, jData] = accessConfig()->accessModule(ConfigModFlag::CONTROLS); | ||
for (auto& [bname, sdlkeys]: (*jData)["keybinds"].items()) { | ||
auto it = map.find(bname.c_str()); | ||
if (it == map.end()) continue; | ||
std::string temp; | ||
sdlkeys.get_to(temp); | ||
|
||
auto& bind = m_binds[(uint32_t)it->second]; | ||
if (!readBind(temp, &bind)) { | ||
printf("Missing key binding for \"%s\"!\n", bname.c_str()); | ||
bind = {0, 0}; | ||
continue; | ||
} | ||
|
||
for (uint32_t c = uint32_t(HkCommand::UNKNOWN); c < uint32_t(HkCommand::COMMANDS_MAX); ++c) { | ||
auto& tbind = m_binds[(uint32_t)c]; | ||
if (bind.kc == SDL_SCANCODE_UNKNOWN || tbind.kc == SDL_SCANCODE_UNKNOWN) continue; | ||
if (tbind.kc == bind.kc && tbind.mod == bind.mod && (uint32_t)it->second != c) { | ||
printf("Key conflict found! Please rebind your \"%s\" key.\n", bname.c_str()); | ||
bind = {0, 0}; | ||
continue; | ||
} | ||
} | ||
} | ||
} | ||
|
||
void registerCallback(HkCommand cmd, HkFunc func) final { m_cbacks.emplace_back(cmd, func); } | ||
|
||
bool isPressed(HkCommand cmd) final { return (m_state & (1ull << (uint8_t)cmd)) != 0; } | ||
|
||
int32_t isPressedEx(HkCommand cmd1, HkCommand cmd2, int32_t ifcmd1, int32_t ifcmd2, int32_t def) final { | ||
return isPressed(cmd1) ? ifcmd1 : (isPressed(cmd2) ? ifcmd2 : def); | ||
} | ||
|
||
void update(const SDL_KeyboardEvent* event) final { | ||
bool pressed = event->type == SDL_KEYDOWN; | ||
HkCommand cmd = lookupCommand(event->keysym.scancode, event->keysym.mod & 0x03C3); | ||
if (cmd == HkCommand::UNKNOWN) return; | ||
uint32_t bit = (1ull << (uint8_t)cmd); | ||
|
||
if (pressed && ((m_state & bit) == 0)) { | ||
for (auto& hkc: m_cbacks) | ||
if (hkc.cmd == cmd) hkc.func(cmd); | ||
|
||
m_state |= bit; | ||
} else if (!pressed && ((m_state & bit) != 0)) { | ||
m_state &= ~bit; | ||
} | ||
} | ||
}; | ||
|
||
IHotkeys& accessHotkeys() { | ||
static Hotkeys ih; | ||
return ih; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#pragma once | ||
|
||
#include "utility/utility.h" | ||
|
||
#include <SDL2/SDL.h> | ||
#include <functional> | ||
|
||
enum class HkCommand { | ||
UNKNOWN = 0, | ||
|
||
// System commands | ||
GAMEREPORT_SEND_REPORT, | ||
OVERLAY_MENU, | ||
|
||
// Gamepad emulation | ||
CONTROLLER_L3, | ||
CONTROLLER_R3, | ||
CONTROLLER_OPTIONS, | ||
CONTROLLER_DPAD_UP, | ||
CONTROLLER_DPAD_RIGHT, | ||
CONTROLLER_DPAD_DOWN, | ||
CONTROLLER_DPAD_LEFT, | ||
CONTROLLER_L2, | ||
CONTROLLER_R2, | ||
CONTROLLER_L1, | ||
CONTROLLER_R1, | ||
CONTROLLER_TRIANGLE, | ||
CONTROLLER_CIRCLE, | ||
CONTROLLER_CROSS, | ||
CONTROLLER_SQUARE, | ||
CONTROLLER_TOUCH_PAD, | ||
CONTROLLER_LX_UP, | ||
CONTROLLER_LX_DOWN, | ||
CONTROLLER_LY_UP, | ||
CONTROLLER_LY_DOWN, | ||
CONTROLLER_RX_UP, | ||
CONTROLLER_RX_DOWN, | ||
CONTROLLER_RY_UP, | ||
CONTROLLER_RY_DOWN, | ||
|
||
/** | ||
* Warning! If this value ever exceeds 32 you should increase | ||
* the size of `m_state` variable in `class Hotkeys` aswell! | ||
*/ | ||
COMMANDS_MAX, | ||
}; | ||
|
||
typedef std::function<void(HkCommand)> HkFunc; | ||
|
||
class IHotkeys { | ||
CLASS_NO_COPY(IHotkeys); | ||
CLASS_NO_MOVE(IHotkeys); | ||
|
||
public: | ||
IHotkeys() = default; | ||
virtual ~IHotkeys() = default; | ||
|
||
virtual void registerCallback(HkCommand cmd, HkFunc func) = 0; | ||
virtual bool isPressed(HkCommand cmd) = 0; | ||
virtual int32_t isPressedEx(HkCommand cmd1, HkCommand cmd2, int32_t ifcmd1, int32_t ifcmd2, int32_t def) = 0; | ||
virtual void update(const SDL_KeyboardEvent* event) = 0; | ||
}; | ||
|
||
#if defined(__APICALL_EXTERN) | ||
#define __APICALL __declspec(dllexport) | ||
#elif defined(__APICALL_IMPORT) | ||
#define __APICALL __declspec(dllimport) | ||
#else | ||
#define __APICALL | ||
#endif | ||
__APICALL IHotkeys& accessHotkeys(); | ||
#undef __APICALL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.