DSXkb: Add DSXkb class for using xkb keymap 85/241685/1
authorjeon <jhyuni.kang@samsung.com>
Wed, 29 Jul 2020 13:27:29 +0000 (22:27 +0900)
committerSung-Jin Park <sj76.park@samsung.com>
Thu, 20 Aug 2020 10:04:47 +0000 (19:04 +0900)
Change-Id: I3a13e44e8168d45f4d5a8634fafad0f3b2f287c9

packaging/libds.spec
src/DSXkb/DSXkb.cpp [new file with mode: 0644]
src/DSXkb/DSXkb.h [new file with mode: 0644]
src/DSXkb/DSXkbPrivate.h [new file with mode: 0644]
src/meson.build
tests/DSXkb-test.cpp [new file with mode: 0644]
tests/meson.build

index c47a179..94c4938 100644 (file)
@@ -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 (file)
index 0000000..cb8fb70
--- /dev/null
@@ -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 (file)
index 0000000..7dd0c5d
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __DS_XKB_H__
+#define __DS_XKB_H__
+
+#include <DSCore.h>
+#include <DSSeat.h>
+
+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 (file)
index 0000000..0a27934
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __DS_XKB_PRIVATE_H__
+#define __DS_XKB_PRIVATE_H__
+
+#include <DSCore.h>
+#include <DSSeat.h>
+#include "DSXkb.h"
+
+#include <xkbcommon/xkbcommon.h>
+
+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
index 30c6848..acdae11 100644 (file)
@@ -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 (file)
index 0000000..83b2a54
--- /dev/null
@@ -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;
+}
index fd461e5..e98ae22 100644 (file)
@@ -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')