From db9a23eb5a309e4500f30253ff2e324fa6ce2649 Mon Sep 17 00:00:00 2001 From: jackun Date: Thu, 2 Jun 2022 23:03:53 +0300 Subject: [PATCH] wip xkbcommon --- meson.build | 10 +++- src/gl/gl_hud.cpp | 17 +++++- src/gl/gl_hud.h | 11 +++- src/gl/inject_egl.cpp | 125 +++++++++++++++++++++++++++++++++++++++-- src/gl/inject_glx.cpp | 2 +- src/keybinds.cpp | 101 ++++++++++++++++++++++++++++++--- src/keybinds.h | 67 ++++------------------ src/overlay.h | 1 - src/overlay_params.cpp | 25 ++++----- src/overlay_params.h | 13 +++-- src/vulkan.cpp | 11 +++- src/wsi_helpers.cpp | 67 +++++++++++++++------- src/wsi_helpers.h | 24 ++++++-- 13 files changed, 349 insertions(+), 125 deletions(-) diff --git a/meson.build b/meson.build index 251a3f77..8127a56b 100644 --- a/meson.build +++ b/meson.build @@ -84,6 +84,7 @@ vulkan_wsi_args = [] vulkan_wsi_deps = [] if is_unixy + dep_xkb = dependency('xkbcommon', required: true) dep_x11 = dependency('x11', required: get_option('with_x11')) dep_xcb = dependency('xcb', required: get_option('with_x11')) dep_wayland_client = dependency('wayland-client', @@ -92,10 +93,15 @@ if is_unixy else dep_x11 = null_dep dep_xcb = null_dep + dep_xkb = null_dep dep_wayland_client = null_dep dbus_dep = null_dep endif +if dep_xkb.found() + pre_args += '-DHAVE_XKBCOMMON' +endif + if dep_x11.found() vulkan_wsi_args += ['-DVK_USE_PLATFORM_XLIB_KHR'] vulkan_wsi_deps += dep_x11.partial_dependency(compile_args : true, includes : true) @@ -104,9 +110,9 @@ if dep_xcb.found() vulkan_wsi_args += ['-DVK_USE_PLATFORM_XCB_KHR'] vulkan_wsi_deps += dep_xcb #.partial_dependency(compile_args : true, includes : true) endif -if dep_wayland_client.found() +if dep_wayland_client.found() and dep_xkb.found() vulkan_wsi_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR'] - vulkan_wsi_deps += dep_wayland_client + vulkan_wsi_deps += [dep_wayland_client, dep_xkb] endif if is_unixy and not dep_x11.found() and not dep_wayland_client.found() diff --git a/src/gl/gl_hud.cpp b/src/gl/gl_hud.cpp index 90c11e3b..cc549d46 100644 --- a/src/gl/gl_hud.cpp +++ b/src/gl/gl_hud.cpp @@ -14,6 +14,7 @@ #include "notify.h" #include "blacklist.h" #include "wsi_helpers.h" +#include "keybinds.h" #ifdef HAVE_DBUS #include "dbus_info.h" @@ -115,7 +116,7 @@ void imgui_init() } //static -void imgui_create(void *ctx) +void imgui_create(void *ctx, GL_SESSION gl_session) { if (inited) return; @@ -172,6 +173,16 @@ void imgui_create(void *ctx) sw_stats.font_params_hash = params.font_params_hash; wsi_conn.focus_changed = focus_changed; + if (gl_session == GL_SESSION_X11) + wsi_conn.keys_are_pressed = keys_are_pressed; +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + if (gl_session == GL_SESSION_WL) + { + wsi_conn.keys_are_pressed = wl_keys_are_pressed; + wsi_wayland_init(wsi_conn); + } +#endif + // Restore global context or ours might clash with apps that use Dear ImGui ImGui::SetCurrentContext(saved_ctx); } @@ -191,7 +202,7 @@ void imgui_set_context(void *ctx) { if (!ctx) return; - imgui_create(ctx); + imgui_create(ctx, GL_SESSION_X11); } void imgui_render(unsigned int width, unsigned int height) @@ -205,7 +216,7 @@ void imgui_render(unsigned int width, unsigned int height) process_control_socket(control_client, params); } - check_keybinds(params, vendorID); + check_keybinds(wsi_conn, params); update_hud_info(sw_stats, params, vendorID); ImGuiContext *saved_ctx = ImGui::GetCurrentContext(); diff --git a/src/gl/gl_hud.h b/src/gl/gl_hud.h index 99658ef7..f46f4a19 100644 --- a/src/gl/gl_hud.h +++ b/src/gl/gl_hud.h @@ -7,9 +7,18 @@ namespace MangoHud { namespace GL { +extern wsi_connection wsi_conn; + +enum GL_SESSION +{ + GL_SESSION_UNKNOWN, + GL_SESSION_X11, + GL_SESSION_WL, +}; + extern overlay_params params; void imgui_init(); -void imgui_create(void *ctx); +void imgui_create(void *ctx, GL_SESSION); void imgui_shutdown(); void imgui_set_context(void *ctx); void imgui_render(unsigned int width, unsigned int height); diff --git a/src/gl/inject_egl.cpp b/src/gl/inject_egl.cpp index d12b0237..f868fa3e 100644 --- a/src/gl/inject_egl.cpp +++ b/src/gl/inject_egl.cpp @@ -10,10 +10,60 @@ #include "mesa/util/os_time.h" #include "blacklist.h" #include "gl_hud.h" +#include "wsi_helpers.h" + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#include +#endif + +#include +#include +#define HAVE_MINCORE using namespace MangoHud::GL; -EXPORT_C_(void *) eglGetProcAddress(const char* procName); +namespace MangoHud { namespace GL { + extern swapchain_stats sw_stats; + extern wsi_connection wsi_conn; +}} + +EXPORT_C_(void*) eglGetProcAddress(const char* procName); +static GL_SESSION egl_session = GL_SESSION_UNKNOWN; + +// mesa eglglobals.c +static bool pointer_is_dereferencable(void *p) +{ +#ifdef HAVE_MINCORE + uintptr_t addr = (uintptr_t) p; + unsigned char valid = 0; + const long page_size = getpagesize(); + + if (p == NULL) + return false; + + /* align addr to page_size */ + addr &= ~(page_size - 1); + + if (mincore((void *) addr, page_size, &valid) < 0) { + return false; + } + + /* mincore() returns 0 on success, and -1 on failure. The last parameter + * is a vector of bytes with one entry for each page queried. mincore + * returns page residency information in the first bit of each byte in the + * vector. + * + * Residency doesn't actually matter when determining whether a pointer is + * dereferenceable, so the output vector can be ignored. What matters is + * whether mincore succeeds. See: + * + * http://man7.org/linux/man-pages/man2/mincore.2.html + */ + return true; +#else + return p != NULL; +#endif +} void* get_egl_proc_address(const char* name) { @@ -48,6 +98,66 @@ EXPORT_C_(int) eglMakeCurrent_OFF(void *dpy, void *draw, void *read,void *ctx) { return ret; } +EXPORT_C_(void*) eglGetDisplay(void* native_display) +{ + static decltype(&eglGetDisplay) pfn_eglGetDisplay = nullptr; + if (!pfn_eglGetDisplay) + pfn_eglGetDisplay = reinterpret_cast(get_egl_proc_address("eglGetDisplay")); + + if (getenv("WAYLAND_DISPLAY")) + { + egl_session = GL_SESSION_WL; + wsi_conn.wl.display = reinterpret_cast (native_display); + } + else if (getenv("DISPLAY")) + { + egl_session = GL_SESSION_X11; + wsi_conn.xlib.dpy = reinterpret_cast (native_display); + } + + if (pointer_is_dereferencable(native_display)) + { + Dl_info info; + void *first_pointer = *(void **) native_display; + dladdr(first_pointer, &info); + if (info.dli_saddr) + fprintf(stderr, "dli_sname: %s\n", info.dli_sname); + } + + return pfn_eglGetDisplay(native_display); +} + +EXPORT_C_(void*) eglCreateWindowSurface(void *egl_display, void *egl_config, void *native_window, int const * attrib_list) +{ + static decltype(&eglCreateWindowSurface) pfn_eglCreateWindowSurface = nullptr; + if (!pfn_eglCreateWindowSurface) + pfn_eglCreateWindowSurface = reinterpret_cast(get_egl_proc_address("eglCreateWindowSurface")); + + if (egl_session == GL_SESSION_WL) + { +// wsi_conn.wl.surface = reinterpret_cast(native_window); + } + else if (egl_session == GL_SESSION_X11) + { + wsi_conn.xlib.window = reinterpret_cast(native_window); + } + return pfn_eglCreateWindowSurface(egl_display, egl_config, native_window, attrib_list); +} + +EXPORT_C_(wl_egl_window*) wl_egl_window_create(wl_surface *surf, int w, int h) +{ + static decltype(&wl_egl_window_create) pfn_wl_egl_window_create = nullptr; + if (!pfn_wl_egl_window_create) + { + void *hlib = dlopen("libwayland-egl.so.1", RTLD_LAZY); + pfn_wl_egl_window_create = reinterpret_cast(dlsym(hlib, "wl_egl_window_create")); + } + + fprintf(stderr, "%s\n", __func__); + wsi_conn.wl.surface = surf; + return pfn_wl_egl_window_create(surf, w, h); +} + EXPORT_C_(unsigned int) eglSwapBuffers( void* dpy, void* surf) { static int (*pfn_eglSwapBuffers)(void*, void*) = nullptr; @@ -59,7 +169,7 @@ EXPORT_C_(unsigned int) eglSwapBuffers( void* dpy, void* surf) if (!pfn_eglQuerySurface) pfn_eglQuerySurface = reinterpret_cast(get_egl_proc_address("eglQuerySurface")); - imgui_create(surf); + imgui_create(surf, egl_session); int width=0, height=0; if (pfn_eglQuerySurface(dpy, surf, 0x3056, &height) && @@ -67,9 +177,9 @@ EXPORT_C_(unsigned int) eglSwapBuffers( void* dpy, void* surf) imgui_render(width, height); using namespace std::chrono_literals; - if (fps_limit_stats.targetFrameTime > 0s){ + if (fps_limit_stats.targetFrameTime > 0s || (sw_stats.lost_focus && fps_limit_stats.focusLossFrameTime > 0s)){ fps_limit_stats.frameStart = Clock::now(); - FpsLimiter(fps_limit_stats); + FpsLimiter(fps_limit_stats, sw_stats.lost_focus); fps_limit_stats.frameEnd = Clock::now(); } } @@ -82,10 +192,12 @@ struct func_ptr { void *ptr; }; -static std::array name_to_funcptr_map = {{ +static std::array name_to_funcptr_map = {{ #define ADD_HOOK(fn) { #fn, (void *) fn } ADD_HOOK(eglGetProcAddress), ADD_HOOK(eglSwapBuffers), + ADD_HOOK(eglGetDisplay), + ADD_HOOK(wl_egl_window_create), #undef ADD_HOOK }}; @@ -102,7 +214,8 @@ EXPORT_C_(void *) mangohud_find_egl_ptr(const char *name) return nullptr; } -EXPORT_C_(void *) eglGetProcAddress(const char* procName) { +void* eglGetProcAddress(const char* procName) +{ void* real_func = get_egl_proc_address(procName); void* func = mangohud_find_egl_ptr(procName); SPDLOG_TRACE("{}: proc: {}, real: {}, fun: {}", __func__, procName, real_func, func); diff --git a/src/gl/inject_glx.cpp b/src/gl/inject_glx.cpp index 023d1946..b0ef2e3d 100644 --- a/src/gl/inject_glx.cpp +++ b/src/gl/inject_glx.cpp @@ -132,10 +132,10 @@ static void do_imgui_swap(void *dpy, void *drawable) { GLint vp[4]; if (!is_blacklisted()) { - imgui_create(glx.GetCurrentContext()); wsi_conn.xlib.dpy = (Display*)dpy; wsi_conn.xlib.window = (Window)drawable; + imgui_create(glx.GetCurrentContext(), GL_SESSION_X11); unsigned int width = -1, height = -1; diff --git a/src/keybinds.cpp b/src/keybinds.cpp index 60026a3d..cc6ef9b0 100644 --- a/src/keybinds.cpp +++ b/src/keybinds.cpp @@ -1,10 +1,89 @@ +#include +#include #include "overlay.h" #include "timing.hpp" #include "logging.h" #include "keybinds.h" -#include +#include "wsi_helpers.h" -void check_keybinds(struct overlay_params& params, uint32_t vendorID){ +#ifdef HAVE_X11 +#include "shared_x11.h" +#include "loaders/loader_x11.h" +#endif + +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) { + + if (!init_x11()) + return false; + + char keys_return[32]; + size_t pressed = 0; + + g_x11->XQueryKeymap(get_xdisplay(), keys_return); + + for (KeySym ks : keys) { + KeyCode kc2 = g_x11->XKeysymToKeycode(get_xdisplay(), ks); + + bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7))); + + if (isPressed) + pressed++; + } + + if (pressed > 0 && pressed == keys.size()) { + return true; + } + + return false; +} +#elif defined(_WIN32) +#include +bool keys_are_pressed(const std::vector& keys) { + size_t pressed = 0; + + for (KeySym ks : keys) { + if (GetAsyncKeyState(ks) & 0x8000) + pressed++; + } + + if (pressed > 0 && pressed == keys.size()) { + return true; + } + + return false; +} +#else +bool keys_are_pressed(const std::vector& keys) { + return false; +} +#endif + +void check_keybinds(wsi_connection& wsi, struct overlay_params& params){ using namespace std::chrono_literals; auto now = Clock::now(); /* us */ auto elapsedF2 = now - last_f2_press; @@ -20,8 +99,14 @@ void check_keybinds(struct overlay_params& params, uint32_t vendorID){ auto keyPressDelay = 400ms; + if (!wsi.keys_are_pressed) + { + SPDLOG_DEBUG("wsi.keys_are_pressed is not set!"); + return; + } + if (elapsedF2 >= keyPressDelay && - keys_are_pressed(params.toggle_logging)) { + wsi.keys_are_pressed(params.toggle_logging)) { last_f2_press = now; if (logger->is_active()) { logger->stop_logging(); @@ -32,7 +117,7 @@ void check_keybinds(struct overlay_params& params, uint32_t vendorID){ } if (elapsedFpsLimitToggle >= keyPressDelay && - keys_are_pressed(params.toggle_fps_limit)) { + wsi.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]; @@ -51,26 +136,26 @@ void check_keybinds(struct overlay_params& params, uint32_t vendorID){ } if (elapsedF12 >= keyPressDelay && - keys_are_pressed(params.toggle_hud)) { + wsi.keys_are_pressed(params.toggle_hud)) { last_f12_press = now; params.no_display = !params.no_display; } if (elapsedReloadCfg >= keyPressDelay && - keys_are_pressed(params.reload_cfg)) { + wsi.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 && - keys_are_pressed(params.upload_log)) { + wsi.keys_are_pressed(params.upload_log)) { last_upload_press = now; logger->upload_last_log(); } if (params.permit_upload && elapsedUpload >= keyPressDelay && - keys_are_pressed(params.upload_logs)) { + wsi.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 83dff612..d69886ca 100644 --- a/src/keybinds.h +++ b/src/keybinds.h @@ -1,64 +1,21 @@ #pragma once #ifndef MANGOHUD_KEYBINDS_H #define MANGOHUD_KEYBINDS_H +#include -#ifdef HAVE_X11 -#include "shared_x11.h" -#include "loaders/loader_x11.h" +#ifdef HAVE_XKBCOMMON +#include +#else +typedef uint32_t xkb_keysym_t; #endif -#ifndef KeySym -typedef unsigned long KeySym; -#endif - -Clock::time_point last_f2_press, toggle_fps_limit_press , last_f12_press, reload_cfg_press, last_upload_press; - -#if defined(HAVE_X11) -bool keys_are_pressed(const std::vector& keys) { - - if (!init_x11()) - return false; - - char keys_return[32]; - size_t pressed = 0; - - g_x11->XQueryKeymap(get_xdisplay(), keys_return); - - for (KeySym ks : keys) { - KeyCode kc2 = g_x11->XKeysymToKeycode(get_xdisplay(), ks); +struct wsi_connection; +struct overlay_params; - bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7))); - - if (isPressed) - pressed++; - } - - if (pressed > 0 && pressed == keys.size()) { - return true; - } - - return false; -} -#elif defined(_WIN32) -#include -bool keys_are_pressed(const std::vector& keys) { - size_t pressed = 0; - - for (KeySym ks : keys) { - if (GetAsyncKeyState(ks) & 0x8000) - pressed++; - } - - if (pressed > 0 && pressed == keys.size()) { - return true; - } - - return false; -} -#else // XXX: Add wayland support -bool keys_are_pressed(const std::vector& keys) { - return false; -} +void check_keybinds(wsi_connection&, 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/overlay.h b/src/overlay.h index 6ae3924e..ed3f00e0 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -108,7 +108,6 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru void update_hw_info(const struct overlay_params& params, uint32_t vendorID); void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_params& params); void init_cpu_stats(overlay_params& params); -void check_keybinds(overlay_params& params, uint32_t vendorID); void init_system_info(void); void FpsLimiter(struct fps_limit& stats, bool lost_focus = false); std::string get_device_name(uint32_t vendorID, uint32_t deviceID); diff --git a/src/overlay_params.cpp b/src/overlay_params.cpp index 5cd987d4..af8f50cd 100644 --- a/src/overlay_params.cpp +++ b/src/overlay_params.cpp @@ -124,22 +124,19 @@ parse_float(const char *str) return val; } -#ifdef HAVE_X11 -static std::vector +#ifdef HAVE_XKBCOMMON +static std::vector parse_string_to_keysym_vec(const char *str) { - std::vector keys; - if(g_x11->IsLoaded()) - { - auto keyStrings = str_tokenize(str); - for (auto& ks : keyStrings) { - trim(ks); - KeySym xk = g_x11->XStringToKeysym(ks.c_str()); - if (xk) - keys.push_back(xk); - else - SPDLOG_ERROR("Unrecognized key: '{}'", ks); - } + std::vector keys; + auto keyStrings = str_tokenize(str); + for (auto& ks : keyStrings) { + trim(ks); + auto xk = xkb_keysym_from_name(ks.c_str(), XKB_KEYSYM_NO_FLAGS); + if (xk) + keys.push_back(xk); + else + SPDLOG_ERROR("Unrecognized key: '{}'", ks); } return keys; } diff --git a/src/overlay_params.h b/src/overlay_params.h index 33a1a8f1..8d51b8e2 100644 --- a/src/overlay_params.h +++ b/src/overlay_params.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -235,12 +236,12 @@ struct overlay_params { float font_scale_media_player; float background_alpha, alpha; float cellpadding_y; - std::vector toggle_hud; - std::vector toggle_fps_limit; - std::vector toggle_logging; - std::vector reload_cfg; - std::vector upload_log; - std::vector upload_logs; + std::vector toggle_hud; + std::vector toggle_fps_limit; + std::vector toggle_logging; + std::vector reload_cfg; + std::vector upload_log; + std::vector upload_logs; std::string time_format, output_folder, output_file; std::string pci_dev; std::string media_player_name; diff --git a/src/vulkan.cpp b/src/vulkan.cpp index bbd1e8ab..40150a58 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -50,6 +50,7 @@ #include "blacklist.h" #include "pci_ids.h" #include "wsi_helpers.h" +#include "keybinds.h" using namespace std; @@ -430,6 +431,7 @@ static VkResult overlay_CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurf struct surface_data *data = new_surface_data(*pSurface); data->wsi.xcb.conn = pCreateInfo->connection; data->wsi.xcb.window = pCreateInfo->window; + data->wsi.keys_are_pressed = keys_are_pressed; } return result; @@ -447,13 +449,14 @@ static VkResult overlay_CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSu struct surface_data *data = new_surface_data(*pSurface); data->wsi.xlib.dpy = pCreateInfo->dpy; data->wsi.xlib.window = pCreateInfo->window; + data->wsi.keys_are_pressed = keys_are_pressed; } return result; } #endif #ifdef VK_USE_PLATFORM_WAYLAND_KHR -extern void wayland_init(wsi_connection&); +extern void wsi_wayland_init(wsi_connection&); static VkResult overlay_CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { SPDLOG_DEBUG("{}", __func__); @@ -464,7 +467,9 @@ static VkResult overlay_CreateWaylandSurfaceKHR(VkInstance instance, const VkWay struct surface_data *data = new_surface_data(*pSurface); data->wsi.wl.display = pCreateInfo->display; data->wsi.wl.surface = pCreateInfo->surface; - wayland_init(data->wsi); + data->wsi.keys_are_pressed = wl_keys_are_pressed; + data->wsi.key_pressed = wl_key_pressed; + wsi_wayland_init(data->wsi); } return result; } @@ -531,7 +536,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(instance_data->params, device_data->properties.vendorID); + check_keybinds(data->surface_data->wsi, 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 6552cbcc..84d8976b 100644 --- a/src/wsi_helpers.cpp +++ b/src/wsi_helpers.cpp @@ -1,5 +1,11 @@ +#include +#include #include #include +#include +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +#include +#endif #include "wsi_helpers.h" #ifdef VK_USE_PLATFORM_XCB_KHR @@ -9,10 +15,10 @@ static bool check_window_focus(xcb_connection_t * connection, xcb_window_t windo auto reply = xcb_get_input_focus_reply(connection, xcb_get_input_focus(connection), nullptr); if (reply) { - SPDLOG_DEBUG("Window: {:08x} Focus WId: {:08x}", window, reply->focus); - bool has_focus = (window == reply->focus); - free(reply); - return has_focus; + SPDLOG_DEBUG("Window: {:08x} Focus WId: {:08x}", window, reply->focus); + bool has_focus = (window == reply->focus); + free(reply); + return has_focus; } // xcb_query_tree_cookie_t cookie = xcb_query_tree(connection, reply->focus); @@ -92,33 +98,56 @@ void window_has_focus(wsi_connection* conn) #endif } -struct interfaces_ +struct wl_state { - wl_shell *shell; - wl_seat *seat; +// 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? static void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { SPDLOG_DEBUG("{}", __func__); + + 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 + 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 } static void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - SPDLOG_DEBUG("{}", __func__); 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); } static void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { - SPDLOG_DEBUG("{}", __func__); + SPDLOG_DEBUG("{}: {}", __func__, (void*)surface); auto wsi = reinterpret_cast(data); if (wsi->focus_changed && surface == wsi->wl.surface) wsi->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) { - SPDLOG_DEBUG("{}: key pressed: {}", __func__, key); + auto wsi = reinterpret_cast(data); + 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); + + SPDLOG_DEBUG("{}: key pressed: {}, {}, {:08x}", __func__, key, state, 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) { @@ -130,7 +159,7 @@ static struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keybo static void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) { SPDLOG_DEBUG("{}", __func__); if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - SPDLOG_DEBUG("SEAT"); + SPDLOG_DEBUG("Got usable seat"); struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat); wl_keyboard_add_listener (keyboard, &keyboard_listener, data); } @@ -139,7 +168,7 @@ 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) { SPDLOG_DEBUG("{}", __func__); - if (!strcmp(interface,"wl_seat")) { + if (!strcmp(interface, "wl_seat")) { //input_reader* ir = wl_registry_get_user_data(registry); auto seat = (wl_seat*)wl_registry_bind (registry, name, &wl_seat_interface, 1); // SPDLOG_DEBUG("wl_seat_add_listener {}", wl_proxy_get_listener((wl_proxy*)seat)); @@ -152,11 +181,11 @@ static void registry_remove_object (void *data, struct wl_registry *registry, ui static struct wl_registry_listener registry_listener = {®istry_add_object, ®istry_remove_object}; -// interfaces_ g_interfaces {}; - -void wayland_init(wsi_connection& conn) +void wsi_wayland_init(wsi_connection& conn) { - auto registry = wl_display_get_registry(conn.wl.display); - wl_registry_add_listener(registry, ®istry_listener, &conn); - wl_display_roundtrip(conn.wl.display); + 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? + wl_registry_add_listener(registry, ®istry_listener, &conn); + wl_display_roundtrip(conn.wl.display); } diff --git a/src/wsi_helpers.h b/src/wsi_helpers.h index 119629f2..e93a6bac 100644 --- a/src/wsi_helpers.h +++ b/src/wsi_helpers.h @@ -1,5 +1,13 @@ #pragma once #include +#include + +#ifdef HAVE_XKBCOMMON +#include +#else +typedef uint32_t xkb_keysym_t; +#endif + #ifdef VK_USE_PLATFORM_XLIB_KHR #include "loaders/loader_x11.h" #endif @@ -16,28 +24,32 @@ struct wsi_connection { std::function focus_changed; + std::function key_pressed; + std::function& keys)> keys_are_pressed; #ifdef VK_USE_PLATFORM_XCB_KHR struct xcb { - xcb_connection_t *conn = nullptr; - xcb_window_t window = 0; + xcb_connection_t *conn; + xcb_window_t window; } xcb; #endif #ifdef VK_USE_PLATFORM_XLIB_KHR struct xlib { - Display *dpy = nullptr; - Window window = 0; - int evmask = 0; + Display *dpy; + Window window; + int evmask; } xlib; #endif #ifdef VK_USE_PLATFORM_WAYLAND_KHR struct wl { wl_display *display; wl_surface *surface; - bool has_focus; } wl; #endif }; // struct wsi_connection; // bool check_window_focus(const wsi_connection&); + +void wsi_wayland_init(wsi_connection& conn); +