From 4a3aa8d4420f7fc402d6c5d8e3e1b8166e4bf325 Mon Sep 17 00:00:00 2001 From: jeon Date: Thu, 30 Jul 2020 19:46:28 +0900 Subject: [PATCH] DSXkb: Imply xkb to get keyname and update modifiers Change-Id: I8f4064428691e949e9447e3894616571eae00900 --- src/DSInput/DSInput.cpp | 37 +++++++++++- src/DSInput/DSInput.h | 3 + src/DSInput/DSInputEvent.h | 1 + src/DSSeat/DSSeat.cpp | 5 +- src/DSSeat/DSSeat.h | 2 + src/DSXkb/DSXkb.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++++- src/DSXkb/DSXkb.h | 4 +- src/DSXkb/DSXkbPrivate.h | 13 ++++- tests/DSXkb-test.cpp | 82 ++++++++++++++++++++++++++ 9 files changed, 279 insertions(+), 8 deletions(-) diff --git a/src/DSInput/DSInput.cpp b/src/DSInput/DSInput.cpp index a1bf408..817755a 100644 --- a/src/DSInput/DSInput.cpp +++ b/src/DSInput/DSInput.cpp @@ -2,6 +2,7 @@ #include "DSInputPrivate.h" #include "DSSeat.h" #include "DSInputEvent.h" +#include "DSXkb.h" namespace display_server { @@ -104,14 +105,16 @@ void DSInput::__initiaiize_ecore_event_types() DSInput::DSInput() : DS_INIT_PRIVATE_PTR(DSInput), - __seat(nullptr) + __seat(nullptr), + __xkb(nullptr) { __initiaiize_ecore_event_types(); } DSInput::DSInput(DSSeat *seat) : DS_INIT_PRIVATE_PTR(DSInput), - __seat(seat) + __seat(seat), + __xkb(nullptr) { if (seat == nullptr) { @@ -122,6 +125,21 @@ DSInput::DSInput(DSSeat *seat) __initiaiize_ecore_event_types(); } +DSInput::DSInput(DSSeat *seat, DSXkb *xkb) + : DS_INIT_PRIVATE_PTR(DSInput), + __seat(seat), + __xkb(xkb) +{ + if (seat == nullptr) + { + DSLOG_ERR("DSInput", "DSSeat ptr is required."); + return; + } + + __initiaiize_ecore_event_types(); +} + + DSInput::~DSInput() { for (auto eventHandler : __eventHandlerList) @@ -192,6 +210,11 @@ void DSInput::keyDown(int keycode, std::string devIdentifier, DSInput::DeviceCla DSLOG_DBG("DSInput", "[keyDown] keycode: %d, identifier: %d\n", keycode, devIdentifier); DSInputDevice *device = findDevice(devIdentifier, devClass); DSInputKeyboardEvent *ev = new DSInputKeyboardEvent(std::make_shared(*device), DSInputEvent::KeyDownEvent, 0, keycode); + if (__xkb) + { + __xkb->updateModifier(keycode, true); + ev->setKeyname(__xkb->getKeyname(keycode)); + } ecore_event_add(DS_INPUT_EVENT_KEY_DOWN, (void *)ev, nullptr, nullptr); } @@ -200,6 +223,11 @@ void DSInput::keyUp(int keycode, std::string devIdentifier, DSInput::DeviceClass DSLOG_DBG("DSInput", "[keyUp] keycode: %d, identifier: %d\n", keycode, devIdentifier); DSInputDevice *device = findDevice(devIdentifier, devClass); DSInputKeyboardEvent *ev = new DSInputKeyboardEvent(std::make_shared(*device), DSInputEvent::KeyUpEvent, 0, keycode); + if (__xkb) + { + __xkb->updateModifier(keycode, false); + ev->setKeyname(__xkb->getKeyname(keycode)); + } ecore_event_add(DS_INPUT_EVENT_KEY_UP, (void *)ev, nullptr, nullptr); } @@ -446,6 +474,11 @@ const std::string DSInputKeyboardEvent::getKeyname() return __keyname; } +void DSInputKeyboardEvent::setKeyname(std::string name) +{ + __keyname = name; +} + DSInputMouseEvent::DSInputMouseEvent() : DSInputEvent(nullptr, NoneEvent, 0), diff --git a/src/DSInput/DSInput.h b/src/DSInput/DSInput.h index 6f53993..3555256 100644 --- a/src/DSInput/DSInput.h +++ b/src/DSInput/DSInput.h @@ -17,6 +17,7 @@ namespace display_server class DSSeat; class DSInputPrivate; class DSInputDevice; +class DSXkb; class DSInput : public DSObject { @@ -34,6 +35,7 @@ public: public: DSInput(); DSInput(DSSeat *seat); + DSInput(DSSeat *seat, DSXkb *xkb); ~DSInput() override; void init(); @@ -64,6 +66,7 @@ public: private: DSSeat* __seat; + DSXkb* __xkb; std::list devList; DSSignal> __deviceAddSignal; diff --git a/src/DSInput/DSInputEvent.h b/src/DSInput/DSInputEvent.h index 7a8f75e..b737289 100644 --- a/src/DSInput/DSInputEvent.h +++ b/src/DSInput/DSInputEvent.h @@ -55,6 +55,7 @@ public: const int getKeycode(); const std::string getKeyname(); + void setKeyname(std::string name); protected: int __keycode; diff --git a/src/DSSeat/DSSeat.cpp b/src/DSSeat/DSSeat.cpp index b911c17..2a49039 100644 --- a/src/DSSeat/DSSeat.cpp +++ b/src/DSSeat/DSSeat.cpp @@ -5,6 +5,7 @@ #include "DSWaylandSeat.h" #include "DSWaylandCompositor.h" #include "DSInputEvent.h" +#include "DSXkb.h" namespace display_server { @@ -18,6 +19,7 @@ DSSeat::DSSeat() __dswlSeat(nullptr), __dswlComp(nullptr), __compositor(nullptr), + __xkb(nullptr), __numPointer(0), __numKeyboard(0), __numTouch(0) @@ -32,6 +34,7 @@ DSSeat::DSSeat(DSCompositor *compositor, std::string name) __dswlSeat(nullptr), __dswlComp(nullptr), __compositor(compositor), + __xkb(new DSXkb(this)), __numPointer(0), __numKeyboard(0), __numTouch(0) @@ -48,7 +51,7 @@ DSSeat::DSSeat(DSCompositor *compositor, std::string name) if (!name.empty()) __dswlSeat->setName(name); - __input = new DSInput(this); + __input = new DSInput(this, __xkb); DS_ASSERT(__input != nullptr); __input->registerCallbackDeviceAdd(this, std::bind(&DSSeat::slotDeviceAdd, this, std::placeholders::_1)); diff --git a/src/DSSeat/DSSeat.h b/src/DSSeat/DSSeat.h index a7347a0..5842428 100644 --- a/src/DSSeat/DSSeat.h +++ b/src/DSSeat/DSSeat.h @@ -15,6 +15,7 @@ class DSInputDevice; class DSCompositor; class DSWaylandSeat; class DSWaylandCompositor; +class DSXkb; class DSSeat : public DSObject { @@ -34,6 +35,7 @@ private: DSWaylandSeat *__dswlSeat; DSWaylandCompositor *__dswlComp; DSCompositor *__compositor; + DSXkb *__xkb; uint32_t __numPointer; uint32_t __numKeyboard; diff --git a/src/DSXkb/DSXkb.cpp b/src/DSXkb/DSXkb.cpp index cb8fb70..8a80669 100644 --- a/src/DSXkb/DSXkb.cpp +++ b/src/DSXkb/DSXkb.cpp @@ -1,12 +1,16 @@ #include "DSXkb.h" #include "DSXkbPrivate.h" +#include +#include + namespace display_server { DSXkbPrivate::DSXkbPrivate(DSXkb *p_ptr) : DSObjectPrivate(p_ptr), __p_ptr(p_ptr), __xkb_state(nullptr), __xkb_keymap(nullptr), __xkb_context(nullptr), + __keymap_fd(-1), __keymap_size(0), __keymap_area(nullptr), __depressed(0), __latched(0), __locked(0), __group(0) { } @@ -51,6 +55,52 @@ bool DSXkbPrivate::makeKeymap() return true; } +void DSXkbPrivate::mmapKeymap() +{ + char *tmp; + + if (__keymap_area) + { + munmap(__keymap_area, __keymap_size); + } + if (__keymap_fd >= 0) + { + close(__keymap_fd); + __keymap_fd = -1; + } + __keymap_size = 0; + + if (!(tmp = xkb_map_get_as_string(__xkb_keymap))) + { + DSLOG_ERR("DSXkb", "Could not get keymap string"); + return; + } + + __keymap_size = strlen(tmp) + 1; + __keymap_fd = __getKeymapFd(__keymap_size); + if (__keymap_fd < 0) + { + DSLOG_ERR("DSXkb", "Could not create keymap file"); + free(tmp); + __keymap_size = 0; + return; + } + + __keymap_area = (char *)mmap(nullptr, __keymap_size, (PROT_READ | PROT_WRITE), MAP_SHARED, __keymap_fd, 0); + if (__keymap_area == MAP_FAILED) + { + DSLOG_ERR("DSXkb", "Failed to mmap keymap area: %m"); + free(tmp); + __keymap_size = 0; + close(__keymap_fd); + __keymap_fd = -1; + return; + } + + strncpy(__keymap_area, tmp, __keymap_size); + free(tmp); +} + void DSXkbPrivate::updateModifier(int keycode, bool pressed) { enum xkb_key_direction direction; @@ -68,7 +118,7 @@ void DSXkbPrivate::updateModifier(int keycode, bool pressed) __group = xkb_state_serialize_mods(__xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); } -uint32_t DSXkbPrivate::getModifierDePressed() +uint32_t DSXkbPrivate::getModifierDepressed() { return __depressed; } @@ -88,6 +138,16 @@ uint32_t DSXkbPrivate::getModifierGroup() return __group; } +int DSXkbPrivate::getKeymapFd() +{ + return __keymap_fd; +} + +int DSXkbPrivate::getKeymapSize() +{ + return __keymap_size; +} + std::string DSXkbPrivate::getKeyname(int keycode) { int nsyms; @@ -166,6 +226,64 @@ int DSXkbPrivate::getKeycode(std::string keyname) return keycode; } +int DSXkbPrivate::__getKeymapFd(off_t size) +{ + int fd = 0, blen = 0, len = 0; + char *path; + char tmp[PATH_MAX] = {0, }; + long flags; + mode_t old_umask; + + blen = sizeof(tmp) - 20; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) return -1; + + len = strlen(path) + 19; + if (len < blen) + { + strncpy(tmp, path, PATH_MAX - 20); + strncat(tmp, "/e-wl-keymap-XXXXXX", 19); + free(path); + } + else + { + free(path); + return -1; + } + + old_umask = umask(S_IRWXG|S_IRWXO); + fd = mkstemp(tmp); + umask(old_umask); + + if (fd < 0) + { + return -1; + } + + flags = fcntl(fd, F_GETFD); + if (flags < 0) + { + close(fd); + return -1; + } + + if (fcntl(fd, F_SETFD, (flags | FD_CLOEXEC)) == -1) + { + close(fd); + return -1; + } + + if (ftruncate(fd, size) < 0) + { + close(fd); + return -1; + } + + unlink(tmp); + return fd; +} + DSXkb::DSXkb(DSSeat *seat) : DS_INIT_PRIVATE_PTR(DSXkb), @@ -175,6 +293,7 @@ DSXkb::DSXkb(DSSeat *seat) DS_GET_PRIV(DSXkb); priv->makeKeymap(); + priv->mmapKeymap(); } DSXkb::DSXkb(DSSeat *seat, std::string rules, std::string model, std::string layout, std::string variant, std::string options) @@ -185,6 +304,7 @@ DSXkb::DSXkb(DSSeat *seat, std::string rules, std::string model, std::string lay DS_GET_PRIV(DSXkb); priv->makeKeymap(); + priv->mmapKeymap(); } DSXkb::~DSXkb() @@ -198,11 +318,11 @@ void DSXkb::updateModifier(int keycode, bool pressed) priv->updateModifier(keycode, pressed); } -uint32_t DSXkb::getModifierDePressed() +uint32_t DSXkb::getModifierDepressed() { DS_GET_PRIV(DSXkb); - return priv->getModifierDePressed(); + return priv->getModifierDepressed(); } uint32_t DSXkb::getModifierLatched() @@ -226,6 +346,20 @@ uint32_t DSXkb::getModifierGroup() return priv->getModifierGroup(); } +int DSXkb::getKeymapFd() +{ + DS_GET_PRIV(DSXkb); + + return priv->getKeymapFd(); +} + +int DSXkb::getKeymapSize() +{ + DS_GET_PRIV(DSXkb); + + return priv->getKeymapSize(); +} + std::string DSXkb::getKeyname(int keycode) { DS_GET_PRIV(DSXkb); diff --git a/src/DSXkb/DSXkb.h b/src/DSXkb/DSXkb.h index 7dd0c5d..a1e32ab 100644 --- a/src/DSXkb/DSXkb.h +++ b/src/DSXkb/DSXkb.h @@ -18,10 +18,12 @@ public: ~DSXkb() override; void updateModifier(int keycode, bool pressed); - uint32_t getModifierDePressed(); + uint32_t getModifierDepressed(); uint32_t getModifierLatched(); uint32_t getModifierLocked(); uint32_t getModifierGroup(); + int getKeymapFd(); + int getKeymapSize(); std::string getKeyname(int keycode); int getKeycode(std::string keyname); diff --git a/src/DSXkb/DSXkbPrivate.h b/src/DSXkb/DSXkbPrivate.h index 0a27934..d1f89d6 100644 --- a/src/DSXkb/DSXkbPrivate.h +++ b/src/DSXkb/DSXkbPrivate.h @@ -20,23 +20,34 @@ public: bool makeKeymap(); void updateModifier(int keycode, bool pressed); - xkb_mod_mask_t getModifierDePressed(); + xkb_mod_mask_t getModifierDepressed(); xkb_mod_mask_t getModifierLatched(); xkb_mod_mask_t getModifierLocked(); xkb_mod_mask_t getModifierGroup(); + int getKeymapFd(); + int getKeymapSize(); std::string getKeyname(int keycode); int getKeycode(std::string keyname); +protected: + void mmapKeymap(); + private: struct ::xkb_state *__xkb_state; struct ::xkb_keymap *__xkb_keymap; struct ::xkb_context *__xkb_context; + int __keymap_fd; + size_t __keymap_size; + char *__keymap_area; + xkb_mod_mask_t __depressed; xkb_mod_mask_t __latched; xkb_mod_mask_t __locked; xkb_mod_mask_t __group; + + int __getKeymapFd(off_t size); }; } diff --git a/tests/DSXkb-test.cpp b/tests/DSXkb-test.cpp index 83b2a54..832363c 100644 --- a/tests/DSXkb-test.cpp +++ b/tests/DSXkb-test.cpp @@ -49,3 +49,85 @@ TEST_F(DSXkbTest, GetKeycode) delete xkb; delete seat; } + +TEST_F(DSXkbTest, GetModifierDepressed) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + uint32_t depressed = xkb->getModifierDepressed(); + int keycode = xkb->getKeycode("Shift_L"); + + xkb->updateModifier(keycode, true); + + EXPECT_TRUE(depressed != xkb->getModifierDepressed()); + xkb->updateModifier(keycode, false); + + delete xkb; + delete seat; +} + +TEST_F(DSXkbTest, GetModifierLatched) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + + (void)xkb->getModifierLatched(); + + delete xkb; + delete seat; +} + +TEST_F(DSXkbTest, GetModifierLocked) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + uint32_t locked = xkb->getModifierLocked(); + int keycode = xkb->getKeycode("Caps_Lock"); + + xkb->updateModifier(keycode, true); + xkb->updateModifier(keycode, false); + + EXPECT_TRUE(locked != xkb->getModifierLocked()); + + xkb->updateModifier(keycode, true); + xkb->updateModifier(keycode, false); + + delete xkb; + delete seat; +} + +TEST_F(DSXkbTest, GetModifierGroup) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + + (void)xkb->getModifierGroup(); + + delete xkb; + delete seat; +} + +TEST_F(DSXkbTest, GetKeymapFd) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + int fd = xkb->getKeymapFd(); + + EXPECT_TRUE(fd >= 0); + + delete xkb; + delete seat; +} + +TEST_F(DSXkbTest, GetKeymapSize) +{ + DSSeat *seat = new DSSeat; + DSXkb *xkb = new DSXkb(seat); + int size = xkb->getKeymapSize(); + + EXPECT_TRUE(size > 0); + + delete xkb; + delete seat; +} + -- 2.7.4