/* * SPDX-FileCopyrightText: 2012~2017 CSSlayer * * SPDX-License-Identifier: BSD-3-Clause * */ #ifndef QFCITXPLATFORMINPUTCONTEXT_H #define QFCITXPLATFORMINPUTCONTEXT_H #include "fcitxcandidatewindow.h" #include "fcitxqtwatcher.h" #include "hybridinputcontext.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace fcitx { class FcitxQtConnection; class QFcitxPlatformInputContext; class FcitxQtICData : public QObject { public: FcitxQtICData(QFcitxPlatformInputContext *context, QWindow *window); FcitxQtICData(const FcitxQtICData &that) = delete; ~FcitxQtICData() override; FcitxCandidateWindow *candidateWindow(); QWindow *window() { return window_.data(); } void resetCandidateWindow(); quint64 capability = 0; HybridInputContext *proxy; QRect rect; // Last key event forwarded. std::unique_ptr event; QString surroundingText; int surroundingAnchor = -1; int surroundingCursor = -1; bool expectingMicroFocusChange = false; bool eventFilter(QObject *watched, QEvent *event) override; private: QFcitxPlatformInputContext *context_; QPointer window_; QPointer candidateWindow_; }; class ProcessKeyWatcher : public QDBusPendingCallWatcher { Q_OBJECT public: ProcessKeyWatcher(const QKeyEvent &event, QWindow *window, const QDBusPendingCall &call, QObject *parent = nullptr) : QDBusPendingCallWatcher(call, parent), event_(event.type(), event.key(), event.modifiers(), event.nativeScanCode(), event.nativeVirtualKey(), event.nativeModifiers(), event.text(), event.isAutoRepeat(), event.count()), window_(window) {} const QKeyEvent &keyEvent() { return event_; } QWindow *window() { return window_.data(); } private: QKeyEvent event_; QPointer window_; }; struct XkbContextDeleter { static inline void cleanup(struct xkb_context *pointer) { if (pointer) { xkb_context_unref(pointer); } } }; struct XkbComposeTableDeleter { static inline void cleanup(struct xkb_compose_table *pointer) { if (pointer) { xkb_compose_table_unref(pointer); } } }; struct XkbComposeStateDeleter { static inline void cleanup(struct xkb_compose_state *pointer) { if (pointer) { xkb_compose_state_unref(pointer); } } }; class QFcitxPlatformInputContext : public QPlatformInputContext { Q_OBJECT public: QFcitxPlatformInputContext(); ~QFcitxPlatformInputContext() override; bool isValid() const override; void setFocusObject(QObject *object) override; void invokeAction(QInputMethod::Action imAction, int cursorPosition) override; void reset() override; void commit() override; void update(Qt::InputMethodQueries queries) override; bool filterEvent(const QEvent *event) override; QLocale locale() const override; bool hasCapability(Capability capability) const override; void showInputPanel() override; void hideInputPanel() override; bool isInputPanelVisible() const override; auto *watcher() { return watcher_; } auto *fcitx4Watcher() { return fcitx4Watcher_; } // Use Wrapper as suffix to avoid upstream add function with same name. QObject *focusObjectWrapper() const; QWindow *focusWindowWrapper() const; QRect cursorRectangleWrapper() const; // Initialize theme object on demand. FcitxTheme *theme(); bool hasPreedit() const { return !preeditList_.isEmpty(); } public Q_SLOTS: void cursorRectChanged(); void commitString(const QString &str); void updateFormattedPreedit(const FcitxQtFormattedPreeditList &preeditList, int cursorPos); void deleteSurroundingText(int offset, unsigned int nchar); void forwardKey(unsigned int keyval, unsigned int state, bool type); void createInputContextFinished(const QByteArray &uuid); void cleanUp(); void windowDestroyed(QObject *object); void updateCurrentIM(const QString &name, const QString &uniqueName, const QString &langCode); void updateClientSideUI(const FcitxQtFormattedPreeditList &preedit, int cursorpos, const FcitxQtFormattedPreeditList &auxUp, const FcitxQtFormattedPreeditList &auxDown, const FcitxQtStringKeyValueList &candidates, int candidateIndex, int layoutHint, bool hasPrev, bool hasNext); void serverSideFocusOut(); bool commitPreedit(QPointer input = qApp->focusObject()); private Q_SLOTS: void processKeyEventFinished(QDBusPendingCallWatcher *); private: bool processCompose(unsigned int keyval, unsigned int state, bool isRelease); QKeyEvent *createKeyEvent(unsigned int keyval, unsigned int state, bool isRelease, const QKeyEvent *event); void forwardEvent(QWindow *window, const QKeyEvent &event); void addCapability(FcitxQtICData &data, quint64 capability, bool forceUpdate = false) { auto newcaps = data.capability | capability; if (data.capability != newcaps || forceUpdate) { data.capability = newcaps; updateCapability(data); } } void removeCapability(FcitxQtICData &data, quint64 capability, bool forceUpdate = false) { auto newcaps = data.capability & (~capability); if (data.capability != newcaps || forceUpdate) { data.capability = newcaps; updateCapability(data); } } void updateCapability(const FcitxQtICData &data); void createICData(QWindow *w); HybridInputContext *validIC() const; HybridInputContext *validICByWindow(QWindow *window) const; bool filterEventFallback(unsigned int keyval, unsigned int keycode, unsigned int state, bool isRelease); void updateCursorRect(); bool objectAcceptsInputMethod() const; bool shouldDisableInputMethod() const; void updateInputPanelVisible(); FcitxQtWatcher *watcher_; Fcitx4Watcher *fcitx4Watcher_; QString preedit_; QString commitPreedit_; FcitxQtFormattedPreeditList preeditList_; int cursorPos_; bool useSurroundingText_; bool syncMode_; std::unordered_map icMap_; QPointer lastWindow_; QPointer lastObject_; bool destroy_; bool virtualKeyboardVisible_; QScopedPointer xkbContext_; QScopedPointer xkbComposeTable_; QScopedPointer xkbComposeState_; QLocale locale_; FcitxTheme *theme_ = nullptr; bool inputPanelVisible_ = false; }; } // namespace fcitx #endif // QFCITXPLATFORMINPUTCONTEXT_H