summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEtaash Mathamsetty <45927311+Etaash-mathamsetty@users.noreply.github.com>2024-02-19 07:59:51 -0500
committerflightlessmango <42713625+flightlessmango@users.noreply.github.com>2024-02-28 21:10:58 +0100
commit732629e5a0f9101142dbb9466dfd7fbf3afbe06d (patch)
tree0647c86e3b1109acdd8220324cd774af72d6d820
parent98e442ba7f860de493a1b48460ef5398715bde2a (diff)
Implement Wayland hotkeys
-rw-r--r--.github/workflows/ubuntu.yml3
-rw-r--r--meson.build2
-rw-r--r--meson_options.txt2
-rw-r--r--src/keybinds.cpp8
-rw-r--r--src/keybinds.h53
-rw-r--r--src/mangohud.version2
-rw-r--r--src/meson.build12
-rw-r--r--src/vulkan.cpp25
-rw-r--r--src/wayland_hook.cpp59
-rw-r--r--src/wayland_hook.h13
-rw-r--r--src/wayland_keybinds.cpp115
11 files changed, 268 insertions, 26 deletions
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index fc15f39..04d7081 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -28,7 +28,8 @@ jobs:
libglew-dev \
libglfw3-dev \
libwayland-dev \
- libxnvctrl-dev
+ libxnvctrl-dev \
+ libxkbcommon-dev
sudo pip3 install 'meson>=0.60'
- name: 'Install clang'
if: ${{ (matrix.compiler == 'clang') }}
diff --git a/meson.build b/meson.build
index b80e661..b40132e 100644
--- a/meson.build
+++ b/meson.build
@@ -89,6 +89,7 @@ if is_unixy
dep_wayland_client = dependency('wayland-client',
required: get_option('with_wayland'), version : '>=1.11')
dbus_dep = dependency('dbus-1', required: get_option('with_dbus')).partial_dependency(compile_args : true, includes : true)
+ dep_xkb = dependency('xkbcommon', required: get_option('with_wayland'))
else
dep_x11 = null_dep
dep_wayland_client = null_dep
@@ -102,6 +103,7 @@ endif
if dep_wayland_client.found()
vulkan_wsi_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR']
vulkan_wsi_deps += dep_wayland_client
+ vulkan_wsi_deps += dep_xkb
endif
if is_unixy and not dep_x11.found() and not dep_wayland_client.found()
diff --git a/meson_options.txt b/meson_options.txt
index c82ae15..b6f127e 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -5,7 +5,7 @@ option('include_doc', type : 'boolean', value : true, description: 'Include the
option('with_nvml', type : 'combo', value : 'enabled', choices: ['enabled', 'system', 'disabled'], description: 'Enable NVML support')
option('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support')
option('with_x11', type : 'feature', value : 'enabled')
-option('with_wayland', type : 'feature', value : 'disabled')
+option('with_wayland', type : 'feature', value : 'enabled')
option('with_dbus', type : 'feature', value : 'enabled')
option('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build')
option('mangoapp', type: 'boolean', value : false)
diff --git a/src/keybinds.cpp b/src/keybinds.cpp
index 395eb55..84c0288 100644
--- a/src/keybinds.cpp
+++ b/src/keybinds.cpp
@@ -1,10 +1,16 @@
#include <cstdint>
+#include <cstring>
+#include <array>
+#include <algorithm>
+#include <unistd.h>
#include "overlay.h"
#include "timing.hpp"
#include "logging.h"
#include "keybinds.h"
#include "fps_metrics.h"
+Clock::time_point last_f2_press, toggle_fps_limit_press, toggle_preset_press, last_f12_press, reload_cfg_press, last_upload_press;
+
void check_keybinds(struct overlay_params& params, uint32_t vendorID){
using namespace std::chrono_literals;
auto now = Clock::now(); /* us */
@@ -20,7 +26,7 @@ void check_keybinds(struct overlay_params& params, uint32_t vendorID){
return;
last_check = now;
- auto keyPressDelay = 400ms;
+ const auto keyPressDelay = 400ms;
if (elapsedF2 >= keyPressDelay &&
keys_are_pressed(params.toggle_logging)) {
diff --git a/src/keybinds.h b/src/keybinds.h
index e48aafa..62d33ac 100644
--- a/src/keybinds.h
+++ b/src/keybinds.h
@@ -6,37 +6,50 @@
#include "shared_x11.h"
#include "loaders/loader_x11.h"
#endif
+#ifdef HAVE_WAYLAND
+#include "wayland_hook.h"
+#endif
#ifndef KeySym
typedef unsigned long KeySym;
#endif
-Clock::time_point last_f2_press, toggle_fps_limit_press, toggle_preset_press, last_f12_press, reload_cfg_press, last_upload_press;
+#if defined(HAVE_X11) || defined(HAVE_WAYLAND)
+static inline bool keys_are_pressed(const std::vector<KeySym>& keys)
+{
+ #if defined(HAVE_WAYLAND)
+ if(wl_display_ptr && wl_handle)
+ {
+ update_wl_queue();
-#if defined(HAVE_X11)
-static inline bool keys_are_pressed(const std::vector<KeySym>& keys) {
+ if(wl_pressed_keys.size() == keys.size() && wl_pressed_keys == keys)
+ return true;
+ }
+ #endif
- if (!init_x11())
- return false;
+ #if defined(HAVE_X11)
+ if (init_x11())
+ {
+ char keys_return[32];
+ size_t pressed = 0;
- char keys_return[32];
- size_t pressed = 0;
+ auto libx11 = get_libx11();
+ libx11->XQueryKeymap(get_xdisplay(), keys_return);
- auto libx11 = get_libx11();
- libx11->XQueryKeymap(get_xdisplay(), keys_return);
+ for (KeySym ks : keys) {
+ KeyCode kc2 = libx11->XKeysymToKeycode(get_xdisplay(), ks);
- for (KeySym ks : keys) {
- KeyCode kc2 = libx11->XKeysymToKeycode(get_xdisplay(), ks);
+ bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7)));
- bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7)));
+ if (isPressed)
+ pressed++;
+ }
- if (isPressed)
- pressed++;
- }
-
- if (pressed > 0 && pressed == keys.size()) {
- return true;
+ if (pressed > 0 && pressed == keys.size()) {
+ return true;
+ }
}
+ #endif
return false;
}
@@ -56,10 +69,6 @@ static inline bool keys_are_pressed(const std::vector<KeySym>& keys) {
return false;
}
-#else // XXX: Add wayland support
-static inline bool keys_are_pressed(const std::vector<KeySym>& keys) {
- return false;
-}
#endif
#endif //MANGOHUD_KEYBINDS_H
diff --git a/src/mangohud.version b/src/mangohud.version
index 7fd09a4..5be0a29 100644
--- a/src/mangohud.version
+++ b/src/mangohud.version
@@ -8,5 +8,7 @@
dlsym;
mangohud_find_glx_ptr;
mangohud_find_egl_ptr;
+ wl_display_connect;
+ wl_display_connect_to_fd;
local: *;
};
diff --git a/src/meson.build b/src/meson.build
index c776ca3..5754b72 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -59,7 +59,7 @@ vklayer_files = files(
'config.cpp',
'gpu.cpp',
'blacklist.cpp',
- 'file_utils.cpp',
+ 'file_utils.cpp'
)
opengl_files = []
@@ -150,6 +150,15 @@ if is_unixy
)
endif
+ if get_option('with_wayland').enabled()
+ pre_args += '-DHAVE_WAYLAND'
+
+ vklayer_files += files(
+ 'wayland_hook.cpp',
+ 'wayland_keybinds.cpp'
+ )
+ endif
+
if dbus_dep.found() and get_option('with_dbus').enabled()
pre_args += '-DHAVE_DBUS'
vklayer_files += files(
@@ -290,6 +299,7 @@ if get_option('mangoapp')
spdlog_dep,
dbus_dep,
dep_x11,
+ dep_wayland_client,
glfw3_dep,
json_dep,
glew_dep,
diff --git a/src/vulkan.cpp b/src/vulkan.cpp
index 322f01a..f205b80 100644
--- a/src/vulkan.cpp
+++ b/src/vulkan.cpp
@@ -50,8 +50,13 @@
#include "notify.h"
#include "blacklist.h"
#include "pci_ids.h"
+#if defined(HAVE_WAYLAND)
+#include "wayland_hook.h"
+#endif
+#include "real_dlsym.h"
#include "file_utils.h"
#ifdef __linux__
+#include <dlfcn.h>
#include "implot.h"
#endif
@@ -2028,6 +2033,23 @@ static void overlay_DestroyInstance(
destroy_instance_data(instance_data);
}
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+static VkResult overlay_CreateWaylandSurfaceKHR(
+ VkInstance instance,
+ const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface
+)
+{
+ struct instance_data *instance_data = FIND(struct instance_data, instance);
+ if (!wl_handle)
+ wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
+ wl_display_ptr = pCreateInfo->display;
+ init_wayland_data();
+ return instance_data->vtable.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif
+
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev,
const char *funcName);
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance,
@@ -2048,6 +2070,9 @@ static const struct {
ADD_HOOK(EndCommandBuffer),
ADD_HOOK(CmdExecuteCommands),
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ ADD_HOOK(CreateWaylandSurfaceKHR),
+#endif
ADD_HOOK(CreateSwapchainKHR),
ADD_HOOK(QueuePresentKHR),
ADD_HOOK(DestroySwapchainKHR),
diff --git a/src/wayland_hook.cpp b/src/wayland_hook.cpp
new file mode 100644
index 0000000..c29e47a
--- /dev/null
+++ b/src/wayland_hook.cpp
@@ -0,0 +1,59 @@
+#include <cstdint>
+#include <array>
+#include <dlfcn.h>
+#include <cstdio>
+#include "real_dlsym.h"
+#include "wayland_hook.h"
+
+EXPORT_C_(struct wl_display*) wl_display_connect(const char *name);
+EXPORT_C_(struct wl_display*) wl_display_connect_to_fd(int fd);
+
+typedef struct wl_display* (*pwl_display_connect)(const char *name);
+typedef struct wl_display* (*pwl_display_connect_to_fd)(int fd);
+
+pwl_display_connect wl_display_connect_ptr = nullptr;
+pwl_display_connect_to_fd wl_display_connect_to_fd_ptr = nullptr;
+void* wl_handle = nullptr;
+struct wl_display* wl_display_ptr = nullptr;
+
+EXPORT_C_(struct wl_display*) wl_display_connect(const char *name)
+{
+ struct wl_display *ret = NULL;
+
+ if(!wl_handle)
+ {
+ wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
+ wl_display_connect_ptr = (pwl_display_connect)real_dlsym(wl_handle, "wl_display_connect");
+ wl_display_connect_to_fd_ptr = (pwl_display_connect_to_fd)real_dlsym(wl_handle, "wl_display_connect_to_fd");
+ }
+
+ ret = wl_display_connect_ptr(name);
+
+ if(!wl_display_ptr)
+ wl_display_ptr = ret;
+
+ init_wayland_data();
+
+ return ret;
+}
+
+EXPORT_C_(struct wl_display*) wl_display_connect_to_fd(int fd)
+{
+ struct wl_display *ret = NULL;
+
+ if(!wl_handle)
+ {
+ wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
+ wl_display_connect_to_fd_ptr = (pwl_display_connect_to_fd)real_dlsym(wl_handle, "wl_display_connect_to_fd");
+ wl_display_connect_ptr = (pwl_display_connect)real_dlsym(wl_handle, "wl_display_connect");
+ }
+
+ ret = wl_display_connect_to_fd_ptr(fd);
+
+ if(!wl_display_ptr)
+ wl_display_ptr = ret;
+
+ init_wayland_data();
+
+ return ret;
+}
diff --git a/src/wayland_hook.h b/src/wayland_hook.h
new file mode 100644
index 0000000..c637e72
--- /dev/null
+++ b/src/wayland_hook.h
@@ -0,0 +1,13 @@
+#include <wayland-client.h>
+#include <vector>
+
+#ifndef KeySym
+typedef unsigned long KeySym;
+#endif
+
+extern void* wl_handle;
+extern struct wl_display* wl_display_ptr;
+extern std::vector<KeySym> wl_pressed_keys;
+
+void init_wayland_data();
+void update_wl_queue();
diff --git a/src/wayland_keybinds.cpp b/src/wayland_keybinds.cpp
new file mode 100644
index 0000000..670040b
--- /dev/null
+++ b/src/wayland_keybinds.cpp
@@ -0,0 +1,115 @@
+#include <cstdint>
+#include <cstring>
+#include <array>
+#include <algorithm>
+#include <unistd.h>
+#include <vector>
+#include <wayland-client.h>
+#include <xkbcommon/xkbcommon.h>
+#include <sys/mman.h>
+#include "wayland_hook.h"
+#include "timing.hpp"
+#include "keybinds.h"
+
+struct wl_seat* seat = nullptr;
+struct wl_keyboard* keyboard = nullptr;
+struct xkb_context *context_xkb = nullptr;
+struct xkb_keymap *keymap_xkb = nullptr;
+struct xkb_state *state_xkb = nullptr;
+struct wl_event_queue* queue = nullptr;
+std::vector<KeySym> wl_pressed_keys {};
+
+static void registry_handle_global(void *data, struct wl_registry* registry, uint32_t name, const char *interface, uint32_t version)
+{
+ if(strcmp(interface, wl_seat_interface.name) == 0)
+ {
+ seat = (struct wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 7);
+ }
+}
+
+static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name){}
+
+static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
+{
+ char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if(!context_xkb)
+ context_xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+
+ if(keymap_xkb && state_xkb)
+ {
+ xkb_keymap_unref(keymap_xkb);
+ xkb_state_unref(state_xkb);
+ }
+
+ keymap_xkb = xkb_keymap_new_from_string(
+ context_xkb, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+ state_xkb = xkb_state_new(keymap_xkb);
+
+ munmap((void*)map_shm, size);
+ close(fd);
+}
+
+static void wl_keyboard_enter(void *user_data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys){}
+
+static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)
+{
+ wl_pressed_keys.clear();
+}
+
+static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+ xkb_keycode_t keycode = key + 8;
+ xkb_keysym_t keysym = xkb_state_key_get_one_sym(state_xkb, keycode);
+
+ if(state)
+ {
+ wl_pressed_keys.push_back(keysym);
+ }
+ else
+ {
+ auto it = std::find(wl_pressed_keys.begin(), wl_pressed_keys.end(), keysym);
+ if(it != wl_pressed_keys.end())
+ wl_pressed_keys.erase(it);
+ }
+}
+
+static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group){}
+
+static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){}
+
+struct wl_registry_listener registry_listener {
+ .global = registry_handle_global,
+ .global_remove = registry_handle_global_remove
+};
+
+struct wl_keyboard_listener keyboard_listener {
+ .keymap = wl_keyboard_keymap,
+ .enter = wl_keyboard_enter,
+ .leave = wl_keyboard_leave,
+ .key = wl_keyboard_key,
+ .modifiers = wl_keyboard_modifiers,
+ .repeat_info = wl_keyboard_repeat_info
+};
+
+void update_wl_queue()
+{
+ wl_display_roundtrip_queue(wl_display_ptr, queue);
+}
+
+void init_wayland_data()
+{
+ struct wl_display *display_wrapped = (struct wl_display*)wl_proxy_create_wrapper(wl_display_ptr);
+ queue = wl_display_create_queue(wl_display_ptr);
+ wl_proxy_set_queue((struct wl_proxy*)display_wrapped, queue);
+ wl_registry *registry = wl_display_get_registry(display_wrapped);
+ wl_proxy_wrapper_destroy(display_wrapped);
+ wl_registry_add_listener(registry, &registry_listener, NULL);
+ update_wl_queue();
+ update_wl_queue();
+ keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
+ update_wl_queue();
+}