From 26c8d1dbdda16ae3af53c3aa7a71eaeb3ffd4acd Mon Sep 17 00:00:00 2001 From: jackun Date: Mon, 18 Jul 2022 02:52:11 +0300 Subject: [PATCH] WIP kinda working wayland hot keys --- src/app/main.cpp | 4 +- src/gl/gl_hud.cpp | 4 +- src/keybinds.cpp | 40 +++-------- src/keybinds.h | 8 +-- src/meson.build | 1 + src/overlay.cpp | 2 +- src/overlay_params.cpp | 1 + src/vulkan.cpp | 6 +- src/wsi_helpers.cpp | 147 ++++++++++++++++++++++++++++++++++------- src/wsi_helpers.h | 13 +++- 10 files changed, 158 insertions(+), 68 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index b49d7e7f..fadbef15 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -12,6 +12,8 @@ #include "../overlay.h" #include "notify.h" #include "mangoapp.h" +#include "wsi_helpers.h" +#include "keybinds.h" #include #include @@ -303,7 +305,7 @@ int main(int, char**) new_frame = false; } - check_keybinds(params, vendorID); + check_keybinds(keys_are_pressed, params); // Start the Dear ImGui frame { if (render(window)) { diff --git a/src/gl/gl_hud.cpp b/src/gl/gl_hud.cpp index cc549d46..d2374ae8 100644 --- a/src/gl/gl_hud.cpp +++ b/src/gl/gl_hud.cpp @@ -175,7 +175,7 @@ void imgui_create(void *ctx, GL_SESSION gl_session) if (gl_session == GL_SESSION_X11) wsi_conn.keys_are_pressed = keys_are_pressed; -#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#if !defined(MANGOAPP) && defined(VK_USE_PLATFORM_WAYLAND_KHR) if (gl_session == GL_SESSION_WL) { wsi_conn.keys_are_pressed = wl_keys_are_pressed; @@ -216,7 +216,7 @@ void imgui_render(unsigned int width, unsigned int height) process_control_socket(control_client, params); } - check_keybinds(wsi_conn, params); + check_keybinds(wsi_conn.keys_are_pressed, params); update_hud_info(sw_stats, params, vendorID); ImGuiContext *saved_ctx = ImGui::GetCurrentContext(); diff --git a/src/keybinds.cpp b/src/keybinds.cpp index cc6ef9b0..131a2be5 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -13,28 +13,6 @@ Clock::time_point last_f2_press, toggle_fps_limit_press , last_f12_press, reload_cfg_press, last_upload_press; -#ifdef VK_USE_PLATFORM_WAYLAND_KHR -std::map xkb_state; -void wl_key_pressed(const xkb_keysym_t key, uint32_t state) -{ - xkb_state[key] = !!state; -} - -bool wl_keys_are_pressed(const std::vector& keys) { - size_t pressed = 0; - for (KeySym ks : keys) { - if (xkb_state[ks]) - pressed++; - } - - if (pressed > 0 && pressed == keys.size()) { - return true; - } - - return false; -} -#endif - #if defined(HAVE_X11) bool keys_are_pressed(const std::vector& keys) { @@ -83,7 +61,7 @@ bool keys_are_pressed(const std::vector& keys) { } #endif -void check_keybinds(wsi_connection& wsi, struct overlay_params& params){ +void check_keybinds(fun_keys_are_pressed keys_are_pressed, struct overlay_params& params){ using namespace std::chrono_literals; auto now = Clock::now(); /* us */ auto elapsedF2 = now - last_f2_press; @@ -99,14 +77,14 @@ void check_keybinds(wsi_connection& wsi, struct overlay_params& params){ auto keyPressDelay = 400ms; - if (!wsi.keys_are_pressed) + if (!keys_are_pressed) { - SPDLOG_DEBUG("wsi.keys_are_pressed is not set!"); + SPDLOG_DEBUG("keys_are_pressed is not set!"); return; } if (elapsedF2 >= keyPressDelay && - wsi.keys_are_pressed(params.toggle_logging)) { + keys_are_pressed(params.toggle_logging)) { last_f2_press = now; if (logger->is_active()) { logger->stop_logging(); @@ -117,7 +95,7 @@ void check_keybinds(wsi_connection& wsi, struct overlay_params& params){ } if (elapsedFpsLimitToggle >= keyPressDelay && - wsi.keys_are_pressed(params.toggle_fps_limit)) { + keys_are_pressed(params.toggle_fps_limit)) { toggle_fps_limit_press = now; for (size_t i = 0; i < params.fps_limit.size(); i++){ uint32_t fps_limit = params.fps_limit[i]; @@ -136,26 +114,26 @@ void check_keybinds(wsi_connection& wsi, struct overlay_params& params){ } if (elapsedF12 >= keyPressDelay && - wsi.keys_are_pressed(params.toggle_hud)) { + keys_are_pressed(params.toggle_hud)) { last_f12_press = now; params.no_display = !params.no_display; } if (elapsedReloadCfg >= keyPressDelay && - wsi.keys_are_pressed(params.reload_cfg)) { + keys_are_pressed(params.reload_cfg)) { parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG")); _params = ¶ms; reload_cfg_press = now; } if (params.permit_upload && elapsedUpload >= keyPressDelay && - wsi.keys_are_pressed(params.upload_log)) { + keys_are_pressed(params.upload_log)) { last_upload_press = now; logger->upload_last_log(); } if (params.permit_upload && elapsedUpload >= keyPressDelay && - wsi.keys_are_pressed(params.upload_logs)) { + keys_are_pressed(params.upload_logs)) { last_upload_press = now; logger->upload_last_logs(); } diff --git a/src/keybinds.h b/src/keybinds.h index d69886ca..59bcebb7 100644 --- a/src/keybinds.h +++ b/src/keybinds.h @@ -12,10 +12,8 @@ typedef uint32_t xkb_keysym_t; struct wsi_connection; struct overlay_params; -void check_keybinds(wsi_connection&, overlay_params& params); +typedef std::function& keys)> fun_keys_are_pressed; + +void check_keybinds(fun_keys_are_pressed, overlay_params& params); bool keys_are_pressed(const std::vector& keys); -#ifdef VK_USE_PLATFORM_WAYLAND_KHR -bool wl_keys_are_pressed(const std::vector& keys); -void wl_key_pressed(const xkb_keysym_t key, uint32_t state); -#endif #endif //MANGOHUD_KEYBINDS_H diff --git a/src/meson.build b/src/meson.build index d3ba997a..6d1f6eac 100644 --- a/src/meson.build +++ b/src/meson.build @@ -249,6 +249,7 @@ if get_option('mangoapp') and sizeof_ptr == 8 spdlog_dep, dbus_dep, dep_x11, + dep_xkb, glfw3_dep, json_dep, ], diff --git a/src/overlay.cpp b/src/overlay.cpp index 07d322bd..aa7d2604 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -252,7 +252,7 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru #ifndef MANGOAPP window_has_focus(sw_stats.wsi); - SPDLOG_DEBUG("lost focus: {}", sw_stats.lost_focus); +// SPDLOG_DEBUG("lost focus: {}", sw_stats.lost_focus); #endif sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed; diff --git a/src/overlay_params.cpp b/src/overlay_params.cpp index af8f50cd..5adca398 100644 --- a/src/overlay_params.cpp +++ b/src/overlay_params.cpp @@ -133,6 +133,7 @@ parse_string_to_keysym_vec(const char *str) for (auto& ks : keyStrings) { trim(ks); auto xk = xkb_keysym_from_name(ks.c_str(), XKB_KEYSYM_NO_FLAGS); + SPDLOG_DEBUG("KeySym: {}, {:08X}", ks, xk); if (xk) keys.push_back(xk); else diff --git a/src/vulkan.cpp b/src/vulkan.cpp index 40150a58..ab60c7c6 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -479,6 +479,10 @@ static void overlay_DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, { struct instance_data *instance_data = FIND(struct instance_data, instance); struct surface_data *surface_data = FIND(struct surface_data, surface); + + if (surface_data->wsi.wl.display) + wsi_wayland_deinit(surface_data->wsi); + destroy_surface_data(surface_data); instance_data->vtable.DestroySurfaceKHR(instance, surface, pAllocator); } @@ -536,7 +540,7 @@ static void snapshot_swapchain_frame(struct swapchain_data *data) struct device_data *device_data = data->device; struct instance_data *instance_data = device_data->instance; update_hud_info(data->sw_stats, instance_data->params, device_data->properties.vendorID); - check_keybinds(data->surface_data->wsi, instance_data->params); + check_keybinds(data->surface_data->wsi.keys_are_pressed, instance_data->params); #ifdef __linux__ if (instance_data->params.control >= 0) { control_client_check(instance_data->params.control, instance_data->control_client, gpu.c_str()); diff --git a/src/wsi_helpers.cpp b/src/wsi_helpers.cpp index 84d8976b..6237d646 100644 --- a/src/wsi_helpers.cpp +++ b/src/wsi_helpers.cpp @@ -7,6 +7,7 @@ #include #endif #include "wsi_helpers.h" +#include "keybinds.h" //TODO global funcs or pass by pointer with wsi_connection? #ifdef VK_USE_PLATFORM_XCB_KHR @@ -98,60 +99,144 @@ void window_has_focus(wsi_connection* conn) #endif } + +// -------- Wayland -------- // + +struct table_entry { +// xkb_keysym_t symbol; + xkb_keycode_t code; + size_t level; + bool operator==(const table_entry& r) const + { + return code == r.code && level == r.level; + } +}; + +namespace std { + + template <> + struct hash + { + std::size_t operator()(const table_entry& k) const + { + using std::hash; + return (hash()(k.code) ^ (hash()(k.level) << 1)); + } + }; + +} + +static std::unordered_map> g_keysym_map; + struct wl_state { // wl_shell *shell; // wl_seat *seat; - wsi_connection *wsi; - xkb_context *ctx; - xkb_keymap *keymap; - struct xkb_state *state; -} g_wl_state {}; //TODO per surface etc instance? + xkb_context *ctx; + xkb_keymap *keymap; + struct xkb_state *state; +}; + +// #ifdef VK_USE_PLATFORM_WAYLAND_KHR +static std::unordered_map xkb_state; +void wl_key_pressed(const xkb_keycode_t key, uint32_t state) +{ + xkb_state[key] = !!state; +} + +bool wl_keys_are_pressed(const std::vector& keys) { + size_t pressed = 0; + for (auto ks : keys) { + auto kcs = g_keysym_map[ks]; +// SPDLOG_DEBUG("code: {}, sym: {:08X}", kc.code, ks); + for (const auto& entry : kcs) + if (xkb_state[entry.code]) + pressed++; + } + + if (pressed > 0 && pressed == keys.size()) { + return true; + } + + return false; +} +// #endif + +static void key_iter(struct xkb_keymap* map, xkb_keycode_t code, void* data) +{ + size_t n_levels = xkb_keymap_num_levels_for_key(map, code, 0); + for (size_t level = 0; level < n_levels; level++) { + const xkb_keysym_t* symbols; + size_t n = xkb_keymap_key_get_syms_by_level(map, code, 0, level, &symbols); + for (size_t i = 0; i < n; i++) + g_keysym_map[symbols[i]].push_back ({ code, level }); + } +} static void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { SPDLOG_DEBUG("{}", __func__); + auto conn = reinterpret_cast(data); + wl_state* state = reinterpret_cast(conn->userdata); + + if (!state->ctx) + return; assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); char *map_shm = reinterpret_cast(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0)); assert(map_shm != MAP_FAILED); - xkb_keymap_unref(g_wl_state.keymap); - g_wl_state.keymap = xkb_keymap_new_from_string(g_wl_state.ctx, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, - XKB_KEYMAP_COMPILE_NO_FLAGS); // FIXME probably leaking stuff + xkb_keymap_unref(state->keymap); + state->keymap = xkb_keymap_new_from_string(state->ctx, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(map_shm, size); close(fd); - xkb_state_unref(g_wl_state.state); - g_wl_state.state = xkb_state_new(g_wl_state.keymap); // FIXME probably leaking stuff + xkb_state_unref(state->state); + state->state = xkb_state_new(state->keymap); + xkb_keymap_key_for_each(state->keymap, key_iter, data); } static void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - auto wsi = reinterpret_cast(data); - SPDLOG_DEBUG("{}: {} == {}", __func__, (void*)wsi->wl.surface, (void*)surface); - if (wsi->focus_changed && surface == wsi->wl.surface) - wsi->focus_changed(true); + auto conn = reinterpret_cast(data); + SPDLOG_DEBUG("{}: {} == {}", __func__, (void*)conn->wl.surface, (void*)surface); + if (conn->focus_changed && surface == conn->wl.surface) + conn->focus_changed(true); } static void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { SPDLOG_DEBUG("{}: {}", __func__, (void*)surface); - auto wsi = reinterpret_cast(data); - if (wsi->focus_changed && surface == wsi->wl.surface) - wsi->focus_changed(false); + auto conn = reinterpret_cast(data); + if (conn->focus_changed && surface == conn->wl.surface) + conn->focus_changed(false); } static void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - auto wsi = reinterpret_cast(data); + auto conn = reinterpret_cast(data); + wl_state* wlstate = reinterpret_cast(conn->userdata); + if (!wlstate->ctx) + return; + uint32_t keycode = key + 8; - xkb_keysym_t sym = xkb_state_key_get_one_sym(g_wl_state.state, keycode); - if (wsi->key_pressed) - wsi->key_pressed(sym, state); +// xkb_state_update_key(wlstate->state, keycode, state ? xkb_key_direction::XKB_KEY_DOWN : xkb_key_direction::XKB_KEY_UP); + auto level = xkb_state_key_get_level(wlstate->state, keycode, 0); + xkb_keysym_t sym = xkb_state_key_get_one_sym(wlstate->state, keycode); +// xkb_keysym_t sym = wlstate->xkb_keycode_map[{keycode, level}]; - SPDLOG_DEBUG("{}: key pressed: {}, {}, {:08x}", __func__, key, state, sym); +// if (conn->key_pressed) +// conn->key_pressed(keycode, state); + wl_key_pressed(keycode, state); + SPDLOG_DEBUG("{}: key pressed: level:{}, keycode: {}, {}, keysym: {:08X}", __func__, level, keycode, state ? "down" : "up ", sym); } static void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { SPDLOG_DEBUG("{}", __func__); + auto conn = reinterpret_cast(data); + wl_state* wlstate = reinterpret_cast(conn->userdata); + if (!wlstate->ctx) + return; + + xkb_state_update_mask(wlstate->state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); } static struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers}; @@ -164,6 +249,7 @@ static void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabi wl_keyboard_add_listener (keyboard, &keyboard_listener, data); } } + static struct wl_seat_listener seat_listener = {&seat_capabilities}; static void registry_add_object (void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { @@ -175,6 +261,7 @@ static void registry_add_object (void *data, struct wl_registry *registry, uint3 wl_seat_add_listener (seat, &seat_listener, data); } } + static void registry_remove_object (void *data, struct wl_registry *registry, uint32_t name) { } @@ -184,8 +271,20 @@ static struct wl_registry_listener registry_listener = {®istry_add_object, &r void wsi_wayland_init(wsi_connection& conn) { auto registry = wl_display_get_registry(conn.wl.display); - g_wl_state.ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); //FIXME probably leaking stuff - g_wl_state.wsi = &conn; //TODO per surfacei nstance? + auto state = new wl_state(); + state->ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!state->ctx) + SPDLOG_ERROR("Failed to create XKB context!"); + conn.userdata = state; wl_registry_add_listener(registry, ®istry_listener, &conn); wl_display_roundtrip(conn.wl.display); } + +void wsi_wayland_deinit(wsi_connection& conn) +{ + wl_state* state = reinterpret_cast(conn.userdata); + xkb_state_unref(state->state); + xkb_keymap_unref(state->keymap); + xkb_context_unref(state->ctx); + delete reinterpret_cast(conn.userdata); +} diff --git a/src/wsi_helpers.h b/src/wsi_helpers.h index e93a6bac..07994d77 100644 --- a/src/wsi_helpers.h +++ b/src/wsi_helpers.h @@ -20,31 +20,36 @@ typedef uint32_t xkb_keysym_t; #include #endif +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +bool wl_keys_are_pressed(const std::vector& keys); +void wl_key_pressed(const xkb_keycode_t key, uint32_t state); +#endif struct wsi_connection { std::function focus_changed; std::function key_pressed; std::function& keys)> keys_are_pressed; + void* userdata {}; #ifdef VK_USE_PLATFORM_XCB_KHR struct xcb { xcb_connection_t *conn; xcb_window_t window; - } xcb; + } xcb {}; #endif #ifdef VK_USE_PLATFORM_XLIB_KHR struct xlib { Display *dpy; Window window; int evmask; - } xlib; + } xlib {}; #endif #ifdef VK_USE_PLATFORM_WAYLAND_KHR struct wl { wl_display *display; wl_surface *surface; - } wl; + } wl {}; #endif }; @@ -52,4 +57,6 @@ struct wsi_connection // bool check_window_focus(const wsi_connection&); void wsi_wayland_init(wsi_connection& conn); +void wsi_wayland_deinit(wsi_connection& conn); +