Use unordered_map for keydown to allow codes above 255 (#248)

- Adds internal support for 32bit key codes, required for proper keyboard input on Linux
- Use gdk_keyval_name to get key name on Linux
This commit is contained in:
SSimco 2022-09-18 18:07:26 -07:00 committed by GitHub
parent 5e968eff4f
commit 9f02733a0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 143 additions and 83 deletions

View file

@ -170,16 +170,16 @@ int CemuApp::FilterEvent(wxEvent& event)
{
const auto& key_event = (wxKeyEvent&)event;
wxGetKeyState(wxKeyCode::WXK_F17);
uint32 keycode=fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags());
if(keycode<256)
g_window_info.keydown[keycode] = true;
g_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), true);
}
else if(event.GetEventType() == wxEVT_KEY_UP)
{
const auto& key_event = (wxKeyEvent&)event;
uint32 keycode=fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags());
if(keycode<256)
g_window_info.keydown[keycode] = false;
g_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), false);
}
else if(event.GetEventType() == wxEVT_KILL_FOCUS)
{
g_window_info.set_keystatesdown();
}
return wxApp::FilterEvent(event);

View file

@ -153,6 +153,15 @@ bool gui_isPadWindowOpen()
#include <dlfcn.h>
typedef void GdkDisplay;
namespace
{
const char* (*gdk_keyval_name)(unsigned int keyval);
}
std::string gui_gtkRawKeyCodeToString(uint32 keyCode)
{
return gdk_keyval_name(keyCode);
}
#endif
void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, class wxWindow* wxw)
@ -176,9 +185,11 @@ void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, c
Window (*dyn_gdk_x11_window_get_xid)(GdkWindow *window);
dyn_gdk_x11_window_get_xid = (Window(*)(GdkWindow *window))dlsym(RTLD_NEXT, "gdk_x11_window_get_xid");
gdk_keyval_name = (const char* (*)(unsigned int))dlsym(RTLD_NEXT, "gdk_keyval_name");
if(!dyn_gtk_widget_realize || !dyn_gtk_widget_get_window ||
!dyn_gdk_window_get_display || !dyn_gdk_x11_display_get_xdisplay ||
!dyn_gdk_x11_window_get_xid)
!dyn_gdk_x11_window_get_xid || !gdk_keyval_name)
{
cemuLog_log(LogType::Force, "Unable to load GDK symbols");
return;
@ -206,10 +217,7 @@ void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, c
bool gui_isKeyDown(int key)
{
if (key >= 256)
return false;
return g_window_info.keydown[key];
return g_window_info.get_keystate(key);
}
void gui_notifyGameLoaded()

View file

@ -41,14 +41,48 @@ struct WindowInfo
std::atomic_bool has_screenshot_request;
std::atomic_bool is_fullscreen;
std::atomic_bool keydown[256]{};
void set_keystate(uint32 keycode, bool state)
{
const std::lock_guard<std::mutex> lock(keycode_mutex);
m_keydown[keycode] = state;
};
bool get_keystate(uint32 keycode)
{
const std::lock_guard<std::mutex> lock(keycode_mutex);
auto result = m_keydown.find(keycode);
if (result == m_keydown.end())
return false;
return result->second;
}
void get_keystates(std::unordered_map<uint32, bool>& buttons_out)
{
const std::lock_guard<std::mutex> lock(keycode_mutex);
for (auto&& button : m_keydown)
{
buttons_out[button.first] = button.second;
}
}
void set_keystatesdown()
{
const std::lock_guard<std::mutex> lock(keycode_mutex);
std::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair<const uint32, bool>& el){ el.second = false; });
}
template <typename fn>
void iter_keystates(fn f)
{
const std::lock_guard<std::mutex> lock(keycode_mutex);
std::for_each(m_keydown.cbegin(), m_keydown.cend(), f);
}
WindowHandleInfo window_main;
WindowHandleInfo window_pad;
// canvas
WindowHandleInfo canvas_main;
WindowHandleInfo canvas_pad;
private:
std::mutex keycode_mutex;
// m_keydown keys must be valid ImGuiKey values
std::unordered_map<uint32, bool> m_keydown;
};
void gui_create();
@ -68,6 +102,9 @@ bool gui_isFullScreen();
void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, class wxWindow* wxw);
#if BOOST_OS_LINUX
std::string gui_gtkRawKeyCodeToString(uint32 keyCode);
#endif
/*
* Returns true if a screenshot request is queued
* Once this function has returned true, it will reset back to

View file

@ -41,7 +41,7 @@ void InputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, cons
}
static bool s_was_idle = true;
if (state.buttons.none()) {
if (!std::any_of(state.buttons.begin(), state.buttons.end(), [](auto el){ return el.second; })) {
s_was_idle = true;
return;
}
@ -49,58 +49,65 @@ void InputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, cons
if (!s_was_idle) {
return;
}
s_was_idle = false;
for (size_t i = 0; i < state.buttons.size(); ++i)
auto get_button_state = [&](uint32 key_id)
{
if (state.buttons[i])
auto result = state.buttons.find(key_id);
if (result == state.buttons.end())
return false;
return result->second;
};
s_was_idle = false;
for(auto && button : state.buttons)
{
if (button.second)
{
auto id=button.first;
if (controller->has_axis()) {
// test if one axis direction is pressed more than the other
if ((i == kAxisXP || i == kAxisXN) && (state.buttons[kAxisYP] || state.buttons[kAxisYN]))
if ((id == kAxisXP || id == kAxisXN) && (get_button_state(kAxisYP) || get_button_state(kAxisYN)))
{
if (std::abs(state.axis.y) > std::abs(state.axis.x))
continue;
}
else if ((i == kAxisYP || i == kAxisYN) && (state.buttons[kAxisXP] || state.buttons[kAxisXN]))
else if ((id == kAxisYP || id == kAxisYN) && (get_button_state(kAxisXP) || get_button_state(kAxisXN)))
{
if (std::abs(state.axis.x) > std::abs(state.axis.y))
continue;
}
else if ((i == kRotationXP || i == kRotationXN) && (state.buttons[kRotationYP] || state.buttons[kRotationYN]))
else if ((id == kRotationXP || id == kRotationXN) && (get_button_state(kRotationYP) || get_button_state(kRotationYN)))
{
if (std::abs(state.rotation.y) > std::abs(state.rotation.x))
continue;
}
else if ((i == kRotationYP || i == kRotationYN) && (state.buttons[kRotationXP] || state.buttons[kRotationXN]))
else if ((id == kRotationYP || id == kRotationYN) && (get_button_state(kRotationXP) || get_button_state(kRotationXN)))
{
if (std::abs(state.rotation.x) > std::abs(state.rotation.y))
continue;
}
else if ((i == kTriggerXP || i == kTriggerXN) && (state.buttons[kTriggerYP] || state.buttons[kTriggerYN]))
else if ((id == kTriggerXP || id == kTriggerXN) && (get_button_state(kTriggerYP) || get_button_state(kTriggerYN)))
{
if (std::abs(state.trigger.y) > std::abs(state.trigger.x))
continue;
}
else if ((i == kTriggerYP || i == kTriggerYN) && (state.buttons[kTriggerXP] || state.buttons[kTriggerXN]))
else if ((id == kTriggerYP || id == kTriggerYN) && (get_button_state(kTriggerXP) || get_button_state(kTriggerXN)))
{
if (std::abs(state.trigger.x) > std::abs(state.trigger.y))
continue;
}
// ignore too low button values on configuration
if (i >= kButtonAxisStart)
if (id >= kButtonAxisStart)
{
if (controller->get_axis_value(i) < 0.33f) {
forceLogDebug_printf("skipping since value too low %f", controller->get_axis_value(i));
if (controller->get_axis_value(id) < 0.33f) {
forceLogDebug_printf("skipping since value too low %f", controller->get_axis_value(id));
s_was_idle = true;
return;
}
}
}
emulated_controller->set_mapping(mapping, controller, i);
element->SetValue(controller->get_button_name(i));
emulated_controller->set_mapping(mapping, controller, id);
element->SetValue(controller->get_button_name(id));
element->SetBackgroundColour(kKeyColourNormalMode);
m_color_backup[element->GetId()] = kKeyColourNormalMode;
break;