Implement Wayland hotkeys

pull/1249/head
Etaash Mathamsetty 2 months ago committed by flightlessmango
parent 98e442ba7f
commit 732629e5a0

@ -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') }}

@ -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()

@ -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)

@ -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)) {

@ -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

@ -8,5 +8,7 @@
dlsym;
mangohud_find_glx_ptr;
mangohud_find_egl_ptr;
wl_display_connect;
wl_display_connect_to_fd;
local: *;
};

@ -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,

@ -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),

@ -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;
}

@ -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();

@ -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();
}
Loading…
Cancel
Save