Skip to content

Commit 2368446

Browse files
committed
wayland: follow keyboard focus for keys
1 parent 9ba42b5 commit 2368446

3 files changed

Lines changed: 90 additions & 14 deletions

File tree

src/core/platforms/WaylandPlatform.cpp

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,14 @@ void CWaylandPlatform::initSeat() {
365365
// keyboard focus follows what the compositor focuses, not where the pointer is. without
366366
// this a freshly opened dialog (e.g. a polkit prompt) gets no keys until the pointer
367367
// enters it, so a programmatically focused field could not be typed into.
368-
m_waylandState.keyboard->setEnter([this](CCWlKeyboard* r, uint32_t serial, wl_proxy* surf, wl_array* keys) {
369-
if (auto w = windowForSurf(surf); w)
370-
m_keyboardWindow = w;
371-
});
368+
m_waylandState.keyboard->setEnter([this](CCWlKeyboard* r, uint32_t serial, wl_proxy* surf, wl_array* keys) { onKeyboardEnter(surf, keys); });
372369

373-
m_waylandState.keyboard->setLeave([this](CCWlKeyboard* r, uint32_t serial, wl_proxy* surf) { m_keyboardWindow.reset(); });
370+
m_waylandState.keyboard->setLeave([this](CCWlKeyboard* r, uint32_t serial, wl_proxy* surf) { onKeyboardLeave(); });
374371

375-
} else if (!HAS_KEYBOARD && m_waylandState.keyboard)
372+
} else if (!HAS_KEYBOARD && m_waylandState.keyboard) {
373+
onKeyboardLeave();
376374
m_waylandState.keyboard.reset();
375+
}
377376

378377
if (HAS_POINTER && !m_waylandState.pointer) {
379378
m_waylandState.pointer = makeShared<CCWlPointer>(m_waylandState.seat->sendGetPointer());
@@ -389,12 +388,8 @@ void CWaylandPlatform::initSeat() {
389388
w->mouseEnter(local);
390389
m_currentWindow = w;
391390
m_lastEnterSerial = serial;
392-
m_currentMods = 0;
393391

394392
setCursor(HT_POINTER_ARROW);
395-
396-
m_waylandState.seatState.pressedKeys.clear();
397-
stopRepeatTimer();
398393
});
399394

400395
m_waylandState.pointer->setLeave([this](CCWlPointer* r, uint32_t serial, wl_proxy* surf) {
@@ -405,10 +400,6 @@ void CWaylandPlatform::initSeat() {
405400

406401
w->mouseLeave();
407402
m_currentWindow.reset();
408-
m_currentMods = 0;
409-
410-
m_waylandState.seatState.pressedKeys.clear();
411-
stopRepeatTimer();
412403
});
413404

414405
m_waylandState.pointer->setMotion([this](CCWlPointer* r, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
@@ -730,6 +721,37 @@ void CWaylandPlatform::onKey(uint32_t keycode, bool state) {
730721
stopRepeatTimer();
731722
}
732723

724+
void CWaylandPlatform::onKeyboardEnter(wl_proxy* surf, wl_array* keys) {
725+
resetKeyboardState();
726+
m_keyboardWindow = windowForSurf(surf);
727+
728+
if (!keys || !keys->data)
729+
return;
730+
731+
const auto KEY_COUNT = keys->size / sizeof(uint32_t);
732+
const auto KEYS = sc<const uint32_t*>(keys->data);
733+
m_waylandState.seatState.pressedKeys.assign(KEYS, KEYS + KEY_COUNT);
734+
}
735+
736+
void CWaylandPlatform::onKeyboardLeave() {
737+
m_keyboardWindow.reset();
738+
resetKeyboardState();
739+
}
740+
741+
void CWaylandPlatform::resetKeyboardState() {
742+
stopRepeatTimer();
743+
744+
m_waylandState.seatState.pressedKeys.clear();
745+
m_waylandState.seatState.repeatKeyEvent = {.down = false};
746+
m_waylandState.seatState.currentLayer = 0;
747+
m_currentMods = 0;
748+
749+
if (m_waylandState.seatState.xkbState)
750+
xkb_state_update_mask(m_waylandState.seatState.xkbState, 0, 0, 0, 0, 0, 0);
751+
if (m_waylandState.seatState.xkbComposeState)
752+
xkb_compose_state_reset(m_waylandState.seatState.xkbComposeState);
753+
}
754+
733755
void CWaylandPlatform::onRepeatTimerFire() {
734756
if (!m_keyboardWindow)
735757
return;

src/core/platforms/WaylandPlatform.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ namespace Hyprtoolkit {
6262
WP<CWaylandOutput> outputForHandle(uint32_t handle);
6363

6464
void onKey(uint32_t keycode, bool state);
65+
void onKeyboardEnter(wl_proxy* surf, wl_array* keys);
66+
void onKeyboardLeave();
67+
void resetKeyboardState();
6568
void startRepeatTimer();
6669
void stopRepeatTimer();
6770

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <array>
4+
5+
#include <core/platforms/WaylandPlatform.hpp>
6+
#include <xkbcommon/xkbcommon-keysyms.h>
7+
8+
using namespace Hyprtoolkit;
9+
10+
TEST(WaylandPlatform, keyboardEnterReplacesPressedKeys) {
11+
CWaylandPlatform platform;
12+
13+
platform.m_waylandState.seatState.pressedKeys = {1, 2, 3};
14+
platform.m_waylandState.seatState.currentLayer = 2;
15+
platform.m_currentMods = Input::HT_MODIFIER_CTRL;
16+
17+
std::array<uint32_t, 2> keysData = {28, 42};
18+
wl_array keys = {
19+
.size = keysData.size() * sizeof(uint32_t),
20+
.alloc = keysData.size() * sizeof(uint32_t),
21+
.data = keysData.data(),
22+
};
23+
24+
platform.onKeyboardEnter(nullptr, &keys);
25+
26+
EXPECT_EQ(platform.m_waylandState.seatState.pressedKeys, std::vector<uint32_t>({28, 42}));
27+
EXPECT_EQ(platform.m_waylandState.seatState.currentLayer, 0);
28+
EXPECT_EQ(platform.m_currentMods, 0);
29+
}
30+
31+
TEST(WaylandPlatform, keyboardLeaveClearsKeyboardState) {
32+
CWaylandPlatform platform;
33+
34+
platform.m_waylandState.seatState.pressedKeys = {28};
35+
platform.m_waylandState.seatState.currentLayer = 2;
36+
platform.m_waylandState.seatState.repeatKeyEvent = {
37+
.xkbKeysym = XKB_KEY_Return,
38+
.down = true,
39+
.repeat = true,
40+
};
41+
platform.m_currentMods = Input::HT_MODIFIER_SHIFT;
42+
43+
platform.onKeyboardLeave();
44+
45+
EXPECT_TRUE(platform.m_waylandState.seatState.pressedKeys.empty());
46+
EXPECT_EQ(platform.m_waylandState.seatState.currentLayer, 0);
47+
EXPECT_FALSE(platform.m_waylandState.seatState.repeatKeyEvent.down);
48+
EXPECT_FALSE(platform.m_waylandState.seatState.repeatKeyEvent.repeat);
49+
EXPECT_EQ(platform.m_waylandState.seatState.repeatKeyEvent.xkbKeysym, 0);
50+
EXPECT_EQ(platform.m_currentMods, 0);
51+
}

0 commit comments

Comments
 (0)