Skip to content

Commit

Permalink
keyboard: properly update keymap state and fd on keymap changes
Browse files Browse the repository at this point in the history
needed for virtual keyboards that impose their own layouts.

fixes #6991
  • Loading branch information
vaxerski committed Jul 25, 2024
1 parent 4beac91 commit daf5fad
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 25 deletions.
42 changes: 31 additions & 11 deletions src/devices/IKeyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ void IKeyboard::clearManuallyAllocd() {
}

void IKeyboard::setKeymap(const SStringRuleNames& rules) {
if (keymapOverridden) {
Debug::log(LOG, "Ignoring setKeymap: keymap is overridden");
return;
}

currentRules = rules;
xkb_rule_names XKBRULES = {
.rules = rules.rules.c_str(),
Expand Down Expand Up @@ -103,10 +108,6 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
}

// set internal translation state
// demo sunao ni ienai
xkbStaticState = xkb_state_new(xkbKeymap);

updateXKBTranslationState(xkbKeymap);

const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
Expand All @@ -131,6 +132,20 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
}

updateKeymapFD();

xkb_context_unref(CONTEXT);

g_pSeatManager->updateActiveKeyboardData();
}

void IKeyboard::updateKeymapFD() {
Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName);

if (xkbKeymapFD >= 0)
close(xkbKeymapFD);
xkbKeymapFD = -1;

auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
xkbKeymapString = cKeymapStr;
free(cKeymapStr);
Expand All @@ -151,21 +166,24 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
}
}

xkb_context_unref(CONTEXT);

g_pSeatManager->updateActiveKeyboardData();
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD);
}

void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {

if (xkbStaticState)
xkb_state_unref(xkbStaticState);

if (xkbState)
xkb_state_unref(xkbState);

xkbState = nullptr;
xkbState = nullptr;
xkbStaticState = nullptr;

if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbState = xkb_state_new(keymap);
xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap);
return;
}

Expand Down Expand Up @@ -209,7 +227,8 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}

xkbState = xkb_state_new(KEYMAP);
xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP);

xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT);
Expand All @@ -230,7 +249,8 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {

const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);

xkbState = xkb_state_new(NEWKEYMAP);
xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = xkb_state_new(NEWKEYMAP);

xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT);
Expand Down
30 changes: 18 additions & 12 deletions src/devices/IKeyboard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,24 @@ class IKeyboard : public IHID {
std::string rules = "";
};

void setKeymap(const SStringRuleNames& rules);
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
std::string getActiveLayout();
void updateLEDs();
void updateLEDs(uint32_t leds);
uint32_t getModifiers();
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
bool updateModifiersState(); // rets whether changed
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);

bool active = false;
bool enabled = true;
void setKeymap(const SStringRuleNames& rules);
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
std::string getActiveLayout();
void updateLEDs();
void updateLEDs(uint32_t leds);
uint32_t getModifiers();
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
bool updateModifiersState(); // rets whether changed
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
void updateKeymapFD();

bool active = false;
bool enabled = true;

// if the keymap is overridden by the implementation,
// don't try to set keyboard rules anymore, to avoid overwriting the requested one.
// e.g. Virtual keyboards with custom maps.
bool keymapOverridden = false;

xkb_layout_index_t activeLayout = 0;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
Expand Down
9 changes: 7 additions & 2 deletions src/devices/VirtualKeyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keybo
});
});
listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) {
auto E = std::any_cast<SKeymapEvent>(d);
xkbKeymap = xkb_keymap_ref(E.keymap);
auto E = std::any_cast<SKeymapEvent>(d);
if (xkbKeymap)
xkb_keymap_unref(xkbKeymap);
xkbKeymap = xkb_keymap_ref(E.keymap);
keymapOverridden = true;
updateXKBTranslationState(xkbKeymap);
updateKeymapFD();
keyboardEvents.keymap.emit(d);
});

Expand Down

0 comments on commit daf5fad

Please sign in to comment.