Skip to content

Commit 10d15ee

Browse files
committed
Allow fallback to repeat info from wl_keyboard of wl_seat.
none of kwin/weston wl_keyboard from keyboard grab send over repeat infomation, thus under kwin, the fcitx internal default value (40,400) is used, which doesn't match the default value used on most system. However, we can still read the repeat information from the actual wl_keyboard. Add repeatInfo to allow us to query repeat info for a seat so we can use the actual repeat information from compositor.
1 parent 9d3b0e7 commit 10d15ee

File tree

10 files changed

+157
-30
lines changed

10 files changed

+157
-30
lines changed

src/frontend/waylandim/waylandim.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ FCITX_CONFIGURATION(
3131
_("Forward key event instead of commiting text if it is not handled"),
3232
true};);
3333

34-
constexpr int32_t repeatHackDelay = 1000;
34+
constexpr int32_t repeatHackDelay = 3000;
3535
class WaylandIMServer;
3636
class WaylandIMServerV2;
3737

src/frontend/waylandim/waylandimserver.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66
*/
77
#include "waylandimserver.h"
88
#include <sys/mman.h>
9+
#include <algorithm>
910
#include <memory>
1011
#include "fcitx-utils/macros.h"
1112
#include "fcitx-utils/utf8.h"
1213
#include "virtualinputcontext.h"
1314
#include "wayland-text-input-unstable-v1-client-protocol.h"
15+
#include "wayland_public.h"
1416
#include "waylandim.h"
17+
#include "wl_seat.h"
1518

