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