1 /* 2 * Copyright (C) 2011~2017 by CSSlayer 3 * wengxt@gmail.com 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above Copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above Copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * 3. Neither the name of the authors nor the names of its contributors 17 * may be used to endorse or promote products derived from this 18 * software without specific prior written permission. 19 */ 20 21 #ifndef QFCITXPLATFORMINPUTCONTEXT_H 22 #define QFCITXPLATFORMINPUTCONTEXT_H 23 24 #include "fcitxinputcontextproxy.h" 25 #include "fcitxqtdbustypes.h" 26 #include "fcitxwatcher.h" 27 #include <QDBusConnection> 28 #include <QDBusServiceWatcher> 29 #include <QGuiApplication> 30 #include <QKeyEvent> 31 #include <QPointer> 32 #include <QRect> 33 #include <QWindow> 34 #include <memory> 35 #include <qpa/qplatforminputcontext.h> 36 #include <unordered_map> 37 #include <xkbcommon/xkbcommon-compose.h> 38 39 class QFileSystemWatcher; 40 enum FcitxKeyEventType { FCITX_PRESS_KEY, FCITX_RELEASE_KEY }; 41 42 enum FcitxCapabilityFlags { 43 CAPACITY_NONE = 0, 44 CAPACITY_CLIENT_SIDE_UI = (1 << 0), 45 CAPACITY_PREEDIT = (1 << 1), 46 CAPACITY_CLIENT_SIDE_CONTROL_STATE = (1 << 2), 47 CAPACITY_PASSWORD = (1 << 3), 48 CAPACITY_FORMATTED_PREEDIT = (1 << 4), 49 CAPACITY_CLIENT_UNFOCUS_COMMIT = (1 << 5), 50 CAPACITY_SURROUNDING_TEXT = (1 << 6), 51 CAPACITY_EMAIL = (1 << 7), 52 CAPACITY_DIGIT = (1 << 8), 53 CAPACITY_UPPERCASE = (1 << 9), 54 CAPACITY_LOWERCASE = (1 << 10), 55 CAPACITY_NOAUTOUPPERCASE = (1 << 11), 56 CAPACITY_URL = (1 << 12), 57 CAPACITY_DIALABLE = (1 << 13), 58 CAPACITY_NUMBER = (1 << 14), 59 CAPACITY_NO_ON_SCREEN_KEYBOARD = (1 << 15), 60 CAPACITY_SPELLCHECK = (1 << 16), 61 CAPACITY_NO_SPELLCHECK = (1 << 17), 62 CAPACITY_WORD_COMPLETION = (1 << 18), 63 CAPACITY_UPPERCASE_WORDS = (1 << 19), 64 CAPACITY_UPPERCASE_SENTENCES = (1 << 20), 65 CAPACITY_ALPHA = (1 << 21), 66 CAPACITY_NAME = (1 << 22), 67 CAPACITY_GET_IM_INFO_ON_FOCUS = (1 << 23), 68 CAPACITY_RELATIVE_CURSOR_RECT = (1 << 24), 69 }; 70 71 enum FcitxKeyState { 72 FcitxKeyState_None = 0, 73 FcitxKeyState_Shift = 1 << 0, 74 FcitxKeyState_CapsLock = 1 << 1, 75 FcitxKeyState_Ctrl = 1 << 2, 76 FcitxKeyState_Alt = 1 << 3, 77 FcitxKeyState_Alt_Shift = FcitxKeyState_Alt | FcitxKeyState_Shift, 78 FcitxKeyState_Ctrl_Shift = FcitxKeyState_Ctrl | FcitxKeyState_Shift, 79 FcitxKeyState_Ctrl_Alt = FcitxKeyState_Ctrl | FcitxKeyState_Alt, 80 FcitxKeyState_Ctrl_Alt_Shift = 81 FcitxKeyState_Ctrl | FcitxKeyState_Alt | FcitxKeyState_Shift, 82 FcitxKeyState_NumLock = 1 << 4, 83 FcitxKeyState_Super = 1 << 6, 84 FcitxKeyState_ScrollLock = 1 << 7, 85 FcitxKeyState_MousePressed = 1 << 8, 86 FcitxKeyState_HandledMask = 1 << 24, 87 FcitxKeyState_IgnoredMask = 1 << 25, 88 FcitxKeyState_Super2 = 1 << 26, 89 FcitxKeyState_Hyper = 1 << 27, 90 FcitxKeyState_Meta = 1 << 28, 91 FcitxKeyState_UsedMask = 0x5c001fff 92 }; 93 94 struct FcitxQtICData { FcitxQtICDataFcitxQtICData95 FcitxQtICData(FcitxWatcher *watcher) 96 : proxy(new FcitxInputContextProxy(watcher, watcher)), 97 surroundingAnchor(-1), surroundingCursor(-1) {} 98 FcitxQtICData(const FcitxQtICData &that) = delete; ~FcitxQtICDataFcitxQtICData99 ~FcitxQtICData() { 100 if (proxy) { 101 delete proxy; 102 } 103 } 104 QFlags<FcitxCapabilityFlags> capability; 105 FcitxInputContextProxy *proxy; 106 QRect rect; 107 // Last key event forwarded. 108 std::unique_ptr<QKeyEvent> event; 109 QString surroundingText; 110 int surroundingAnchor; 111 int surroundingCursor; 112 }; 113 114 class ProcessKeyWatcher : public QDBusPendingCallWatcher { 115 Q_OBJECT 116 public: 117 ProcessKeyWatcher(const QKeyEvent &event, QWindow *window, 118 const QDBusPendingCall &call, QObject *parent = 0) QDBusPendingCallWatcher(call,parent)119 : QDBusPendingCallWatcher(call, parent), 120 m_event(event.type(), event.key(), event.modifiers(), 121 event.nativeScanCode(), event.nativeVirtualKey(), 122 event.nativeModifiers(), event.text(), event.isAutoRepeat(), 123 event.count()), 124 m_window(window) {} 125 ~ProcessKeyWatcher()126 virtual ~ProcessKeyWatcher() {} 127 keyEvent()128 const QKeyEvent &keyEvent() { return m_event; } 129 window()130 QWindow *window() { return m_window.data(); } 131 132 private: 133 QKeyEvent m_event; 134 QPointer<QWindow> m_window; 135 }; 136 137 struct XkbContextDeleter { cleanupXkbContextDeleter138 static inline void cleanup(struct xkb_context *pointer) { 139 if (pointer) 140 xkb_context_unref(pointer); 141 } 142 }; 143 144 struct XkbComposeTableDeleter { cleanupXkbComposeTableDeleter145 static inline void cleanup(struct xkb_compose_table *pointer) { 146 if (pointer) 147 xkb_compose_table_unref(pointer); 148 } 149 }; 150 151 struct XkbComposeStateDeleter { cleanupXkbComposeStateDeleter152 static inline void cleanup(struct xkb_compose_state *pointer) { 153 if (pointer) 154 xkb_compose_state_unref(pointer); 155 } 156 }; 157 158 class FcitxQtInputMethodProxy; 159 160 class QFcitxPlatformInputContext : public QPlatformInputContext { 161 Q_OBJECT 162 public: 163 QFcitxPlatformInputContext(); 164 virtual ~QFcitxPlatformInputContext(); 165 166 virtual bool filterEvent(const QEvent *event) Q_DECL_OVERRIDE; 167 virtual bool isValid() const Q_DECL_OVERRIDE; 168 virtual void invokeAction(QInputMethod::Action, 169 int cursorPosition) Q_DECL_OVERRIDE; 170 virtual void reset() Q_DECL_OVERRIDE; 171 virtual void commit() Q_DECL_OVERRIDE; 172 virtual void update(Qt::InputMethodQueries quries) Q_DECL_OVERRIDE; 173 virtual void setFocusObject(QObject *object) Q_DECL_OVERRIDE; 174 virtual QLocale locale() const Q_DECL_OVERRIDE; 175 176 public Q_SLOTS: 177 void cursorRectChanged(); 178 void commitString(const QString &str); 179 void updateFormattedPreedit(const FcitxFormattedPreeditList &preeditList, 180 int cursorPos); 181 void deleteSurroundingText(int offset, uint nchar); 182 void forwardKey(uint keyval, uint state, bool type); 183 void createInputContextFinished(); 184 void cleanUp(); 185 void windowDestroyed(QObject *object); 186 void updateCurrentIM(const QString &name, const QString &uniqueName, 187 const QString &langCode); 188 189 private: 190 bool processCompose(uint keyval, uint state, bool isRelaese); 191 QKeyEvent *createKeyEvent(uint keyval, uint state, bool isRelaese, 192 const QKeyEvent *event); 193 void forwardEvent(QWindow *window, const QKeyEvent &event); 194 195 void addCapability(FcitxQtICData &data, 196 QFlags<FcitxCapabilityFlags> capability, 197 bool forceUpdate = false) { 198 QFlags<FcitxCapabilityFlags> newcaps = data.capability | capability; 199 if (data.capability != newcaps || forceUpdate) { 200 data.capability = newcaps; 201 updateCapability(data); 202 } 203 } 204 205 void removeCapability(FcitxQtICData &data, 206 QFlags<FcitxCapabilityFlags> capability, 207 bool forceUpdate = false) { 208 QFlags<FcitxCapabilityFlags> newcaps = data.capability & (~capability); 209 if (data.capability != newcaps || forceUpdate) { 210 data.capability = newcaps; 211 updateCapability(data); 212 } 213 } 214 215 void updateCapability(const FcitxQtICData &data); 216 void commitPreedit(QPointer<QObject> input = qApp->focusObject()); 217 void createICData(QWindow *w); 218 FcitxInputContextProxy *validIC(); 219 FcitxInputContextProxy *validICByWindow(QWindow *window); 220 bool filterEventFallback(uint keyval, uint keycode, uint state, 221 bool isRelaese); 222 223 FcitxWatcher *m_watcher; 224 QString m_preedit; 225 QString m_commitPreedit; 226 FcitxFormattedPreeditList m_preeditList; 227 int m_cursorPos; 228 bool m_useSurroundingText; 229 bool m_syncMode; 230 QString m_lastSurroundingText; 231 int m_lastSurroundingAnchor = 0; 232 int m_lastSurroundingCursor = 0; 233 std::unordered_map<QWindow *, FcitxQtICData> m_icMap; 234 QPointer<QWindow> m_lastWindow; 235 QPointer<QObject> m_lastObject; 236 bool m_destroy; 237 QScopedPointer<struct xkb_context, XkbContextDeleter> m_xkbContext; 238 QScopedPointer<struct xkb_compose_table, XkbComposeTableDeleter> 239 m_xkbComposeTable; 240 QScopedPointer<struct xkb_compose_state, XkbComposeStateDeleter> 241 m_xkbComposeState; 242 QLocale m_locale; 243 private Q_SLOTS: 244 void processKeyEventFinished(QDBusPendingCallWatcher *); 245 }; 246 247 #endif // QFCITXPLATFORMINPUTCONTEXT_H 248