Fix fcitx5-t9 * longpress auto-repeat and reset Ctl mode on focus/window change
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+91
-16
@@ -252,6 +252,28 @@ T9Engine::T9Engine(fcitx::Instance* instance)
|
||||
ic->setCursorRect(kFixedPopupRect);
|
||||
}
|
||||
});
|
||||
focusOutWatcher = instance->watchEvent(
|
||||
fcitx::EventType::InputContextFocusOut,
|
||||
fcitx::EventWatcherPhase::PreInputMethod,
|
||||
[this](fcitx::Event& event) {
|
||||
auto& icEvent = static_cast<fcitx::InputContextEvent&>(event);
|
||||
if (auto* ic = icEvent.inputContext()) {
|
||||
if (auto* state = ic->propertyFor(&factory)) {
|
||||
state->onFocusChange();
|
||||
}
|
||||
}
|
||||
});
|
||||
destroyWatcher = instance->watchEvent(
|
||||
fcitx::EventType::InputContextDestroyed,
|
||||
fcitx::EventWatcherPhase::PreInputMethod,
|
||||
[this](fcitx::Event& event) {
|
||||
auto& icEvent = static_cast<fcitx::InputContextEvent&>(event);
|
||||
if (auto* ic = icEvent.inputContext()) {
|
||||
if (auto* state = ic->propertyFor(&factory)) {
|
||||
state->onFocusChange();
|
||||
}
|
||||
}
|
||||
});
|
||||
writeStatusIndicator("[abc]");
|
||||
}
|
||||
|
||||
@@ -269,7 +291,15 @@ void T9Engine::activate(const fcitx::InputMethodEntry& entry,
|
||||
FCITX_UNUSED(entry);
|
||||
auto* ic = event.inputContext();
|
||||
auto* state = ic->propertyFor(&factory);
|
||||
state->reset();
|
||||
state->onFocusChange();
|
||||
}
|
||||
|
||||
void T9Engine::deactivate(const fcitx::InputMethodEntry& entry,
|
||||
fcitx::InputContextEvent& event) {
|
||||
FCITX_UNUSED(entry);
|
||||
auto* ic = event.inputContext();
|
||||
auto* state = ic->propertyFor(&factory);
|
||||
state->onFocusChange();
|
||||
}
|
||||
|
||||
void T9Engine::keyEvent(const fcitx::InputMethodEntry& entry,
|
||||
@@ -652,26 +682,21 @@ bool T9State::handleKeyEvent(fcitx::KeyEvent& keyEvent) {
|
||||
}
|
||||
|
||||
if (keyEvent.isRelease()) {
|
||||
cancelLongPressTimer();
|
||||
int releasedId = pressedKeyId;
|
||||
pressedKeyId = -1;
|
||||
if (isLongPressHandled) {
|
||||
isLongPressHandled = false;
|
||||
return true;
|
||||
}
|
||||
if (releasedId != keyId && releasedId != -1) {
|
||||
return true;
|
||||
}
|
||||
if (!activeItems.empty()) {
|
||||
uint64_t delayUs = (activeItems.size() > 10) ? 1800000 : 1500000;
|
||||
scheduleCommit(delayUs);
|
||||
}
|
||||
scheduleKeyRelease(keyId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Key press event
|
||||
if (releaseTimer) {
|
||||
if (pressedKeyId == keyId) {
|
||||
// Synthetic X11 auto-repeat KeyRelease+KeyPress pair while holding key
|
||||
releaseTimer.reset();
|
||||
return true;
|
||||
}
|
||||
finalizeKeyRelease(pressedKeyId);
|
||||
}
|
||||
if (pressedKeyId == keyId) {
|
||||
// Ignore X11 auto-repeat key presses while holding the same key
|
||||
// Ignore duplicate key presses while holding the same key
|
||||
return true;
|
||||
}
|
||||
pressedKeyId = keyId;
|
||||
@@ -720,6 +745,44 @@ void T9State::cancelLongPressTimer() {
|
||||
}
|
||||
}
|
||||
|
||||
void T9State::scheduleKeyRelease(int keyId) {
|
||||
if (pressedKeyId != -1 && keyId != pressedKeyId) {
|
||||
return;
|
||||
}
|
||||
if (releaseTimer) {
|
||||
releaseTimer.reset();
|
||||
}
|
||||
// X11 auto-repeat sends synthetic KeyRelease immediately followed by KeyPress.
|
||||
// Wait briefly to see if a repeat KeyPress arrives before finalizing release.
|
||||
uint64_t debounceUs = isLongPressHandled ? 80000 : 15000;
|
||||
releaseTimer = engine->instance->eventLoop().addTimeEvent(
|
||||
CLOCK_MONOTONIC, fcitx::now(CLOCK_MONOTONIC) + debounceUs, 0,
|
||||
[this, keyId](fcitx::EventSourceTime*, uint64_t) {
|
||||
finalizeKeyRelease(keyId);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void T9State::finalizeKeyRelease(int keyId) {
|
||||
if (releaseTimer) {
|
||||
releaseTimer.reset();
|
||||
}
|
||||
cancelLongPressTimer();
|
||||
int releasedId = pressedKeyId;
|
||||
pressedKeyId = -1;
|
||||
if (isLongPressHandled) {
|
||||
isLongPressHandled = false;
|
||||
return;
|
||||
}
|
||||
if (releasedId != keyId && releasedId != -1) {
|
||||
return;
|
||||
}
|
||||
if (!activeItems.empty()) {
|
||||
uint64_t delayUs = (activeItems.size() > 10) ? 1800000 : 1500000;
|
||||
scheduleCommit(delayUs);
|
||||
}
|
||||
}
|
||||
|
||||
void T9State::onLongPress(int keyId) {
|
||||
isLongPressHandled = true;
|
||||
// Discard current key's uncommitted multi-tap candidate and commit long-press action
|
||||
@@ -771,6 +834,9 @@ void T9State::handleMultiTap(int keyId) {
|
||||
}
|
||||
|
||||
void T9State::reset() {
|
||||
if (releaseTimer) {
|
||||
releaseTimer.reset();
|
||||
}
|
||||
cancelLongPressTimer();
|
||||
cancelCommit();
|
||||
if (bannerTimer) {
|
||||
@@ -786,6 +852,15 @@ void T9State::reset() {
|
||||
updateStatusBar();
|
||||
}
|
||||
|
||||
void T9State::onFocusChange() {
|
||||
if (engine->sharedMode == T9Mode::Ctrl || mode == T9Mode::Ctrl) {
|
||||
engine->sharedMode = T9Mode::Lower;
|
||||
mode = T9Mode::Lower;
|
||||
}
|
||||
ctrlLatch = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
void T9State::forwardKeyTap(fcitx::KeySym sym, fcitx::KeyStates states,
|
||||
uint32_t xkbCode) {
|
||||
if (states.test(fcitx::KeyState::Ctrl)) {
|
||||
|
||||
@@ -42,6 +42,7 @@ class T9State : public fcitx::InputContextProperty {
|
||||
bool handleKeyEvent(fcitx::KeyEvent& keyEvent);
|
||||
void cancelCommit();
|
||||
void reset();
|
||||
void onFocusChange();
|
||||
|
||||
private:
|
||||
std::vector<T9Item> getItemsForKey(int keyId) const;
|
||||
@@ -53,6 +54,8 @@ class T9State : public fcitx::InputContextProperty {
|
||||
void startLongPressTimer(int keyId);
|
||||
void cancelLongPressTimer();
|
||||
void onLongPress(int keyId);
|
||||
void scheduleKeyRelease(int keyId);
|
||||
void finalizeKeyRelease(int keyId);
|
||||
void scheduleCommit(uint64_t delayUs = 1500000);
|
||||
void commit();
|
||||
void sendItem(const T9Item& item);
|
||||
@@ -73,6 +76,7 @@ class T9State : public fcitx::InputContextProperty {
|
||||
std::vector<T9Item> activeItems;
|
||||
std::unique_ptr<fcitx::EventSourceTime> commitTimer;
|
||||
std::unique_ptr<fcitx::EventSourceTime> longPressTimer;
|
||||
std::unique_ptr<fcitx::EventSourceTime> releaseTimer;
|
||||
std::unique_ptr<fcitx::EventSourceTime> bannerTimer;
|
||||
bool isLongPressHandled = false;
|
||||
};
|
||||
@@ -83,6 +87,8 @@ class T9Engine : public fcitx::InputMethodEngineV2 {
|
||||
std::vector<fcitx::InputMethodEntry> listInputMethods() override;
|
||||
void activate(const fcitx::InputMethodEntry& entry,
|
||||
fcitx::InputContextEvent& event) override;
|
||||
void deactivate(const fcitx::InputMethodEntry& entry,
|
||||
fcitx::InputContextEvent& event) override;
|
||||
void keyEvent(const fcitx::InputMethodEntry& entry,
|
||||
fcitx::KeyEvent& keyEvent) override;
|
||||
void reset(const fcitx::InputMethodEntry& entry,
|
||||
@@ -93,6 +99,8 @@ class T9Engine : public fcitx::InputMethodEngineV2 {
|
||||
private:
|
||||
fcitx::FactoryFor<T9State> factory;
|
||||
std::unique_ptr<fcitx::HandlerTableEntry<fcitx::EventHandler>> cursorWatcher;
|
||||
std::unique_ptr<fcitx::HandlerTableEntry<fcitx::EventHandler>> focusOutWatcher;
|
||||
std::unique_ptr<fcitx::HandlerTableEntry<fcitx::EventHandler>> destroyWatcher;
|
||||
};
|
||||
|
||||
class T9EngineFactory : public fcitx::AddonFactory {
|
||||
|
||||
+4
-3
@@ -1787,12 +1787,11 @@ focus(XEvent *ev)
|
||||
{
|
||||
XFocusChangeEvent *e = &ev->xfocus;
|
||||
|
||||
if (e->mode == NotifyGrab)
|
||||
return;
|
||||
|
||||
if (ev->type == FocusIn) {
|
||||
if (xw.ime.xic)
|
||||
XSetICFocus(xw.ime.xic);
|
||||
if (e->mode == NotifyGrab)
|
||||
return;
|
||||
win.mode |= MODE_FOCUSED;
|
||||
xseturgency(0);
|
||||
if (IS_SET(MODE_FOCUS))
|
||||
@@ -1800,6 +1799,8 @@ focus(XEvent *ev)
|
||||
} else {
|
||||
if (xw.ime.xic)
|
||||
XUnsetICFocus(xw.ime.xic);
|
||||
if (e->mode == NotifyGrab)
|
||||
return;
|
||||
win.mode &= ~MODE_FOCUSED;
|
||||
if (IS_SET(MODE_FOCUS))
|
||||
ttywrite("\033[O", 3, 0);
|
||||
|
||||
Reference in New Issue
Block a user