1 /* 2 * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com> 3 * 4 * SPDX-License-Identifier: LGPL-2.1-or-later 5 * 6 */ 7 #ifndef _FCITX_EVENT_H_ 8 #define _FCITX_EVENT_H_ 9 10 #include <stdint.h> 11 #include <fcitx-utils/capabilityflags.h> 12 #include <fcitx-utils/key.h> 13 #include <fcitx/userinterface.h> 14 #include "fcitxcore_export.h" 15 16 namespace fcitx { 17 18 class InputContext; 19 class FocusGroup; 20 21 enum class ResetReason { 22 ChangeByInactivate FCITXCORE_DEPRECATED, 23 LostFocus FCITXCORE_DEPRECATED, 24 SwitchIM FCITXCORE_DEPRECATED, 25 Client 26 }; 27 28 /** 29 * The reason why input method is switched to another. 30 */ 31 enum class InputMethodSwitchedReason { 32 /// Switched by trigger key 33 Trigger, 34 /// Switched by deactivate key 35 Deactivate, 36 /// Switched by alternative trigger key 37 AltTrigger, 38 /// Switched by activate key 39 Activate, 40 /// Switched by enumerate key 41 Enumerate, 42 /// Switched by group change 43 GroupChange, 44 /// Switched by capability change (e.g. password field) 45 CapabilityChanged, 46 /// miscellaneous reason 47 Other, 48 }; 49 50 /** 51 * Type of input method events. 52 */ 53 enum class EventType : uint32_t { 54 EventTypeFlag = 0xffff0000, 55 UserTypeFlag = 0xffff0000, 56 // send by frontend, captured by core, input method, or module 57 InputContextEventFlag = 0x0001000, 58 // send by im, captured by frontend, or module 59 InputMethodEventFlag = 0x0002000, 60 61 /** 62 * captured by everything 63 */ 64 InstanceEventFlag = 0x0003000, 65 InputContextCreated = InputContextEventFlag | 0x1, 66 InputContextDestroyed = InputContextEventFlag | 0x2, 67 /** 68 * FocusInEvent is generated when client gets focused. 69 * 70 * @see FocusInEvent 71 */ 72 InputContextFocusIn = InputContextEventFlag | 0x3, 73 /** 74 * when using lost focus 75 * this might be variance case to case. the default behavior is to commit 76 * the preedit, and resetIM. 77 * 78 * Controlled by [Output/DontCommitPreeditWhenUnfocus], this option will not 79 * work for application switch doesn't support async commit. 80 * 81 * So OnClose is called when preedit IS committed (not like 82 * CChangeByInactivate, 83 * this behavior cannot be overrided), it give im a chance to choose 84 * remember this 85 * word or not. 86 * 87 * Input method need to notice, that the commit is already DONE, do not do 88 * extra commit. 89 * 90 * @see FocusOutEvent 91 */ 92 InputContextFocusOut = InputContextEventFlag | 0x4, 93 /** 94 * Key event is generated when client press or release a key. 95 * @see KeyEvent 96 */ 97 InputContextKeyEvent = InputContextEventFlag | 0x5, 98 /** 99 * ResetEvent is generated 100 * 101 */ 102 InputContextReset = InputContextEventFlag | 0x6, 103 InputContextSurroundingTextUpdated = InputContextEventFlag | 0x7, 104 InputContextCapabilityChanged = InputContextEventFlag | 0x8, 105 InputContextCursorRectChanged = InputContextEventFlag | 0x9, 106 InputContextCapabilityAboutToChange = InputContextEventFlag | 0xD, 107 /** 108 * when user switch to a different input method by hand 109 * such as ctrl+shift by default, or by ui, 110 * default behavior is reset IM. 111 */ 112 InputContextSwitchInputMethod = InputContextEventFlag | 0xA, 113 114 // Two convenient event after input method is actually activate and 115 // deactivated. Useful for UI to update after specific input method get 116 // activated and deactivated. Will not be emitted if the input method is not 117 // a valid one. 118 InputContextInputMethodActivated = InputContextEventFlag | 0xB, 119 InputContextInputMethodDeactivated = InputContextEventFlag | 0xC, 120 /** 121 * InvokeAction event is generated when client click on the preedit. 122 * 123 * Not all client support this feature. 124 * 125 * @since 5.0.11 126 */ 127 InputContextInvokeAction = InputContextEventFlag | 0xE, 128 129 InputContextForwardKey = InputMethodEventFlag | 0x1, 130 InputContextCommitString = InputMethodEventFlag | 0x2, 131 InputContextDeleteSurroundingText = InputMethodEventFlag | 0x3, 132 InputContextUpdatePreedit = InputMethodEventFlag | 0x4, 133 InputContextUpdateUI = InputMethodEventFlag | 0x5, 134 135 /** 136 * This is generated when input method group changed. 137 * This would also trigger InputContextSwitchInputMethod afterwards. 138 */ 139 InputMethodGroupChanged = InstanceEventFlag | 0x1, 140 /** 141 * InputMethodGroupAboutToChangeEvent is generated when input method group 142 * is about to bed changed. 143 * 144 * @see InputMethodGroupAboutToChange 145 */ 146 InputMethodGroupAboutToChange = InstanceEventFlag | 0x2, 147 /** 148 * UIChangedEvent is posted when the UI implementation is changed. 149 */ 150 UIChanged = InstanceEventFlag | 0x3, 151 /** 152 * CheckUpdateEvent is posted when the Instance is requested to check for 153 * newly installed addons and input methods. 154 * 155 * This can be used for addons to pick up new input methods if it provides 156 * input method at runtime. 157 */ 158 CheckUpdate = InstanceEventFlag | 0x4, 159 /** 160 * FocusGroupFocusChanged is posted when a focus group changed its focused 161 * input context. 162 * 163 * This is a more fine grained control over focus in and focus out event. 164 * This is more useful for UI to keep track of what input context is being 165 * focused. 166 * 167 * @see FocusInEvent 168 * @see FocusOutEvent 169 */ 170 FocusGroupFocusChanged = InstanceEventFlag | 0x5, 171 }; 172 173 /** 174 * Base class for fcitx event. 175 */ 176 class FCITXCORE_EXPORT Event { 177 public: Event(EventType type)178 Event(EventType type) : type_(type) {} 179 virtual ~Event(); 180 181 /** 182 * Type of event, can be used to decide event class. 183 * 184 * @return fcitx::EventType 185 */ type()186 EventType type() const { return type_; } 187 accept()188 void accept() { accepted_ = true; } 189 /** 190 * Return value used by Instance::postEvent. 191 * 192 * @see Instance::postEvent 193 * @return bool 194 */ accepted()195 bool accepted() const { return accepted_; } 196 197 /** 198 * Whether a event is filtered by handler. 199 * 200 * If event is filtered, it will not send to another handler. 201 * For now only keyevent from input context can be filtered. 202 * 203 * @return bool 204 */ filtered()205 virtual bool filtered() const { return false; } 206 207 /** 208 * A helper function to check if a event is input context event. 209 * 210 * @return bool 211 */ isInputContextEvent()212 bool isInputContextEvent() const { 213 auto flag = static_cast<uint32_t>(EventType::InputContextEventFlag); 214 return (static_cast<uint32_t>(type_) & flag) == flag; 215 } 216 217 protected: 218 EventType type_; 219 bool accepted_ = false; 220 }; 221 222 class FCITXCORE_EXPORT InputContextEvent : public Event { 223 public: InputContextEvent(InputContext * context,EventType type)224 InputContextEvent(InputContext *context, EventType type) 225 : Event(type), ic_(context) {} 226 inputContext()227 InputContext *inputContext() const { return ic_; } 228 229 protected: 230 InputContext *ic_; 231 }; 232 233 class FCITXCORE_EXPORT KeyEventBase : public InputContextEvent { 234 public: 235 KeyEventBase(EventType type, InputContext *context, Key rawKey, 236 bool isRelease = false, int time = 0); 237 KeyEventBase(const KeyEventBase &) = default; 238 239 /** 240 * Normalized key event. 241 * 242 * @return fcitx::Key 243 */ key()244 Key key() const { return key_; } 245 246 /** 247 * It will automatically be called if input method layout does not match the 248 * system keyboard layout. 249 * 250 * @param key p_key:... 251 */ setKey(const Key & key)252 void setKey(const Key &key) { 253 key_ = key; 254 forward_ = true; 255 } 256 257 /** 258 * It is designed for faking the key event. Normally should not be used. 259 * 260 * @param key key event to override. 261 * @since 5.0.4 262 */ setRawKey(const Key & key)263 void setRawKey(const Key &key) { 264 rawKey_ = key; 265 key_ = key.normalize(); 266 forward_ = true; 267 } 268 269 /** 270 * It is designed for overriding the key forward option. Normally should not 271 * be used. 272 * 273 * @param forward 274 * @since 5.0.4 275 */ setForward(bool forward)276 void setForward(bool forward) { forward_ = forward; } 277 278 /** 279 * Key event regardless of keyboard layout conversion. 280 * 281 * @return fcitx::Key 282 */ origKey()283 Key origKey() const { return origKey_; } 284 285 /** 286 * Key event after layout conversion. 287 * 288 * Basically it is the "unnormalized" key event. 289 * 290 * @return fcitx::Key 291 */ rawKey()292 Key rawKey() const { return rawKey_; } isRelease()293 bool isRelease() const { return isRelease_; } time()294 int time() const { return time_; } 295 296 /** 297 * If true, the key that produce character will commit a string. 298 * 299 * This is currently used by internal keyboard layout translation. 300 * 301 * @return bool 302 */ forward()303 bool forward() const { return forward_; } 304 305 protected: 306 Key key_, origKey_, rawKey_; 307 bool isRelease_; 308 int time_; 309 bool forward_ = false; 310 }; 311 312 class FCITXCORE_EXPORT KeyEvent : public KeyEventBase { 313 public: 314 KeyEvent(InputContext *context, Key rawKey, bool isRelease = false, 315 int time = 0) KeyEventBase(EventType::InputContextKeyEvent,context,rawKey,isRelease,time)316 : KeyEventBase(EventType::InputContextKeyEvent, context, rawKey, 317 isRelease, time) {} 318 filter()319 void filter() { filtered_ = true; } filtered()320 bool filtered() const override { return filtered_; } filterAndAccept()321 void filterAndAccept() { 322 filter(); 323 accept(); 324 } 325 326 private: 327 bool filtered_ = false; 328 }; 329 330 class FCITXCORE_EXPORT ForwardKeyEvent : public KeyEventBase { 331 public: 332 ForwardKeyEvent(InputContext *context, Key rawKey, bool isRelease = false, 333 int time = 0) KeyEventBase(EventType::InputContextForwardKey,context,rawKey,isRelease,time)334 : KeyEventBase(EventType::InputContextForwardKey, context, rawKey, 335 isRelease, time) {} 336 }; 337 338 class FCITXCORE_EXPORT CommitStringEvent : public InputContextEvent { 339 public: CommitStringEvent(const std::string & text,InputContext * context)340 CommitStringEvent(const std::string &text, InputContext *context) 341 : InputContextEvent(context, EventType::InputContextCommitString), 342 text_(text) {} 343 text()344 const std::string &text() const { return text_; } 345 346 protected: 347 std::string text_; 348 }; 349 350 class FCITXCORE_EXPORT InvokeActionEvent : public InputContextEvent { 351 public: 352 enum class Action { LeftClick, RightClick }; InvokeActionEvent(Action action,int cursor,InputContext * context)353 InvokeActionEvent(Action action, int cursor, InputContext *context) 354 : InputContextEvent(context, EventType::InputContextInvokeAction), 355 action_(action), cursor_(cursor) {} 356 action()357 Action action() const { return action_; } cursor()358 int cursor() const { return cursor_; } 359 filter()360 void filter() { 361 filtered_ = true; 362 accept(); 363 } filtered()364 bool filtered() const override { return filtered_; } 365 366 protected: 367 Action action_; 368 int cursor_; 369 bool filtered_ = false; 370 }; 371 372 class FCITXCORE_EXPORT InputContextSwitchInputMethodEvent 373 : public InputContextEvent { 374 public: InputContextSwitchInputMethodEvent(InputMethodSwitchedReason reason,const std::string & oldIM,InputContext * context)375 InputContextSwitchInputMethodEvent(InputMethodSwitchedReason reason, 376 const std::string &oldIM, 377 InputContext *context) 378 : InputContextEvent(context, EventType::InputContextSwitchInputMethod), 379 reason_(reason), oldInputMethod_(oldIM) {} 380 reason()381 InputMethodSwitchedReason reason() const { return reason_; } oldInputMethod()382 const std::string &oldInputMethod() const { return oldInputMethod_; } 383 384 protected: 385 InputMethodSwitchedReason reason_; 386 std::string oldInputMethod_; 387 }; 388 389 class FCITXCORE_EXPORT ResetEvent : public InputContextEvent { 390 public: ResetEvent(ResetReason reason,InputContext * context)391 FCITXCORE_DEPRECATED ResetEvent(ResetReason reason, InputContext *context) 392 : InputContextEvent(context, EventType::InputContextReset), 393 reason_(reason) {} ResetEvent(InputContext * context)394 ResetEvent(InputContext *context) 395 : InputContextEvent(context, EventType::InputContextReset), 396 reason_(ResetReason::Client) {} 397 reason()398 FCITXCORE_DEPRECATED ResetReason reason() const { return reason_; } 399 400 protected: 401 ResetReason reason_; 402 }; 403 404 class FCITXCORE_EXPORT InputContextUpdateUIEvent : public InputContextEvent { 405 public: 406 InputContextUpdateUIEvent(UserInterfaceComponent component, 407 InputContext *context, bool immediate = false) InputContextEvent(context,EventType::InputContextUpdateUI)408 : InputContextEvent(context, EventType::InputContextUpdateUI), 409 component_(component), immediate_(immediate) {} 410 component()411 UserInterfaceComponent component() const { return component_; } immediate()412 bool immediate() const { return immediate_; } 413 414 protected: 415 UserInterfaceComponent component_; 416 bool immediate_; 417 }; 418 419 class FCITXCORE_EXPORT InputMethodNotificationEvent : public InputContextEvent { 420 public: InputMethodNotificationEvent(EventType type,const std::string & name,InputContext * context)421 InputMethodNotificationEvent(EventType type, const std::string &name, 422 InputContext *context) 423 : InputContextEvent(context, type), name_(name) {} 424 name()425 const std::string &name() const { return name_; } 426 427 protected: 428 std::string name_; 429 }; 430 431 class FCITXCORE_EXPORT InputMethodActivatedEvent 432 : public InputMethodNotificationEvent { 433 public: InputMethodActivatedEvent(const std::string & name,InputContext * context)434 InputMethodActivatedEvent(const std::string &name, InputContext *context) 435 : InputMethodNotificationEvent( 436 EventType::InputContextInputMethodActivated, name, context) {} 437 }; 438 439 class FCITXCORE_EXPORT InputMethodDeactivatedEvent 440 : public InputMethodNotificationEvent { 441 public: InputMethodDeactivatedEvent(const std::string & name,InputContext * context)442 InputMethodDeactivatedEvent(const std::string &name, InputContext *context) 443 : InputMethodNotificationEvent( 444 EventType::InputContextInputMethodDeactivated, name, context) {} 445 }; 446 447 #define FCITX_DEFINE_SIMPLE_EVENT(NAME, TYPE, ARGS...) \ 448 struct FCITXCORE_EXPORT NAME##Event : public InputContextEvent { \ 449 NAME##Event(InputContext *ic) \ 450 : InputContextEvent(ic, EventType::TYPE) {} \ 451 } 452 453 FCITX_DEFINE_SIMPLE_EVENT(InputContextCreated, InputContextCreated); 454 FCITX_DEFINE_SIMPLE_EVENT(InputContextDestroyed, InputContextDestroyed); 455 FCITX_DEFINE_SIMPLE_EVENT(FocusIn, InputContextFocusIn); 456 FCITX_DEFINE_SIMPLE_EVENT(FocusOut, InputContextFocusOut); 457 FCITX_DEFINE_SIMPLE_EVENT(SurroundingTextUpdated, 458 InputContextSurroundingTextUpdated); 459 FCITX_DEFINE_SIMPLE_EVENT(CursorRectChanged, InputContextCursorRectChanged); 460 FCITX_DEFINE_SIMPLE_EVENT(UpdatePreedit, InputContextUpdatePreedit); 461 462 class FCITXCORE_EXPORT InputMethodGroupChangedEvent : public Event { 463 public: InputMethodGroupChangedEvent()464 InputMethodGroupChangedEvent() 465 : Event(EventType::InputMethodGroupChanged) {} 466 }; 467 468 class FCITXCORE_EXPORT InputMethodGroupAboutToChangeEvent : public Event { 469 public: InputMethodGroupAboutToChangeEvent()470 InputMethodGroupAboutToChangeEvent() 471 : Event(EventType::InputMethodGroupAboutToChange) {} 472 }; 473 474 class FCITXCORE_EXPORT UIChangedEvent : public Event { 475 public: UIChangedEvent()476 UIChangedEvent() : Event(EventType::UIChanged) {} 477 }; 478 479 class FCITXCORE_EXPORT CheckUpdateEvent : public Event { 480 public: CheckUpdateEvent()481 CheckUpdateEvent() : Event(EventType::CheckUpdate) {} 482 483 /// Make checking update short circuit. If anything need a refresh, just 484 /// simply break. setHasUpdate()485 void setHasUpdate() { 486 filtered_ = true; 487 accept(); 488 } filtered()489 bool filtered() const override { return filtered_; } 490 491 private: 492 bool filtered_ = false; 493 }; 494 495 /** 496 * Notify a focus change for focus group. 497 * 498 * @since 5.0.11 499 */ 500 class FCITXCORE_EXPORT FocusGroupFocusChangedEvent : public Event { 501 public: FocusGroupFocusChangedEvent(FocusGroup * group,InputContext * oldFocus,InputContext * newFocus)502 FocusGroupFocusChangedEvent(FocusGroup *group, InputContext *oldFocus, 503 InputContext *newFocus) 504 : Event(EventType::FocusGroupFocusChanged), group_(group), 505 oldFocus_(oldFocus), newFocus_(newFocus) {} 506 group()507 FocusGroup *group() const { return group_; } oldFocus()508 InputContext *oldFocus() const { return oldFocus_; }; newFocus()509 InputContext *newFocus() const { return newFocus_; }; 510 511 private: 512 FocusGroup *group_; 513 InputContext *oldFocus_; 514 InputContext *newFocus_; 515 }; 516 517 class FCITXCORE_EXPORT CapabilityEvent : public InputContextEvent { 518 public: CapabilityEvent(InputContext * ic,EventType type,CapabilityFlags oldFlags,CapabilityFlags newFlags)519 CapabilityEvent(InputContext *ic, EventType type, CapabilityFlags oldFlags, 520 CapabilityFlags newFlags) 521 : InputContextEvent(ic, type), oldFlags_(oldFlags), 522 newFlags_(newFlags) {} 523 oldFlags()524 auto oldFlags() const { return oldFlags_; } newFlags()525 auto newFlags() const { return newFlags_; } 526 527 protected: 528 const CapabilityFlags oldFlags_; 529 const CapabilityFlags newFlags_; 530 }; 531 532 class FCITXCORE_EXPORT CapabilityChangedEvent : public CapabilityEvent { 533 public: CapabilityChangedEvent(InputContext * ic,CapabilityFlags oldFlags,CapabilityFlags newFlags)534 CapabilityChangedEvent(InputContext *ic, CapabilityFlags oldFlags, 535 CapabilityFlags newFlags) 536 : CapabilityEvent(ic, EventType::InputContextCapabilityChanged, 537 oldFlags, newFlags) {} 538 }; 539 540 class FCITXCORE_EXPORT CapabilityAboutToChangeEvent : public CapabilityEvent { 541 public: CapabilityAboutToChangeEvent(InputContext * ic,CapabilityFlags oldFlags,CapabilityFlags newFlags)542 CapabilityAboutToChangeEvent(InputContext *ic, CapabilityFlags oldFlags, 543 CapabilityFlags newFlags) 544 : CapabilityEvent(ic, EventType::InputContextCapabilityAboutToChange, 545 oldFlags, newFlags) {} 546 }; 547 } // namespace fcitx 548 549 #endif // _FCITX_EVENT_H_ 550