From a8ddda5f6bf70c7d98083218fb0b96f5483f4d3d Mon Sep 17 00:00:00 2001 From: jeon Date: Wed, 29 Jul 2020 22:27:29 +0900 Subject: [PATCH] DSXkb: Add DSXkb class for using xkb keymap Change-Id: I3a13e44e8168d45f4d5a8634fafad0f3b2f287c9 --- packaging/libds.spec | 1 + src/DSXkb/DSXkb.cpp | 243 +++++++++++++++++++++++++++++++++++++++++++++++ src/DSXkb/DSXkb.h | 40 ++++++++ src/DSXkb/DSXkbPrivate.h | 44 +++++++++ src/meson.build | 9 +- tests/DSXkb-test.cpp | 51 ++++++++++ tests/meson.build | 1 + 7 files changed, 387 insertions(+), 2 deletions(-) create mode 100644 src/DSXkb/DSXkb.cpp create mode 100644 src/DSXkb/DSXkb.h create mode 100644 src/DSXkb/DSXkbPrivate.h create mode 100644 tests/DSXkb-test.cpp diff --git a/packaging/libds.spec b/packaging/libds.spec index c47a179..94c4938 100644 --- a/packaging/libds.spec +++ b/packaging/libds.spec @@ -24,6 +24,7 @@ BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(ecore-evas) BuildRequires: pkgconfig(libinput) BuildRequires: pkgconfig(libudev) +BuildRequires: pkgconfig(xkbcommon) # For samples and tests BuildRequires: pkgconfig(wayland-client) diff --git a/src/DSXkb/DSXkb.cpp b/src/DSXkb/DSXkb.cpp new file mode 100644 index 0000000..cb8fb70 --- /dev/null +++ b/src/DSXkb/DSXkb.cpp @@ -0,0 +1,243 @@ +#include "DSXkb.h" +#include "DSXkbPrivate.h" + +namespace display_server +{ + +DSXkbPrivate::DSXkbPrivate(DSXkb *p_ptr) + : DSObjectPrivate(p_ptr), __p_ptr(p_ptr), + __xkb_state(nullptr), __xkb_keymap(nullptr), __xkb_context(nullptr), + __depressed(0), __latched(0), __locked(0), __group(0) +{ +} + +DSXkbPrivate::~DSXkbPrivate() +{ + xkb_state_unref(__xkb_state); + xkb_keymap_unref(__xkb_keymap); + xkb_context_unref(__xkb_context); +} + +bool DSXkbPrivate::makeKeymap() +{ + DS_GET_PUB(DSXkb); + + __xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!__xkb_context) + { + DSLOG_ERR("DSXkb", "Failed to xkb_context_new()..\n"); + return false; + } + + struct ::xkb_rule_names names = { pub->__rules.c_str(), pub->__model.c_str(), pub->__layout.c_str(), pub->__variant.c_str(), pub->__options.c_str() }; + + __xkb_keymap = xkb_map_new_from_names(__xkb_context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!__xkb_keymap) + { + DSLOG_ERR("DSXkb", "Failed to xkb_map_new_from_names()..\n"); + xkb_context_unref(__xkb_context); + return false; + } + + __xkb_state = xkb_state_new(__xkb_keymap); + if (!__xkb_state) + { + DSLOG_ERR("DSXkb", "Failed to xkb_state_new()..\n"); + xkb_keymap_unref(__xkb_keymap); + xkb_context_unref(__xkb_context); + return false; + } + + return true; +} + +void DSXkbPrivate::updateModifier(int keycode, bool pressed) +{ + enum xkb_key_direction direction; + + if (pressed) + direction = XKB_KEY_DOWN; + else + direction = XKB_KEY_UP; + + xkb_state_update_key(__xkb_state, keycode, direction); + + __depressed = xkb_state_serialize_mods(__xkb_state, XKB_STATE_MODS_DEPRESSED); + __latched = xkb_state_serialize_mods(__xkb_state, XKB_STATE_MODS_LATCHED); + __locked = xkb_state_serialize_mods(__xkb_state, XKB_STATE_MODS_LOCKED); + __group = xkb_state_serialize_mods(__xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); +} + +uint32_t DSXkbPrivate::getModifierDePressed() +{ + return __depressed; +} + +uint32_t DSXkbPrivate::getModifierLatched() +{ + return __latched; +} + +uint32_t DSXkbPrivate::getModifierLocked() +{ + return __locked; +} + +uint32_t DSXkbPrivate::getModifierGroup() +{ + return __group; +} + +std::string DSXkbPrivate::getKeyname(int keycode) +{ + int nsyms; + const xkb_keysym_t *syms; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + char key[256] = {0, }; + std::string keyname; + + nsyms = xkb_key_get_syms(__xkb_state, keycode, &syms); + if (nsyms == 1) sym = syms[0]; + + if (sym == XKB_KEY_NoSymbol) + { + snprintf(key, sizeof(key), "Keycode-%u", keycode); + } + else + { + /* get the keyname for this sym */ + xkb_keysym_get_name(sym, key, sizeof(key)); + } + + if (key[0] == '\0') + { + snprintf(key, sizeof(key), "Keycode-%u", keycode); + } + + keyname = key; + return keyname; +} + +typedef struct _keycode_map +{ + xkb_keysym_t keysym; + xkb_keycode_t keycode; +} keycode_map; + +static void +find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key, void *data) +{ + keycode_map *found_keycodes = (keycode_map *)data; + xkb_keysym_t keysym = found_keycodes->keysym; + int nsyms = 0; + const xkb_keysym_t *syms_out = NULL; + + if (found_keycodes->keycode) return; + + nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out); + if (nsyms && syms_out) + { + if (*syms_out == keysym) + { + found_keycodes->keycode = key; + } + } +} + +int DSXkbPrivate::getKeycode(std::string keyname) +{ + xkb_keysym_t keysym = 0x0; + xkb_keycode_t keycode = 0; + + if (keyname.compare("Keycode-") == 0) + { + keycode = std::stoi(keyname); + } + else + { + keysym = xkb_keysym_from_name(keyname.c_str(), XKB_KEYSYM_NO_FLAGS); + keycode_map found_keycodes = {0,}; + found_keycodes.keysym = keysym; + xkb_keymap_key_for_each(__xkb_keymap, find_keycode, &found_keycodes); + + keycode = found_keycodes.keycode; + } + + return keycode; +} + + +DSXkb::DSXkb(DSSeat *seat) + : DS_INIT_PRIVATE_PTR(DSXkb), + __seat(seat), + __rules("evdev"), __model("pc105"), __layout("us"), __variant(""), __options("") +{ + DS_GET_PRIV(DSXkb); + + priv->makeKeymap(); +} + +DSXkb::DSXkb(DSSeat *seat, std::string rules, std::string model, std::string layout, std::string variant, std::string options) + : DS_INIT_PRIVATE_PTR(DSXkb), + __seat(seat), + __rules(rules), __model(model), __layout(layout), __variant(variant), __options(options) +{ + DS_GET_PRIV(DSXkb); + + priv->makeKeymap(); +} + +DSXkb::~DSXkb() +{ +} + +void DSXkb::updateModifier(int keycode, bool pressed) +{ + DS_GET_PRIV(DSXkb); + + priv->updateModifier(keycode, pressed); +} + +uint32_t DSXkb::getModifierDePressed() +{ + DS_GET_PRIV(DSXkb); + + return priv->getModifierDePressed(); +} + +uint32_t DSXkb::getModifierLatched() +{ + DS_GET_PRIV(DSXkb); + + return priv->getModifierLatched(); +} + +uint32_t DSXkb::getModifierLocked() +{ + DS_GET_PRIV(DSXkb); + + return priv->getModifierLocked(); +} + +uint32_t DSXkb::getModifierGroup() +{ + DS_GET_PRIV(DSXkb); + + return priv->getModifierGroup(); +} + +std::string DSXkb::getKeyname(int keycode) +{ + DS_GET_PRIV(DSXkb); + + return priv->getKeyname(keycode); +} + +int DSXkb::getKeycode(std::string keyname) +{ + DS_GET_PRIV(DSXkb); + + return priv->getKeycode(keyname); +} + +} // namespace display_server diff --git a/src/DSXkb/DSXkb.h b/src/DSXkb/DSXkb.h new file mode 100644 index 0000000..7dd0c5d --- /dev/null +++ b/src/DSXkb/DSXkb.h @@ -0,0 +1,40 @@ +#ifndef __DS_XKB_H__ +#define __DS_XKB_H__ + +#include +#include + +namespace display_server +{ + +class DSXkbPrivate; + +class DSXkb : public DSObject +{ +DS_PIMPL_USE_PRIVATE(DSXkb); +public: + DSXkb(DSSeat *seat); + DSXkb(DSSeat *seat, std::string rules, std::string model, std::string layout, std::string variant, std::string options); + ~DSXkb() override; + + void updateModifier(int keycode, bool pressed); + uint32_t getModifierDePressed(); + uint32_t getModifierLatched(); + uint32_t getModifierLocked(); + uint32_t getModifierGroup(); + + std::string getKeyname(int keycode); + int getKeycode(std::string keyname); + +private: + DSSeat* __seat; + std::string __rules; + std::string __model; + std::string __layout; + std::string __variant; + std::string __options; +}; + +} + +#endif diff --git a/src/DSXkb/DSXkbPrivate.h b/src/DSXkb/DSXkbPrivate.h new file mode 100644 index 0000000..0a27934 --- /dev/null +++ b/src/DSXkb/DSXkbPrivate.h @@ -0,0 +1,44 @@ +#ifndef __DS_XKB_PRIVATE_H__ +#define __DS_XKB_PRIVATE_H__ + +#include +#include +#include "DSXkb.h" + +#include + +namespace display_server +{ + +class DSXkbPrivate : public DSObjectPrivate +{ +DS_PIMPL_USE_PUBLIC(DSXkb); +public: + DSXkbPrivate() = delete; + DSXkbPrivate(DSXkb *p_ptr); + ~DSXkbPrivate(); + + bool makeKeymap(); + void updateModifier(int keycode, bool pressed); + xkb_mod_mask_t getModifierDePressed(); + xkb_mod_mask_t getModifierLatched(); + xkb_mod_mask_t getModifierLocked(); + xkb_mod_mask_t getModifierGroup(); + + std::string getKeyname(int keycode); + int getKeycode(std::string keyname); + +private: + struct ::xkb_state *__xkb_state; + struct ::xkb_keymap *__xkb_keymap; + struct ::xkb_context *__xkb_context; + + xkb_mod_mask_t __depressed; + xkb_mod_mask_t __latched; + xkb_mod_mask_t __locked; + xkb_mod_mask_t __group; +}; + +} + +#endif diff --git a/src/meson.build b/src/meson.build index 30c6848..acdae11 100644 --- a/src/meson.build +++ b/src/meson.build @@ -56,6 +56,9 @@ libds_srcs = [ 'DSClient/DSClientPrivate.h', 'DSClient/DSClient.h', 'DSClient/DSClient.cpp', + 'DSXkb/DSXkbPrivate.h', + 'DSXkb/DSXkb.h', + 'DSXkb/DSXkb.cpp', ] libds_wayland_srcs = [ @@ -153,6 +156,7 @@ libtdm_dep = dependency('libtdm') wayland_dep = dependency('wayland-server') libinput_dep = dependency('libinput') libudev_dep = dependency('libudev') +xkbcommon_dep = dependency('xkbcommon') tizen_ext_dep = dependency('tizen-extension-server') xdg_shell_unstable_v6_dep = dependency('xdg-shell-unstable-v6-server') @@ -191,12 +195,13 @@ libds_include_dirs = include_directories( './DSWindowShell', './DSZone', './DSClient', + './DSXkb', ) libds_lib = shared_library( 'ds', libds_srcs, - dependencies : [dlog_dep, libtdm_dep, wayland_dep, tizen_ext_deps, ecore_dep, ecore_evas_dep, libinput_dep, libudev_dep], + dependencies : [dlog_dep, libtdm_dep, wayland_dep, tizen_ext_deps, ecore_dep, ecore_evas_dep, libinput_dep, libudev_dep, xkbcommon_dep], include_directories : [libds_include_dirs], version : meson.project_version(), install : true @@ -205,7 +210,7 @@ libds_lib = shared_library( libds_static_lib = static_library( 'ds', libds_srcs, - dependencies : [dlog_dep, libtdm_dep, wayland_dep, tizen_ext_deps, ecore_dep, ecore_evas_dep, libinput_dep, libudev_dep], + dependencies : [dlog_dep, libtdm_dep, wayland_dep, tizen_ext_deps, ecore_dep, ecore_evas_dep, libinput_dep, libudev_dep, xkbcommon_dep], include_directories : [libds_include_dirs], install : true ) diff --git a/tests/DSXkb-test.cpp b/tests/DSXkb-test.cpp new file mode 100644 index 0000000..83b2a54 --- /dev/null +++ b/tests/DSXkb-test.cpp @@ -0,0 +1,51 @@ +#include "libds-tests.h" +#include "DSXkb.h" + +using namespace display_server; + +class DSXkbTest : public ::testing::Test +{ +public: + void SetUp(void) override + {} + void TearDown(void) override + {} +}; + +TEST_F(DSXkbTest, NewDSXkb) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + EXPECT_TRUE(xkb != nullptr); + + delete xkb; + delete seat; +} + +TEST_F(DSXkbTest, GetKeyname) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + EXPECT_TRUE(xkb != nullptr); + + std::string keyname = xkb->getKeyname(166); + + EXPECT_TRUE(!keyname.empty()); + + delete xkb; + delete seat; +} + +TEST_F(DSXkbTest, GetKeycode) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + EXPECT_TRUE(xkb != nullptr); + + int keycode = xkb->getKeycode("XF86Back"); + + EXPECT_TRUE(keycode > 8); + + delete xkb; + delete seat; +} diff --git a/tests/meson.build b/tests/meson.build index fd461e5..e98ae22 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -43,6 +43,7 @@ libds_tests_srcs = [ 'DSWaylandTextInputManager-test.cpp', 'DSWaylandInputPanel-test.cpp', 'DSWaylandInputPanelSurface-test.cpp', + 'DSXkb-test.cpp', ] gmock_dep = dependency('gmock', method : 'pkg-config') -- 2.7.4