1619
#ifdef __linux__
1720
#include <linux/input-event-codes.h>
@@ -121,7 +124,7 @@ WaylandIMInputContextV1::WaylandIMInputContextV1(
121124
InputContextManager &inputContextManager, WaylandIMServer *server)
122125
: VirtualInputContextGlue(inputContextManager), server_(server) {
123126
timeEvent_ = server_->instance()->eventLoop().addTimeEvent(
124-
CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
127+
CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 1,
125128
[this](EventSourceTime *, uint64_t) {
126129
repeat();
127130
return true;
@@ -174,7 +177,6 @@ void WaylandIMInputContextV1::activate(wayland::ZwpInputMethodContextV1 *ic) {
174177
keyboard_->repeatInfo().connect([this](int32_t rate, int32_t delay) {
175178
repeatInfoCallback(rate, delay);
176179
});
177-
repeatInfoCallback(repeatRate_, repeatDelay_);
178180
wl_array array;
179181
wl_array_init(&array);
180182
constexpr char data[] = "Shift\0Control\0Mod1\0Mod4";
@@ -193,6 +195,7 @@ void WaylandIMInputContextV1::deactivate(wayland::ZwpInputMethodContextV1 *ic) {
193195
if (ic_.get() == ic) {
194196
ic_.reset();
195197
keyboard_.reset();
198+
repeatInfo_.reset();
196199
// This is the only place we update wayland display mask, so it is ok to
197200
// reset it to 0. This breaks the caps lock or num lock. But we have no
198201
// other option until we can listen to the mod change globally.
@@ -222,7 +225,7 @@ void WaylandIMInputContextV1::repeat() {
222225
sendKeyToVK(repeatTime_, event.rawKey(), WL_KEYBOARD_KEY_STATE_PRESSED);
223226
}
224227

225-
uint64_t interval = 1000000 / repeatRate_;
228+
uint64_t interval = 1000000 / repeatRate();
226229
timeEvent_->setTime(timeEvent_->time() + interval);
227230
timeEvent_->setOneShot();
228231
}
@@ -460,13 +463,14 @@ void WaylandIMInputContextV1::keyCallback(uint32_t serial, uint32_t time,
460463
timeEvent_->setEnabled(false);
461464
} else if (state == WL_KEYBOARD_KEY_STATE_PRESSED &&
462465
xkb_keymap_key_repeats(server_->keymap_.get(), code)) {
463-
if (repeatRate_) {
466+
if (repeatRate() > 0) {
464467
repeatKey_ = key;
465468
repeatTime_ = time;
466469
repeatSym_ = event.rawKey().sym();
467470
// Let's trick the key event system by fake our first.
468471
// Remove 100 from the initial interval.
469-
timeEvent_->setNextInterval(repeatDelay_ * 1000 - repeatHackDelay);
472+
timeEvent_->setNextInterval(std::max(
473+
0, std::max(0, repeatDelay() * 1000 - repeatHackDelay)));
470474
timeEvent_->setOneShot();
471475
}
472476
}
@@ -486,7 +490,7 @@ void WaylandIMInputContextV1::keyCallback(uint32_t serial, uint32_t time,
486490
WAYLANDIM_DEBUG() << "Engine handling speed can not keep up with key "
487491
"repetition rate.";
488492
timeEvent_->setNextInterval(
489-
std::min(1000, repeatDelay_ * 1000 - repeatHackDelay));
493+
std::clamp(0, repeatDelay() * 1000 - repeatHackDelay, 1000));
490494
}
491495
}
492496
void WaylandIMInputContextV1::modifiersCallback(uint32_t serial,
@@ -544,9 +548,10 @@ void WaylandIMInputContextV1::modifiersCallback(uint32_t serial,
544548
}
545549
}
546550

551+
// This is not sent by either kwin/weston, but since it's unclear whether any
552+
// one would send it, so keep it as is.
547553
void WaylandIMInputContextV1::repeatInfoCallback(int32_t rate, int32_t delay) {
548-
repeatRate_ = rate;
549-
repeatDelay_ = delay;
554+
repeatInfo_ = std::make_tuple(rate, delay);
550555
}
551556

552557
void WaylandIMInputContextV1::sendKey(uint32_t time, uint32_t sym,
@@ -626,4 +631,13 @@ void WaylandIMInputContextV1::deleteSurroundingTextDelegate(
626631
ic_->deleteSurroundingText(startBytes - cursorBytes, sizeBytes);
627632
ic_->commitString(serial_, "");
628633
}
634+
635+
int32_t WaylandIMInputContextV1::repeatRate() const {
636+
return server_->repeatRate(nullptr, repeatInfo_);
637+
}
638+
639+
int32_t WaylandIMInputContextV1::repeatDelay() const {
640+
return server_->repeatDelay(nullptr, repeatInfo_);
641+
}
642+
629643
} // namespace fcitx

src/frontend/waylandim/waylandimserver.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "fcitx-utils/key.h"
1313
#include "fcitx-utils/keysymgen.h"
1414
#include "fcitx-utils/macros.h"
15+
#include "fcitx-utils/signals.h"
1516
#include "virtualinputcontext.h"
1617
#include "waylandimserverbase.h"
1718
#include "wl_keyboard.h"
@@ -152,6 +153,9 @@ class WaylandIMInputContextV1 : public VirtualInputContextGlue {
152153
return modifiers;
153154
}
154155

156+
int32_t repeatRate() const;
157+
int32_t repeatDelay() const;
158+
155159
WaylandIMServer *server_;
156160
std::unique_ptr<wayland::ZwpInputMethodContextV1> ic_;
157161
std::unique_ptr<wayland::WlKeyboard> keyboard_;
@@ -164,7 +168,7 @@ class WaylandIMInputContextV1 : public VirtualInputContextGlue {
164168
uint32_t repeatTime_ = 0;
165169
KeySym repeatSym_ = FcitxKey_None;
166170

167-
int32_t repeatRate_ = 40, repeatDelay_ = 400;
171+
std::optional<std::tuple<int32_t, int32_t>> repeatInfo_;
168172
};
169173

170174
} // namespace fcitx

src/frontend/waylandim/waylandimserverbase.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
#include <optional>
99
#include <string>
1010
#include <wayland-client-core.h>
11-
#include "fcitx-utils/event.h"
1211
#include "fcitx-utils/utf8.h"
1312
#include "waylandim.h"
13+
#include "wl_seat.h"
1414

1515
namespace fcitx {
1616

1717
WaylandIMServerBase::WaylandIMServerBase(wl_display *display, FocusGroup *group,
18-
const std::string &name,
18+
std::string name,
1919
WaylandIMModule *waylandim)
20-
: group_(group), name_(name), parent_(waylandim),
20+
: group_(group), name_(std::move(name)), parent_(waylandim),
2121
display_(
2222
static_cast<wayland::Display *>(wl_display_get_user_data(display))) {}
2323

@@ -37,4 +37,42 @@ WaylandIMServerBase::mayCommitAsText(const Key &key, uint32_t state) const {
3737
return std::nullopt;
3838
}
3939

40+
std::optional<std::tuple<int32_t, int32_t>> WaylandIMServerBase::repeatInfo(
41+
const std::shared_ptr<wayland::WlSeat> &seat,
42+
const std::optional<std::tuple<int32_t, int32_t>> &defaultValue) const {
43+
if (defaultValue) {
44+
return defaultValue;
45+
}
46+
auto seatPtr = seat;
47+
if (!seatPtr) {
48+
seatPtr = display_->getGlobal<wayland::WlSeat>();
49+
}
50+
if (seatPtr) {
51+
auto repeatInfo = parent_->wayland()->call<IWaylandModule::repeatInfo>(
52+
name_, *seatPtr);
53+
if (repeatInfo) {
54+
return repeatInfo;
55+
}
56+
}
57+
return std::nullopt;
58+
}
59+
60+
int32_t WaylandIMServerBase::repeatRate(
61+
const std::shared_ptr<wayland::WlSeat> &seat,
62+
const std::optional<std::tuple<int32_t, int32_t>> &defaultValue) const {
63+
if (auto info = repeatInfo(seat, defaultValue)) {
64+
return std::get<0>(info.value());
65+
}
66+
return 25;
67+
}
68+
69+
int32_t WaylandIMServerBase::repeatDelay(
70+
const std::shared_ptr<wayland::WlSeat> &seat,
71+
const std::optional<std::tuple<int32_t, int32_t>> &defaultValue) const {
72+
if (auto info = repeatInfo(seat, defaultValue)) {
73+
return std::get<1>(info.value());
74+
}
75+
return 600;
76+
}
77+
4078
} // namespace fcitx

src/frontend/waylandim/waylandimserverbase.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,29 @@
1212
#include "fcitx-utils/misc.h"
1313
#include "display.h"
1414
#include "waylandim.h"
15+
#include "wl_seat.h"
1516

1617
namespace fcitx {
1718

1819
class WaylandIMServerBase {
1920
public:
2021
WaylandIMServerBase(wl_display *display, FocusGroup *group,
21-
const std::string &name, WaylandIMModule *waylandim);
22+
std::string name, WaylandIMModule *waylandim);
2223
virtual ~WaylandIMServerBase() = default;
2324

2425
auto *parent() { return parent_; }
26+
auto *display() { return display_; }
2527

2628
std::optional<std::string> mayCommitAsText(const Key &key,
2729
uint32_t state) const;
2830

31+
int32_t repeatRate(
32+
const std::shared_ptr<wayland::WlSeat> &seat,
33+
const std::optional<std::tuple<int32_t, int32_t>> &defaultValue) const;
34+
int32_t repeatDelay(
35+
const std::shared_ptr<wayland::WlSeat> &seat,
36+
const std::optional<std::tuple<int32_t, int32_t>> &defaultValue) const;
37+
2938
protected:
3039
FocusGroup *group_;
3140
std::string name_;
@@ -37,6 +46,11 @@ class WaylandIMServerBase {
3746
UniqueCPtr<struct xkb_state, xkb_state_unref> state_;
3847

3948
KeyStates modifiers_;
49+
50+
private:
51+
std::optional<std::tuple<int32_t, int32_t>> repeatInfo(
52+
const std::shared_ptr<wayland::WlSeat> &seat,
53+
const std::optional<std::tuple<int32_t, int32_t>> &defaultValue) const;
4054
};
4155

4256
} // namespace fcitx

src/frontend/waylandim/waylandimserverv2.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
#include "waylandimserverv2.h"
88
#include <sys/mman.h>
9+
#include <ctime>
910
#include "fcitx-utils/keysymgen.h"
1011
#include "fcitx-utils/unixfd.h"
1112
#include "fcitx-utils/utf8.h"
@@ -143,6 +144,7 @@ WaylandIMInputContextV2::WaylandIMInputContextV2(
143144
if (pendingDeactivate_) {
144145
pendingDeactivate_ = false;
145146
keyboardGrab_.reset();
147+
repeatInfo_.reset();
146148
// This is the only place we update wayland xkb mask, so it is ok to
147149
// reset it to 0. This breaks the caps lock or num lock. But we have
148150
// no other option until we can listen to the mod change globally.
@@ -202,7 +204,6 @@ WaylandIMInputContextV2::WaylandIMInputContextV2(
202204
[this](int32_t rate, int32_t delay) {
203205
repeatInfoCallback(rate, delay);
204206
});
205-
repeatInfoCallback(repeatRate_, repeatDelay_);
206207
focusInWrapper();
207208
}
208209
}
@@ -216,7 +217,7 @@ WaylandIMInputContextV2::WaylandIMInputContextV2(
216217
});
217218
ic_->unavailable().connect([]() { WAYLANDIM_DEBUG() << "UNAVAILABLE"; });
218219
timeEvent_ = server_->instance()->eventLoop().addTimeEvent(
219-
CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
220+
CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 1,
220221
[this](EventSourceTime *, uint64_t) {
221222
repeat();
222223
return true;
@@ -249,7 +250,7 @@ void WaylandIMInputContextV2::repeat() {
249250
if (!ic->keyEvent(event)) {
250251
sendKeyToVK(repeatTime_, event.rawKey(), WL_KEYBOARD_KEY_STATE_PRESSED);
251252
}
252-
uint64_t interval = 1000000 / repeatRate_;
253+
uint64_t interval = 1000000 / repeatRate();
253254
timeEvent_->setTime(timeEvent_->time() + interval);
254255
timeEvent_->setOneShot();
255256
}
@@ -457,13 +458,13 @@ void WaylandIMInputContextV2::keyCallback(uint32_t serial, uint32_t time,
457458
timeEvent_->setEnabled(false);
458459
} else if (state == WL_KEYBOARD_KEY_STATE_PRESSED &&
459460
xkb_keymap_key_repeats(server_->keymap_.get(), code)) {
460-
if (repeatRate_) {
461+
if (repeatRate() > 0) {
461462
repeatKey_ = key;
462463
repeatTime_ = time;
463464
repeatSym_ = event.rawKey().sym();
464465
// Let's trick the key event system by fake our first.
465466
// Remove 100 from the initial interval.
466-
timeEvent_->setNextInterval(repeatDelay_ * 1000 - repeatHackDelay);
467+
timeEvent_->setNextInterval(repeatDelay() * 1000 - repeatHackDelay);
467468
timeEvent_->setOneShot();
468469
}
469470
}
@@ -485,7 +486,7 @@ void WaylandIMInputContextV2::keyCallback(uint32_t serial, uint32_t time,
485486
WAYLANDIM_DEBUG() << "Engine handling speed can not keep up with key "
486487
"repetition rate.";
487488
timeEvent_->setNextInterval(
488-
std::min(1000, repeatDelay_ * 1000 - repeatHackDelay));
489+
std::clamp(0, repeatDelay() * 1000 - repeatHackDelay, 1000));
489490
}
490491
}
491492
void WaylandIMInputContextV2::modifiersCallback(uint32_t /*serial*/,
@@ -539,8 +540,7 @@ void WaylandIMInputContextV2::modifiersCallback(uint32_t /*serial*/,
539540
}
540541

541542
void WaylandIMInputContextV2::repeatInfoCallback(int32_t rate, int32_t delay) {
542-
repeatRate_ = rate;
543-
repeatDelay_ = delay;
543+
repeatInfo_ = std::make_tuple(rate, delay);
544544
}
545545

546546
void WaylandIMInputContextV2::sendKeyToVK(uint32_t time, const Key &key,
@@ -672,4 +672,13 @@ void WaylandIMInputContextV2::deleteSurroundingTextDelegate(
672672
startBytes + sizeBytes - cursorBytes);
673673
ic_->commit(serial_);
674674
}
675+
676+
int32_t WaylandIMInputContextV2::repeatRate() const {
677+
return server_->repeatRate(seat_, repeatInfo_);
678+
}
679+
680+
int32_t WaylandIMInputContextV2::repeatDelay() const {
681+
return server_->repeatDelay(seat_, repeatInfo_);
682+
}
683+
675684
} // namespace fcitx

src/frontend/waylandim/waylandimserverv2.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ class WaylandIMInputContextV2 : public VirtualInputContextGlue {
115115
void repeatInfoCallback(int32_t rate, int32_t delay);
116116
void sendKeyToVK(uint32_t time, const Key &key, uint32_t state) const;
117117

118+
int32_t repeatRate() const;
119+
int32_t repeatDelay() const;
120+
118121
WaylandIMServerV2 *server_;
119122
std::shared_ptr<wayland::WlSeat> seat_;
120123
std::unique_ptr<wayland::ZwpInputMethodV2> ic_;
@@ -134,7 +137,7 @@ class WaylandIMInputContextV2 : public VirtualInputContextGlue {
134137
uint32_t repeatTime_ = 0;
135138
KeySym repeatSym_ = FcitxKey_None;
136139

137-
int32_t repeatRate_ = 40, repeatDelay_ = 400;
140+
std::optional<std::tuple<int32_t, int32_t>> repeatInfo_;
138141

139142
mutable OrderedMap<uint32_t, uint32_t> pressedVKKey_;
140143
};

src/modules/wayland/wayland_public.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313
#include <fcitx-utils/metastring.h>
1414
#include <fcitx/addoninstance.h>
1515
#include <fcitx/focusgroup.h>
16+
#include <wayland-client-protocol.h>
1617
#include <wayland-client.h>
1718

1819
namespace fcitx {
1920

20-
typedef std::function<void(const std::string &name, wl_display *display,
21-
FocusGroup *group)>
22-
WaylandConnectionCreated;
23-
typedef std::function<void(const std::string &name, wl_display *display)>
24-
WaylandConnectionClosed;
21+
using WaylandConnectionCreated =
22+
std::function<void(const std::string &, wl_display *, FocusGroup *)>;
23+
using WaylandConnectionClosed =
24+
std::function<void(const std::string &, wl_display *)>;
2525
} // namespace fcitx
2626

2727
FCITX_ADDON_DECLARE_FUNCTION(
@@ -38,5 +38,8 @@ FCITX_ADDON_DECLARE_FUNCTION(WaylandModule, openConnection,
3838
FCITX_ADDON_DECLARE_FUNCTION(WaylandModule, openConnectionSocket, bool(int fd));
3939
FCITX_ADDON_DECLARE_FUNCTION(WaylandModule, reopenConnectionSocket,
4040
bool(const std::string &name, int fd));
41+
FCITX_ADDON_DECLARE_FUNCTION(WaylandModule, repeatInfo,
42+
std::optional<std::tuple<int32_t, int32_t>>(
43+
const std::string &name, wl_seat *));
4144

4245
#endif // _FCITX_MODULES_WAYLAND_WAYLAND_PUBLIC_H_

0 commit comments

Comments
 (0)