Add simple keyboard handling for wayland.

This commit is contained in:
James Grogan 2022-11-10 16:29:59 +00:00
parent e2cc98e1fb
commit 918c1d3046
8 changed files with 175 additions and 28 deletions

View file

@ -33,7 +33,7 @@ sudo apt-get install libpng-dev
#### Window rendering
```bash
sudo apt-get install libwayland-dev wayland-protocols
sudo apt-get install libwayland-dev wayland-protocols libx11-dev libxkbcommon-dev libx11-xcb-dev
```
We need to generate suitable xdg shell c code for wayland:
@ -48,6 +48,13 @@ export WAYLAND_EXTENSION_DIR=$WORK_DIR
In `xdg-shell-protocol.cpp` - we need access to `xdg_wm_base_interface` so export it also `extern const struct wl_interface xdg_wm_base_interface;` as per similar interface structs.
#### 3D Rendering
```bash
sudo apt-get install libgl-dev
```
# Build from Source
## Linux

View file

@ -17,7 +17,8 @@ if(UNIX)
ui_interfaces/x11/XcbKeyboard.cpp
ui_interfaces/x11/GlxInterface.cpp
)
list(APPEND platform_LIBS ${X11_LIBRARIES} ${X11_xcb_LIB} ${X11_X11_xcb_LIB})
list(APPEND platform_LIBS ${X11_LIBRARIES} ${X11_xcb_LIB} ${X11_X11_xcb_LIB} ${X11_xkbcommon_LIB})
list(APPEND X11_INCLUDE_DIRS ${X11_xkbcommon_INCLUDE_PATH})
else()
message(STATUS "x11 development headers not found - skipping support")
endif()
@ -38,6 +39,7 @@ if(UNIX)
ui_interfaces/wayland/WaylandBuffer.cpp
ui_interfaces/wayland/WaylandPointerInterface.cpp
ui_interfaces/wayland/WaylandSeatInterface.cpp
ui_interfaces/wayland/WaylandKeyboard.cpp
${WAYLAND_EXTENSIONS_INCLUDE_DIR}/xdg-shell-protocol.cpp
)
set(_HAS_WAYLAND ON)
@ -81,6 +83,7 @@ target_include_directories(windows PUBLIC
"${PROJECT_SOURCE_DIR}/src/ui_elements"
"${PROJECT_SOURCE_DIR}/src/ui_elements/widgets"
${WAYLAND_INCLUDE_DIRS}
${X11_INCLUDE_DIRS}
)
target_link_libraries(windows PUBLIC ${platform_LIBS} core geometry graphics ui_elements ${WAYLAND_CLIENT_LIBRARY})

View file

