|
|
|
@ -7,6 +7,7 @@
|
|
|
|
|
#include <xkbcommon/xkbcommon.h>
|
|
|
|
|
#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<table_entry>
|
|
|
|
|
{
|
|
|
|
|
std::size_t operator()(const table_entry& k) const
|
|
|
|
|
{
|
|
|
|
|
using std::hash;
|
|
|
|
|
return (hash<xkb_keycode_t>()(k.code) ^ (hash<size_t>()(k.level) << 1));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::unordered_map<xkb_keysym_t, std::vector<table_entry>> 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_keycode_t, bool> 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<xkb_keysym_t>& 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<wsi_connection*>(data);
|
|
|
|
|
wl_state* state = reinterpret_cast<wl_state *>(conn->userdata);
|
|
|
|
|
|
|
|
|
|
if (!state->ctx)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
|
|
|
|
|
char *map_shm = reinterpret_cast<char *>(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<wsi_connection*>(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<wsi_connection*>(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<wsi_connection*>(data);
|
|
|
|
|
if (wsi->focus_changed && surface == wsi->wl.surface)
|
|
|
|
|
wsi->focus_changed(false);
|
|
|
|
|
auto conn = reinterpret_cast<wsi_connection*>(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<wsi_connection*>(data);
|
|
|
|
|
auto conn = reinterpret_cast<wsi_connection*>(data);
|
|
|
|
|
wl_state* wlstate = reinterpret_cast<wl_state *>(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<wsi_connection*>(data);
|
|
|
|
|
wl_state* wlstate = reinterpret_cast<wl_state *>(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<wl_state *>(conn.userdata);
|
|
|
|
|
xkb_state_unref(state->state);
|
|
|
|
|
xkb_keymap_unref(state->keymap);
|
|
|
|
|
xkb_context_unref(state->ctx);
|
|
|
|
|
delete reinterpret_cast<wl_state *>(conn.userdata);
|
|
|
|
|
}
|
|
|
|
|