animated example

This commit is contained in:
Jorijn van der Graaf 2026-05-02 00:03:24 +02:00
commit c9fd1b1585
17 changed files with 576 additions and 465 deletions

View file

@ -454,16 +454,32 @@ void Device::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t serial, ui
std::string buf;
buf.resize(16);
int n = xkb_state_key_get_utf8(xkb_state, keycode, buf.data(), 16);
if (n > 0) {
if ((unsigned char)buf[0] >= 0x20 && buf[0] != 0x7f) {
buf.resize(n);
focusedWindow->onTextInput.Invoke(buf);
}
std::string utf8;
if (n > 0 && (unsigned char)buf[0] >= 0x20 && buf[0] != 0x7f) {
buf.resize(n);
utf8 = buf;
focusedWindow->onTextInput.Invoke(utf8);
}
// Replace the active repeat with this key — most recent press wins,
// matching xkbcommon's typical behaviour and most desktop apps.
keyRepeat.active = (keyRepeat.rate > 0);
keyRepeat.key = crafterKey;
keyRepeat.utf8 = std::move(utf8);
keyRepeat.pressTime = std::chrono::steady_clock::now();
keyRepeat.lastFireTime = keyRepeat.pressTime;
} else {
focusedWindow->heldkeys[(std::uint8_t)crafterKey] = false;
focusedWindow->onKeyUp[(std::uint8_t)crafterKey].Invoke();
focusedWindow->onAnyKeyUp.Invoke(crafterKey);
// If the released key was the one repeating, stop. Otherwise leave
// the existing repeat alone (user pressed/released a modifier
// mid-repeat etc.).
if (keyRepeat.active && keyRepeat.key == crafterKey) {
keyRepeat.active = false;
keyRepeat.utf8.clear();
}
}
}
@ -472,7 +488,36 @@ void Device::keyboard_modifiers(void *data, wl_keyboard *keyboard, uint32_t seri
}
void Device::keyboard_repeat_info(void *data, wl_keyboard *keyboard, int32_t rate, int32_t delay) {
keyRepeat.rate = rate;
keyRepeat.delay = delay;
if (rate <= 0) keyRepeat.active = false; // compositor disabled repeat
}
void Device::TickKeyRepeats() {
if (!keyRepeat.active || !focusedWindow) return;
if (keyRepeat.rate <= 0) return;
auto now = std::chrono::steady_clock::now();
using ms = std::chrono::milliseconds;
auto sincePress = std::chrono::duration_cast<ms>(now - keyRepeat.pressTime).count();
if (sincePress < keyRepeat.delay) return;
auto period = std::chrono::milliseconds(1000 / keyRepeat.rate);
auto sinceLastFire = std::chrono::duration_cast<ms>(now - keyRepeat.lastFireTime).count();
if (sinceLastFire < period.count()) return;
// Catch up — emit one event per missed period so a paused frame doesn't
// make the repeat permanently lag behind.
while (now - keyRepeat.lastFireTime >= period) {
focusedWindow->onKeyDown[(std::uint8_t)keyRepeat.key].Invoke();
focusedWindow->onAnyKeyDown.Invoke(keyRepeat.key);
focusedWindow->onKeyHold[(std::uint8_t)keyRepeat.key].Invoke();
focusedWindow->onAnyKeyHold.Invoke(keyRepeat.key);
if (!keyRepeat.utf8.empty()) {
focusedWindow->onTextInput.Invoke(keyRepeat.utf8);
}
keyRepeat.lastFireTime += period;
}
}
void Device::seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities) {