core: add support for composed keys (#551)

This commit is contained in:
Maximilian Seidler 2024-11-11 16:49:51 +01:00 committed by GitHub
parent 6c3c444136
commit d8bd25b52d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 13 deletions

View file

@ -722,6 +722,15 @@ static void handleKeyboardKeymap(void* data, wl_keyboard* wl_keyboard, uint form
Debug::log(ERR, "Failed to create xkb state"); Debug::log(ERR, "Failed to create xkb state");
return; return;
} }
const auto PCOMOPOSETABLE = xkb_compose_table_new_from_locale(g_pHyprlock->m_pXKBContext, setlocale(LC_CTYPE, nullptr), XKB_COMPOSE_COMPILE_NO_FLAGS);
if (!PCOMOPOSETABLE) {
Debug::log(ERR, "Failed to create xkb compose table");
return;
}
g_pHyprlock->m_pXKBComposeState = xkb_compose_state_new(PCOMOPOSETABLE, XKB_COMPOSE_STATE_NO_FLAGS);
} }
static void handleKeyboardKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { static void handleKeyboardKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
@ -855,6 +864,9 @@ void CHyprlock::startKeyRepeat(xkb_keysym_t sym) {
m_pKeyRepeatTimer.reset(); m_pKeyRepeatTimer.reset();
} }
if (m_pXKBComposeState)
xkb_compose_state_reset(m_pXKBComposeState);
if (m_iKeebRepeatDelay <= 0) if (m_iKeebRepeatDelay <= 0)
return; return;
@ -865,7 +877,7 @@ void CHyprlock::repeatKey(xkb_keysym_t sym) {
if (m_iKeebRepeatRate <= 0) if (m_iKeebRepeatRate <= 0)
return; return;
handleKeySym(sym); handleKeySym(sym, false);
// This condition is for backspace and delete keys, but should also be ok for other keysyms since our buffer won't be empty anyways // This condition is for backspace and delete keys, but should also be ok for other keysyms since our buffer won't be empty anyways
if (bool CONTINUE = m_sPasswordState.passBuffer.length() > 0; CONTINUE) if (bool CONTINUE = m_sPasswordState.passBuffer.length() > 0; CONTINUE)
@ -907,22 +919,32 @@ void CHyprlock::onKey(uint32_t key, bool down) {
} }
if (down) { if (down) {
const auto SYM = xkb_state_key_get_one_sym(m_pXKBState, key + 8);
m_bCapsLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED); m_bCapsLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED);
m_bNumLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED); m_bNumLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED);
m_bCtrl = xkb_state_mod_name_is_active(m_pXKBState, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE); m_bCtrl = xkb_state_mod_name_is_active(m_pXKBState, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE);
handleKeySym(SYM); const auto SYM = xkb_state_key_get_one_sym(m_pXKBState, key + 8);
enum xkb_compose_status composeStatus = XKB_COMPOSE_NOTHING;
if (m_pXKBComposeState) {
xkb_compose_state_feed(m_pXKBComposeState, SYM);
composeStatus = xkb_compose_state_get_status(m_pXKBComposeState);
}
handleKeySym(SYM, composeStatus == XKB_COMPOSE_COMPOSED);
if (SYM == XKB_KEY_BackSpace || SYM == XKB_KEY_Delete) // keys allowed to repeat if (SYM == XKB_KEY_BackSpace || SYM == XKB_KEY_Delete) // keys allowed to repeat
startKeyRepeat(SYM); startKeyRepeat(SYM);
}
} else if (m_pXKBComposeState && xkb_compose_state_get_status(m_pXKBComposeState) == XKB_COMPOSE_COMPOSED)
xkb_compose_state_reset(m_pXKBComposeState);
renderAllOutputs(); renderAllOutputs();
} }
void CHyprlock::handleKeySym(xkb_keysym_t sym) { void CHyprlock::handleKeySym(xkb_keysym_t sym, bool composed) {
const auto SYM = sym; const auto SYM = sym;
if (SYM == XKB_KEY_Escape || (m_bCtrl && (SYM == XKB_KEY_u || SYM == XKB_KEY_BackSpace))) { if (SYM == XKB_KEY_Escape || (m_bCtrl && (SYM == XKB_KEY_u || SYM == XKB_KEY_BackSpace))) {
Debug::log(LOG, "Clearing password buffer"); Debug::log(LOG, "Clearing password buffer");
@ -951,7 +973,9 @@ void CHyprlock::handleKeySym(xkb_keysym_t sym) {
m_bNumLock = !m_bNumLock; m_bNumLock = !m_bNumLock;
} else { } else {
char buf[16] = {0}; char buf[16] = {0};
int len = xkb_keysym_to_utf8(SYM, buf, 16); int len = (composed) ? xkb_compose_state_get_utf8(m_pXKBComposeState, buf, sizeof(buf)) /* nullbyte */ + 1 :
xkb_keysym_to_utf8(SYM, buf, sizeof(buf)) /* already includes a nullbyte */;
if (len > 1) if (len > 1)
m_sPasswordState.passBuffer += std::string{buf, len - 1}; m_sPasswordState.passBuffer += std::string{buf, len - 1};
} }

View file

@ -14,6 +14,7 @@
#include <optional> #include <optional>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include <gbm.h> #include <gbm.h>
#include <xf86drm.h> #include <xf86drm.h>
@ -55,9 +56,9 @@ class CHyprlock {
std::string spawnSync(const std::string& cmd); std::string spawnSync(const std::string& cmd);
void onKey(uint32_t key, bool down); void onKey(uint32_t key, bool down);
void handleKeySym(xkb_keysym_t sym);
void startKeyRepeat(xkb_keysym_t sym); void startKeyRepeat(xkb_keysym_t sym);
void repeatKey(xkb_keysym_t sym); void repeatKey(xkb_keysym_t sym);
void handleKeySym(xkb_keysym_t sym, bool compose);
void onPasswordCheckTimer(); void onPasswordCheckTimer();
void clearPasswordBuffer(); void clearPasswordBuffer();
bool passwordCheckWaiting(); bool passwordCheckWaiting();
@ -79,13 +80,13 @@ class CHyprlock {
zwlr_screencopy_manager_v1* getScreencopy(); zwlr_screencopy_manager_v1* getScreencopy();
wl_pointer* m_pPointer = nullptr; wl_pointer* m_pPointer = nullptr;
wl_keyboard* m_pKeeb = nullptr;
std::unique_ptr<CCursorShape> m_pCursorShape; std::unique_ptr<CCursorShape> m_pCursorShape;
wl_keyboard* m_pKeeb = nullptr;
xkb_context* m_pXKBContext = nullptr; xkb_context* m_pXKBContext = nullptr;
xkb_keymap* m_pXKBKeymap = nullptr; xkb_keymap* m_pXKBKeymap = nullptr;
xkb_state* m_pXKBState = nullptr; xkb_state* m_pXKBState = nullptr;
xkb_compose_state* m_pXKBComposeState = nullptr;
int32_t m_iKeebRepeatRate = 25; int32_t m_iKeebRepeatRate = 25;
int32_t m_iKeebRepeatDelay = 600; int32_t m_iKeebRepeatDelay = 600;