@ -0,0 +1,113 @@
#include "WaylandKeyboard.h"
#include "FileLogger.h"
#include <unistd.h>
#include <sys/mman.h>
void WaylandKeyboard::keyboardKeymapEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onKeymapEvent(wl_keyboard, format, fd, size);
}
void WaylandKeyboard::keyboardEnterEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onEnterEvent(keys);
}
void WaylandKeyboard::keyboardPressedEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onPressedEvent(key, state);
}
static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)
{
fprintf(stderr, "keyboard leave\n");
}
static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay)
{
}
void WaylandKeyboard::keyboardModifierEvent(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)
{
auto thisClass = static_cast<WaylandKeyboard*>(data);
thisClass->onKeyboardModifier(mods_depressed, mods_latched, mods_locked, group);
}
void WaylandKeyboard::onKeyboardModifier(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
{
xkb_state_update_mask(mXkbState, mods_depressed, mods_latched, mods_locked, 0, 0, group);
}
void WaylandKeyboard::onEnterEvent(struct wl_array *keys)
{
MLOG_INFO("keyboard enter; keys pressed are:");
void* key;
wl_array_for_each(key, keys)
{
uint32_t* key_type = static_cast<uint32_t*>(key);
char buf[128];
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, *key_type + 8);
xkb_keysym_get_name(sym, buf, sizeof(buf));
fprintf(stderr, "sym: %-12s (%d), ", buf, sym);
xkb_state_key_get_utf8(mXkbState, *key_type + 8, buf, sizeof(buf));
fprintf(stderr, "utf8: '%s'\n", buf);
}
}
void WaylandKeyboard::onPressedEvent(uint32_t key, uint32_t state)
{
char buf[128];
uint32_t keycode = key + 8;
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, keycode);
xkb_keysym_get_name(sym, buf, sizeof(buf));
const char *action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? "press" : "release";
fprintf(stderr, "key %s: sym: %-12s (%d), ", action, buf, sym);
xkb_state_key_get_utf8(mXkbState, keycode, buf, sizeof(buf));
fprintf(stderr, "utf8: '%s'\n", buf);
}
void WaylandKeyboard::onKeymapEvent(struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
{
// assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
char* map_shm = static_cast<char*>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
// assert(map_shm != MAP_FAILED);
struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string(mXkbContext, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
munmap(map_shm, size);
close(fd);
struct xkb_state* xkb_state = xkb_state_new(xkb_keymap);
xkb_keymap_unref(mXkbKeymap);
xkb_state_unref(mXkbState);
mXkbKeymap = xkb_keymap;
mXkbState = xkb_state;
}
WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard)
: mKeyboard(keyboard)
{
mXkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
mKeyboardListener.keymap = keyboardKeymapEvent;
mKeyboardListener.enter = keyboardEnterEvent;
mKeyboardListener.key = keyboardPressedEvent;
mKeyboardListener.leave = wl_keyboard_leave;
mKeyboardListener.modifiers = keyboardModifierEvent;
mKeyboardListener.repeat_info = wl_keyboard_repeat_info;
wl_keyboard_add_listener(mKeyboard, &mKeyboardListener, this);
}
WaylandKeyboard::~WaylandKeyboard()
{
wl_keyboard_release(mKeyboard);
}

View file

@ -0,0 +1,30 @@
#pragma once
#include "wayland-client.h"
#include <xkbcommon/xkbcommon.h>
class WaylandKeyboard
{
public:
WaylandKeyboard(wl_keyboard* keyboard);
~WaylandKeyboard();
private:
static void keyboardKeymapEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
static void keyboardEnterEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
static void keyboardPressedEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
static void keyboardModifierEvent(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);
void onKeyboardModifier(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
void onKeymapEvent(struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
void onEnterEvent(struct wl_array *keys);
void onPressedEvent(uint32_t key, uint32_t state);
wl_keyboard* mKeyboard{nullptr};
xkb_state* mXkbState{nullptr};
xkb_context* mXkbContext{nullptr};
xkb_keymap* mXkbKeymap{nullptr};
wl_keyboard_listener mKeyboardListener;
};

View file

@ -22,6 +22,11 @@ static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
}
WaylandPointerInterface::~WaylandPointerInterface()
{
wl_pointer_release(mPointer);
}
void WaylandPointerInterface::pointerFrameEvent(void *data, struct wl_pointer *wl_pointer)
{
auto thisClass = static_cast<WaylandPointerInterface*>(data);
@ -122,8 +127,3 @@ WaylandPointerInterface::WaylandPointerInterface(wl_pointer* pointer)
wl_pointer_add_listener(mPointer, &mPointerListener, this);
}
wl_pointer* WaylandPointerInterface::getPointer() const
{
return mPointer;
}

View file

@ -7,10 +7,9 @@ class WaylandPointerInterface
public:
WaylandPointerInterface(wl_pointer* pointer);
wl_pointer* getPointer() const;
~WaylandPointerInterface();
private:
static void pointerEnterEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
static void pointerLeaveEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface);
static void pointerMotionEvent(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);

View file

@ -18,8 +18,18 @@ void WaylandSeatInterface::onSeatCapabilitiesEvent(uint32_t capabilities)
}
else if (!have_pointer && mPointerInterface!= nullptr)
{
wl_pointer_release(mPointerInterface->getPointer());
mPointerInterface.release();
mPointerInterface.reset();
}
const bool have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD;
if (have_keyboard && mKeyboard == nullptr)
{
auto keyboard = wl_seat_get_keyboard(mSeat);
mKeyboard = std::make_unique<WaylandKeyboard>(keyboard);
}
else if (!have_keyboard && mKeyboard!= nullptr)
{
mKeyboard.reset();
}
}
@ -36,13 +46,3 @@ void WaylandSeatInterface::seatNameEvent(void *data, struct wl_seat *wl_seat, co
{
MLOG_INFO("seat name: " << name);
}
void WaylandSeatInterface::setKeyboard(wl_keyboard* keyboard)
{
}
void WaylandSeatInterface::setPointer(wl_pointer* pointer)
{
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "WaylandPointerInterface.h"
#include "WaylandKeyboard.h"
#include "wayland-client.h"
@ -12,21 +13,15 @@ public:
WaylandSeatInterface(wl_seat* seat);
private:
static void seatCapabilitiesEvent(void *data, struct wl_seat *wl_seat, uint32_t capabilities);
static void seatNameEvent(void *data, struct wl_seat *wl_seat, const char *name);
void onSeatCapabilitiesEvent(uint32_t capabilities);
void setKeyboard(wl_keyboard* keyboard);
void setPointer(wl_pointer* pointer);
wl_seat* mSeat{nullptr};
wl_seat_listener mSeatListener;
wl_keyboard* mKeyboard{nullptr};
std::unique_ptr<WaylandKeyboard> mKeyboard;
std::unique_ptr<WaylandPointerInterface> mPointerInterface;
};