core: add key repeat for backspace and make del clear the input (#277)

* core: add support for repeating backspace when held

* core: move keysym handling to a seperate function in order to reuse it for key repeat

* core: get keyboard repeat info from wayland

* core: defaults for keyboard repeat and delay
This commit is contained in:
Maximilian Seidler 2024-05-14 17:11:45 +02:00 committed by GitHub
parent 386a1e6fc2
commit 316c37746d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 84 additions and 34 deletions

View file

@ -695,7 +695,8 @@ static void handleKeyboardModifiers(void* data, wl_keyboard* wl_keyboard, uint s
}
static void handleRepeatInfo(void* data, struct wl_keyboard* wl_keyboard, int32_t rate, int32_t delay) {
;
g_pHyprlock->m_iKeebRepeatRate = rate;
g_pHyprlock->m_iKeebRepeatDelay = delay;
}
inline const wl_keyboard_listener keyboardListener = {
@ -793,6 +794,35 @@ void CHyprlock::renderOutput(const std::string& stringPort) {
PMONITOR->sessionLockSurface->render();
}
void CHyprlock::startKeyRepeat(xkb_keysym_t sym) {
if (m_pKeyRepeatTimer) {
m_pKeyRepeatTimer->cancel();
m_pKeyRepeatTimer.reset();
}
if (m_iKeebRepeatDelay <= 0)
return;
m_pKeyRepeatTimer = addTimer(
std::chrono::milliseconds(m_iKeebRepeatDelay), [sym](std::shared_ptr<CTimer> self, void* data) { g_pHyprlock->repeatKey(sym); }, nullptr);
}
void CHyprlock::repeatKey(xkb_keysym_t sym) {
if (m_iKeebRepeatRate <= 0)
return;
handleKeySym(sym);
// 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)
m_pKeyRepeatTimer = addTimer(
std::chrono::milliseconds(m_iKeebRepeatRate), [sym](std::shared_ptr<CTimer> self, void* data) { g_pHyprlock->repeatKey(sym); }, nullptr);
for (auto& o : m_vOutputs) {
o->sessionLockSurface->render();
}
}
void CHyprlock::onKey(uint32_t key, bool down) {
if (m_bFadeStarted)
return;
@ -812,8 +842,13 @@ void CHyprlock::onKey(uint32_t key, bool down) {
if (down)
m_vPressedKeys.push_back(key);
else
else {
std::erase(m_vPressedKeys, key);
if (m_pKeyRepeatTimer) {
m_pKeyRepeatTimer->cancel();
m_pKeyRepeatTimer.reset();
}
}
if (g_pAuth->checkWaiting()) {
for (auto& o : m_vOutputs) {
@ -829,38 +864,9 @@ void CHyprlock::onKey(uint32_t key, bool down) {
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);
if (SYM == XKB_KEY_Escape || (m_bCtrl && (SYM == XKB_KEY_u || SYM == XKB_KEY_BackSpace))) {
Debug::log(LOG, "Clearing password buffer");
m_sPasswordState.passBuffer = "";
} else if (SYM == XKB_KEY_Return || SYM == XKB_KEY_KP_Enter) {
Debug::log(LOG, "Authenticating");
static auto* const PIGNOREEMPTY = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:ignore_empty_input");
if (m_sPasswordState.passBuffer.empty() && **PIGNOREEMPTY) {
Debug::log(LOG, "Ignoring empty input");
return;
}
g_pAuth->submitInput(m_sPasswordState.passBuffer);
} else if (SYM == XKB_KEY_BackSpace) {
if (m_sPasswordState.passBuffer.length() > 0) {
// handle utf-8
while ((m_sPasswordState.passBuffer.back() & 0xc0) == 0x80)
m_sPasswordState.passBuffer.pop_back();
m_sPasswordState.passBuffer = m_sPasswordState.passBuffer.substr(0, m_sPasswordState.passBuffer.length() - 1);
}
} else if (SYM == XKB_KEY_Caps_Lock) {
m_bCapsLock = !m_bCapsLock;
} else if (SYM == XKB_KEY_Num_Lock) {
m_bNumLock = !m_bNumLock;
} else {
char buf[16] = {0};
int len = xkb_keysym_to_utf8(SYM, buf, 16);
if (len > 1)
m_sPasswordState.passBuffer += std::string{buf, len - 1};
}
handleKeySym(SYM);
if (SYM == XKB_KEY_BackSpace || SYM == XKB_KEY_Delete) // keys allowed to repeat
startKeyRepeat(SYM);
}
for (auto& o : m_vOutputs) {
@ -868,6 +874,42 @@ void CHyprlock::onKey(uint32_t key, bool down) {
}
}
void CHyprlock::handleKeySym(xkb_keysym_t sym) {
const auto SYM = sym;
if (SYM == XKB_KEY_Escape || (m_bCtrl && (SYM == XKB_KEY_u || SYM == XKB_KEY_BackSpace))) {
Debug::log(LOG, "Clearing password buffer");
m_sPasswordState.passBuffer = "";
} else if (SYM == XKB_KEY_Return || SYM == XKB_KEY_KP_Enter) {
Debug::log(LOG, "Authenticating");
static auto* const PIGNOREEMPTY = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:ignore_empty_input");
if (m_sPasswordState.passBuffer.empty() && **PIGNOREEMPTY) {
Debug::log(LOG, "Ignoring empty input");
return;
}
g_pAuth->submitInput(m_sPasswordState.passBuffer);
} else if (SYM == XKB_KEY_BackSpace || SYM == XKB_KEY_Delete) {
if (m_sPasswordState.passBuffer.length() > 0) {
// handle utf-8
while ((m_sPasswordState.passBuffer.back() & 0xc0) == 0x80)
m_sPasswordState.passBuffer.pop_back();
m_sPasswordState.passBuffer = m_sPasswordState.passBuffer.substr(0, m_sPasswordState.passBuffer.length() - 1);
}
} else if (SYM == XKB_KEY_Caps_Lock) {
m_bCapsLock = !m_bCapsLock;
} else if (SYM == XKB_KEY_Num_Lock) {
m_bNumLock = !m_bNumLock;
} else {
char buf[16] = {0};
int len = xkb_keysym_to_utf8(SYM, buf, 16);
if (len > 1)
m_sPasswordState.passBuffer += std::string{buf, len - 1};
}
}
void CHyprlock::acquireSessionLock() {
Debug::log(LOG, "Locking session");
m_sLockState.lock = ext_session_lock_manager_v1_lock(m_sWaylandState.sessionLock);

View file

@ -54,6 +54,9 @@ class CHyprlock {
std::string spawnSync(const std::string& cmd);
void onKey(uint32_t key, bool down);
void handleKeySym(xkb_keysym_t sym);
void startKeyRepeat(xkb_keysym_t sym);
void repeatKey(xkb_keysym_t sym);
void onPasswordCheckTimer();
void clearPasswordBuffer();
bool passwordCheckWaiting();
@ -82,6 +85,9 @@ class CHyprlock {
xkb_keymap* m_pXKBKeymap = nullptr;
xkb_state* m_pXKBState = nullptr;
int32_t m_iKeebRepeatRate = 25;
int32_t m_iKeebRepeatDelay = 600;
xkb_layout_index_t m_uiActiveLayout = 0;
bool m_bTerminate = false;
@ -97,6 +103,8 @@ class CHyprlock {
std::chrono::system_clock::time_point m_tFadeEnds;
Vector2D m_vLastEnterCoords = {};
std::shared_ptr<CTimer> m_pKeyRepeatTimer = nullptr;
std::vector<std::unique_ptr<COutput>> m_vOutputs;
std::vector<std::shared_ptr<CTimer>> getTimers();