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);
|
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]");
|
writeStatusIndicator("[abc]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +291,15 @@ void T9Engine::activate(const fcitx::InputMethodEntry& entry,
|
|||||||
FCITX_UNUSED(entry);
|
FCITX_UNUSED(entry);
|
||||||
auto* ic = event.inputContext();
|
auto* ic = event.inputContext();
|
||||||
auto* state = ic->propertyFor(&factory);
|
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,
|
void T9Engine::keyEvent(const fcitx::InputMethodEntry& entry,
|
||||||
@@ -652,26 +682,21 @@ bool T9State::handleKeyEvent(fcitx::KeyEvent& keyEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (keyEvent.isRelease()) {
|
if (keyEvent.isRelease()) {
|
||||||
cancelLongPressTimer();
|
scheduleKeyRelease(keyId);
|
||||||
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);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key press event
|
// 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) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
pressedKeyId = keyId;
|
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) {
|
void T9State::onLongPress(int keyId) {
|
||||||
isLongPressHandled = true;
|
isLongPressHandled = true;
|
||||||
// Discard current key's uncommitted multi-tap candidate and commit long-press action
|
// 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() {
|
void T9State::reset() {
|
||||||
|
if (releaseTimer) {
|
||||||
|
releaseTimer.reset();
|
||||||
|
}
|
||||||
cancelLongPressTimer();
|
cancelLongPressTimer();
|
||||||
cancelCommit();
|
cancelCommit();
|
||||||
if (bannerTimer) {
|
if (bannerTimer) {
|
||||||
@@ -786,6 +852,15 @@ void T9State::reset() {
|
|||||||
updateStatusBar();
|
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,
|
void T9State::forwardKeyTap(fcitx::KeySym sym, fcitx::KeyStates states,
|
||||||
uint32_t xkbCode) {
|
uint32_t xkbCode) {
|
||||||
if (states.test(fcitx::KeyState::Ctrl)) {
|
if (states.test(fcitx::KeyState::Ctrl)) {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class T9State : public fcitx::InputContextProperty {
|
|||||||
bool handleKeyEvent(fcitx::KeyEvent& keyEvent);
|
bool handleKeyEvent(fcitx::KeyEvent& keyEvent);
|
||||||
void cancelCommit();
|
void cancelCommit();
|
||||||
void reset();
|
void reset();
|
||||||
|
void onFocusChange();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<T9Item> getItemsForKey(int keyId) const;
|
std::vector<T9Item> getItemsForKey(int keyId) const;
|
||||||
@@ -53,6 +54,8 @@ class T9State : public fcitx::InputContextProperty {
|
|||||||
void startLongPressTimer(int keyId);
|
void startLongPressTimer(int keyId);
|
||||||
void cancelLongPressTimer();
|
void cancelLongPressTimer();
|
||||||
void onLongPress(int keyId);
|
void onLongPress(int keyId);
|
||||||
|
void scheduleKeyRelease(int keyId);
|
||||||
|
void finalizeKeyRelease(int keyId);
|
||||||
void scheduleCommit(uint64_t delayUs = 1500000);
|
void scheduleCommit(uint64_t delayUs = 1500000);
|
||||||
void commit();
|
void commit();
|
||||||
void sendItem(const T9Item& item);
|
void sendItem(const T9Item& item);
|
||||||
@@ -73,6 +76,7 @@ class T9State : public fcitx::InputContextProperty {
|
|||||||
std::vector<T9Item> activeItems;
|
std::vector<T9Item> activeItems;
|
||||||
std::unique_ptr<fcitx::EventSourceTime> commitTimer;
|
std::unique_ptr<fcitx::EventSourceTime> commitTimer;
|
||||||
std::unique_ptr<fcitx::EventSourceTime> longPressTimer;
|
std::unique_ptr<fcitx::EventSourceTime> longPressTimer;
|
||||||
|
std::unique_ptr<fcitx::EventSourceTime> releaseTimer;
|
||||||
std::unique_ptr<fcitx::EventSourceTime> bannerTimer;
|
std::unique_ptr<fcitx::EventSourceTime> bannerTimer;
|
||||||
bool isLongPressHandled = false;
|
bool isLongPressHandled = false;
|
||||||
};
|
};
|
||||||
@@ -83,6 +87,8 @@ class T9Engine : public fcitx::InputMethodEngineV2 {
|
|||||||
std::vector<fcitx::InputMethodEntry> listInputMethods() override;
|
std::vector<fcitx::InputMethodEntry> listInputMethods() override;
|
||||||
void activate(const fcitx::InputMethodEntry& entry,
|
void activate(const fcitx::InputMethodEntry& entry,
|
||||||
fcitx::InputContextEvent& event) override;
|
fcitx::InputContextEvent& event) override;
|
||||||
|
void deactivate(const fcitx::InputMethodEntry& entry,
|
||||||
|
fcitx::InputContextEvent& event) override;
|
||||||
void keyEvent(const fcitx::InputMethodEntry& entry,
|
void keyEvent(const fcitx::InputMethodEntry& entry,
|
||||||
fcitx::KeyEvent& keyEvent) override;
|
fcitx::KeyEvent& keyEvent) override;
|
||||||
void reset(const fcitx::InputMethodEntry& entry,
|
void reset(const fcitx::InputMethodEntry& entry,
|
||||||
@@ -93,6 +99,8 @@ class T9Engine : public fcitx::InputMethodEngineV2 {
|
|||||||
private:
|
private:
|
||||||
fcitx::FactoryFor<T9State> factory;
|
fcitx::FactoryFor<T9State> factory;
|
||||||
std::unique_ptr<fcitx::HandlerTableEntry<fcitx::EventHandler>> cursorWatcher;
|
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 {
|
class T9EngineFactory : public fcitx::AddonFactory {
|
||||||
|
|||||||
+4
-3
@@ -1787,12 +1787,11 @@ focus(XEvent *ev)
|
|||||||
{
|
{
|
||||||
XFocusChangeEvent *e = &ev->xfocus;
|
XFocusChangeEvent *e = &ev->xfocus;
|
||||||
|
|
||||||
if (e->mode == NotifyGrab)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ev->type == FocusIn) {
|
if (ev->type == FocusIn) {
|
||||||
if (xw.ime.xic)
|
if (xw.ime.xic)
|
||||||
XSetICFocus(xw.ime.xic);
|
XSetICFocus(xw.ime.xic);
|
||||||
|
if (e->mode == NotifyGrab)
|
||||||
|
return;
|
||||||
win.mode |= MODE_FOCUSED;
|
win.mode |= MODE_FOCUSED;
|
||||||
xseturgency(0);
|
xseturgency(0);
|
||||||
if (IS_SET(MODE_FOCUS))
|
if (IS_SET(MODE_FOCUS))
|
||||||
@@ -1800,6 +1799,8 @@ focus(XEvent *ev)
|
|||||||
} else {
|
} else {
|
||||||
if (xw.ime.xic)
|
if (xw.ime.xic)
|
||||||
XUnsetICFocus(xw.ime.xic);
|
XUnsetICFocus(xw.ime.xic);
|
||||||
|
if (e->mode == NotifyGrab)
|
||||||
|
return;
|
||||||
win.mode &= ~MODE_FOCUSED;
|
win.mode &= ~MODE_FOCUSED;
|
||||||
if (IS_SET(MODE_FOCUS))
|
if (IS_SET(MODE_FOCUS))
|
||||||
ttywrite("\033[O", 3, 0);
|
ttywrite("\033[O", 3, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user