fcitx5-qt/qt5/platforminputcontext/hybridinputcontext.cpp

281 lines
8.9 KiB
C++

/*
* SPDX-FileCopyrightText: 2023~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "hybridinputcontext.h"
#include "fcitx4inputcontextproxy.h"
#include "fcitxqtinputcontextproxy.h"
#include "fcitxqtwatcher.h"
#include <cstddef>
namespace fcitx {
HybridInputContext::HybridInputContext(FcitxQtWatcher *watcher,
Fcitx4Watcher *fcitx4Watcher,
QObject *parent)
: QObject(parent), watcher_(watcher), fcitx4Watcher_(fcitx4Watcher) {
// We use a timer here to avoid recheck being triggered multiple times.
// For fcitx5, the fcitx4frontend and dbusfrontend will be initialized
// around the same time. 50ms is specifically selected to be smaller than
// the 100ms timer within input context.
timer_.setInterval(50);
timer_.setSingleShot(true);
connect(&timer_, &QTimer::timeout, this,
[this]() { doRecheck(/*skipFcitx5=*/false); });
connect(watcher_, &FcitxQtWatcher::availabilityChanged, this,
&HybridInputContext::recheck);
connect(fcitx4Watcher_, &Fcitx4Watcher::availabilityChanged, this,
&HybridInputContext::recheck);
recheck();
}
void HybridInputContext::recheck() { timer_.start(); }
void HybridInputContext::doRecheck(bool skipFcitx5) {
const bool fcitx5Available = !skipFcitx5 && watcher_->availability();
if (!fcitx5Available) {
delete proxy_;
proxy_ = nullptr;
}
if (!fcitx4Watcher_->availability()) {
delete proxy4_;
proxy4_ = nullptr;
}
if (fcitx5Available) {
delete proxy4_;
proxy4_ = nullptr;
if (!proxy_) {
proxy_ = new FcitxQtInputContextProxy(watcher_, this);
proxy_->setDisplay(display_);
connect(proxy_, &FcitxQtInputContextProxy::commitString, this,
&HybridInputContext::commitString);
connect(proxy_, &FcitxQtInputContextProxy::currentIM, this,
&HybridInputContext::currentIM);
connect(proxy_, &FcitxQtInputContextProxy::deleteSurroundingText,
this, &HybridInputContext::deleteSurroundingText);
connect(proxy_, &FcitxQtInputContextProxy::forwardKey, this,
&HybridInputContext::forwardKey);
connect(proxy_, &FcitxQtInputContextProxy::updateFormattedPreedit,
this, &HybridInputContext::updateFormattedPreedit);
connect(proxy_, &FcitxQtInputContextProxy::updateClientSideUI, this,
&HybridInputContext::updateClientSideUI);
connect(proxy_, &FcitxQtInputContextProxy::inputContextCreated,
this, &HybridInputContext::inputContextCreated);
connect(proxy_,
&FcitxQtInputContextProxy::inputContextCreationFailed, this,
&HybridInputContext::inputContextCreationFailed);
connect(proxy_, &FcitxQtInputContextProxy::notifyFocusOut, this,
&HybridInputContext::notifyFocusOut);
connect(proxy_,
&FcitxQtInputContextProxy::virtualKeyboardVisibilityChanged,
this,
&HybridInputContext::virtualKeyboardVisibilityChanged);
}
} else if (fcitx4Watcher_->availability()) {
if (!proxy4_) {
proxy4_ = new Fcitx4InputContextProxy(fcitx4Watcher_, this);
connect(proxy4_, &Fcitx4InputContextProxy::commitString, this,
&HybridInputContext::commitString);
connect(proxy4_, &Fcitx4InputContextProxy::currentIM, this,
&HybridInputContext::currentIM);
connect(proxy4_, &Fcitx4InputContextProxy::deleteSurroundingText,
this, &HybridInputContext::deleteSurroundingText);
connect(proxy4_, &Fcitx4InputContextProxy::forwardKey, this,
&HybridInputContext::forwardKey);
connect(
proxy4_, &Fcitx4InputContextProxy::updateFormattedPreedit, this,
[this](const FcitxQtFormattedPreeditList &list, int cursorpos) {
auto newList = list;
for (auto item : newList) {
const qint32 underlineBit = (1 << 3);
// revert non underline and "underline"
item.setFormat(item.format() ^ underlineBit);
}
Q_EMIT updateFormattedPreedit(newList, cursorpos);
});
connect(proxy4_, &Fcitx4InputContextProxy::inputContextCreated,
this,
[this]() { Q_EMIT inputContextCreated(QByteArray()); });
}
}
}
void HybridInputContext::inputContextCreationFailed() {
doRecheck(/*skipFcitx5=*/true);
}
bool HybridInputContext::isValid() const {
if (proxy_) {
return proxy_->isValid();
} else if (proxy4_) {
return proxy4_->isValid();
}
return false;
}
void HybridInputContext::reset() {
if (proxy_) {
proxy_->reset();
} else if (proxy4_) {
proxy4_->reset();
}
}
void HybridInputContext::selectCandidate(int i) {
if (proxy_) {
proxy_->selectCandidate(i);
}
}
void HybridInputContext::prevPage() {
if (proxy_) {
proxy_->prevPage();
}
}
void HybridInputContext::nextPage() {
if (proxy_) {
proxy_->nextPage();
}
}
bool HybridInputContext::supportInvokeAction() const {
if (proxy_) {
return proxy_->supportInvokeAction();
}
return false;
}
void HybridInputContext::invokeAction(unsigned int action, int cursor) {
if (proxy_) {
proxy_->invokeAction(action, cursor);
}
}
void HybridInputContext::setSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor) {
if (proxy_) {
proxy_->setSurroundingText(text, cursor, anchor);
} else if (proxy4_) {
proxy4_->setSurroundingText(text, cursor, anchor);
}
}
void HybridInputContext::setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
if (proxy_) {
proxy_->setSurroundingTextPosition(cursor, anchor);
} else if (proxy4_) {
proxy4_->setSurroundingTextPosition(cursor, anchor);
}
}
void HybridInputContext::focusIn() {
if (proxy_) {
proxy_->focusIn();
} else if (proxy4_) {
proxy4_->focusIn();
}
}
void HybridInputContext::focusOut() {
if (proxy_) {
proxy_->focusOut();
} else if (proxy4_) {
proxy4_->focusOut();
}
}
void HybridInputContext::setCursorRectV2(int x, int y, int w, int h,
double scale) {
if (proxy_) {
proxy_->setCursorRectV2(x, y, w, h, scale);
} else if (proxy4_) {
proxy4_->setCursorRect(x, y, w, h);
}
}
void HybridInputContext::setCursorRect(int x, int y, int w, int h) {
if (proxy_) {
proxy_->setCursorRect(x, y, w, h);
} else if (proxy4_) {
proxy4_->setCursorRect(x, y, w, h);
}
}
void HybridInputContext::setSupportedCapability(quint64 supported) {
if (proxy_) {
proxy_->setSupportedCapability(supported);
}
}
void HybridInputContext::setCapability(quint64 capability) {
if (proxy_) {
proxy_->setCapability(capability);
} else if (proxy4_) {
proxy4_->setCapability(capability & 0xfffffffffULL);
}
}
void HybridInputContext::showVirtualKeyboard() {
if (proxy_) {
proxy_->showVirtualKeyboard();
}
}
void HybridInputContext::hideVirtualKeyboard() {
if (proxy_) {
proxy_->hideVirtualKeyboard();
}
}
bool HybridInputContext::isVirtualKeyboardVisible() const {
if (proxy_) {
return proxy_->isVirtualKeyboardVisible();
}
return false;
}
void HybridInputContext::setDisplay(const QString &display) {
if (proxy_) {
proxy_->setDisplay(display);
}
display_ = display;
}
QDBusPendingCall HybridInputContext::processKeyEvent(unsigned int keyval,
unsigned int keycode,
unsigned int state,
bool type,
unsigned int time) {
if (proxy_) {
return proxy_->processKeyEvent(keyval, keycode, state, type, time);
}
return proxy4_->processKeyEvent(keyval, keycode, state, type ? 1 : 0, time);
}
bool HybridInputContext::processKeyEventResult(const QDBusPendingCall &call) {
if (call.isError()) {
return false;
}
if (call.reply().signature() == "b") {
QDBusPendingReply<bool> reply = call;
return reply.value();
} else if (call.reply().signature() == "i") {
QDBusPendingReply<int> reply = call;
return reply.value() > 0;
}
return false;
}
} // namespace fcitx