Event.java revision 9c17ad1ccd77783354f4c2e9020c48ab7f71947c
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.event;
18
19import com.android.inputmethod.latin.Constants;
20import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
21import com.android.inputmethod.latin.utils.StringUtils;
22
23/**
24 * Class representing a generic input event as handled by Latin IME.
25 *
26 * This contains information about the origin of the event, but it is generalized and should
27 * represent a software keypress, hardware keypress, or d-pad move alike.
28 * Very importantly, this does not necessarily result in inputting one character, or even anything
29 * at all - it may be a dead key, it may be a partial input, it may be a special key on the
30 * keyboard, it may be a cancellation of a keypress (e.g. in a soft keyboard the finger of the
31 * user has slid out of the key), etc. It may also be a batch input from a gesture or handwriting
32 * for example.
33 * The combiner should figure out what to do with this.
34 */
35public class Event {
36    // Should the types below be represented by separate classes instead? It would be cleaner
37    // but probably a bit too much
38    // An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard.
39    final public static int EVENT_TYPE_NOT_HANDLED = 0;
40    // A key press that is part of input, for example pressing an alphabetic character on a
41    // hardware qwerty keyboard. It may be part of a sequence that will be re-interpreted later
42    // through combination.
43    final public static int EVENT_TYPE_INPUT_KEYPRESS = 1;
44    // A toggle event is triggered by a key that affects the previous character. An example would
45    // be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with
46    // repeated presses.
47    final public static int EVENT_TYPE_TOGGLE = 2;
48    // A mode event instructs the combiner to change modes. The canonical example would be the
49    // hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard
50    // if handled at the combiner level.
51    final public static int EVENT_TYPE_MODE_KEY = 3;
52    // An event corresponding to a gesture.
53    final public static int EVENT_TYPE_GESTURE = 4;
54    // An event corresponding to the manual pick of a suggestion.
55    final public static int EVENT_TYPE_SUGGESTION_PICKED = 5;
56    // An event corresponding to a string generated by some software process.
57    final public static int EVENT_TYPE_SOFTWARE_GENERATED_STRING = 6;
58
59    // 0 is a valid code point, so we use -1 here.
60    final public static int NOT_A_CODE_POINT = -1;
61    // -1 is a valid key code, so we use 0 here.
62    final public static int NOT_A_KEY_CODE = 0;
63
64    final private static int FLAG_NONE = 0;
65    // This event is a dead character, usually input by a dead key. Examples include dead-acute
66    // or dead-abovering.
67    final private static int FLAG_DEAD = 0x1;
68    // This event is coming from a key repeat, software or hardware.
69    final private static int FLAG_REPEAT = 0x2;
70
71    final private int mEventType; // The type of event - one of the constants above
72    // The code point associated with the event, if relevant. This is a unicode code point, and
73    // has nothing to do with other representations of the key. It is only relevant if this event
74    // is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point
75    // associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when
76    // it's not relevant.
77    final public int mCodePoint;
78
79    // If applicable, this contains the string that should be input.
80    final public CharSequence mText;
81
82    // The key code associated with the event, if relevant. This is relevant whenever this event
83    // has been triggered by a key press, but not for a gesture for example. This has conceptually
84    // no link to the code point, although keys that enter a straight code point may often set
85    // this to be equal to mCodePoint for convenience. If this is not a key, this must contain
86    // NOT_A_KEY_CODE.
87    final public int mKeyCode;
88
89    // Coordinates of the touch event, if relevant. If useful, we may want to replace this with
90    // a MotionEvent or something in the future. This is only relevant when the keypress is from
91    // a software keyboard obviously, unless there are touch-sensitive hardware keyboards in the
92    // future or some other awesome sauce.
93    final public int mX;
94    final public int mY;
95
96    // Some flags that can't go into the key code. It's a bit field of FLAG_*
97    final private int mFlags;
98
99    // If this is of type EVENT_TYPE_SUGGESTION_PICKED, this must not be null (and must be null in
100    // other cases).
101    final public SuggestedWordInfo mSuggestedWordInfo;
102
103    // The next event, if any. Null if there is no next event yet.
104    final public Event mNextEvent;
105
106    // This method is private - to create a new event, use one of the create* utility methods.
107    private Event(final int type, final CharSequence text, final int codePoint, final int keyCode,
108            final int x, final int y, final SuggestedWordInfo suggestedWordInfo, final int flags,
109            final Event next) {
110        mEventType = type;
111        mText = text;
112        mCodePoint = codePoint;
113        mKeyCode = keyCode;
114        mX = x;
115        mY = y;
116        mSuggestedWordInfo = suggestedWordInfo;
117        mFlags = flags;
118        mNextEvent = next;
119        // Sanity checks
120        // mSuggestedWordInfo is non-null if and only if the type is SUGGESTION_PICKED
121        if (EVENT_TYPE_SUGGESTION_PICKED == mEventType) {
122            if (null == mSuggestedWordInfo) {
123                throw new RuntimeException("Wrong event: SUGGESTION_PICKED event must have a "
124                        + "non-null SuggestedWordInfo");
125            }
126        } else {
127            if (null != mSuggestedWordInfo) {
128                throw new RuntimeException("Wrong event: only SUGGESTION_PICKED events may have " +
129                        "a non-null SuggestedWordInfo");
130            }
131        }
132    }
133
134    public static Event createSoftwareKeypressEvent(final int codePoint, final int keyCode,
135            final int x, final int y, final boolean isKeyRepeat) {
136        return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, x, y,
137                null /* suggestedWordInfo */, isKeyRepeat ? FLAG_REPEAT : FLAG_NONE, null);
138    }
139
140    public static Event createHardwareKeypressEvent(final int codePoint, final int keyCode,
141            final Event next, final boolean isKeyRepeat) {
142        return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode,
143                Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE,
144                null /* suggestedWordInfo */, isKeyRepeat ? FLAG_REPEAT : FLAG_NONE, next);
145    }
146
147    // This creates an input event for a dead character. @see {@link #FLAG_DEAD}
148    public static Event createDeadEvent(final int codePoint, final int keyCode, final Event next) {
149        // TODO: add an argument or something if we ever create a software layout with dead keys.
150        return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode,
151                Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE,
152                null /* suggestedWordInfo */, FLAG_DEAD, next);
153    }
154
155    /**
156     * Create an input event with nothing but a code point. This is the most basic possible input
157     * event; it contains no information on many things the IME requires to function correctly,
158     * so avoid using it unless really nothing is known about this input.
159     * @param codePoint the code point.
160     * @return an event for this code point.
161     */
162    public static Event createEventForCodePointFromUnknownSource(final int codePoint) {
163        // TODO: should we have a different type of event for this? After all, it's not a key press.
164        return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, NOT_A_KEY_CODE,
165                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
166                null /* suggestedWordInfo */, FLAG_NONE, null /* next */);
167    }
168
169    /**
170     * Creates an input event with a code point and x, y coordinates. This is typically used when
171     * resuming a previously-typed word, when the coordinates are still known.
172     * @param codePoint the code point to input.
173     * @param x the X coordinate.
174     * @param y the Y coordinate.
175     * @return an event for this code point and coordinates.
176     */
177    public static Event createEventForCodePointFromAlreadyTypedText(final int codePoint,
178            final int x, final int y) {
179        // TODO: should we have a different type of event for this? After all, it's not a key press.
180        return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, NOT_A_KEY_CODE,
181                x, y, null /* suggestedWordInfo */, FLAG_NONE, null /* next */);
182    }
183
184    /**
185     * Creates an input event representing the manual pick of a suggestion.
186     * @return an event for this suggestion pick.
187     */
188    public static Event createSuggestionPickedEvent(final SuggestedWordInfo suggestedWordInfo) {
189        return new Event(EVENT_TYPE_SUGGESTION_PICKED, suggestedWordInfo.mWord,
190                NOT_A_CODE_POINT, NOT_A_KEY_CODE,
191                Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE,
192                suggestedWordInfo, FLAG_NONE, null /* next */);
193    }
194
195    /**
196     * Creates an input event with a CharSequence. This is used by some software processes whose
197     * output is a string, possibly with styling. Examples include press on a multi-character key,
198     * or combination that outputs a string.
199     * @param text the CharSequence associated with this event.
200     * @param keyCode the key code, or NOT_A_KEYCODE if not applicable.
201     * @return an event for this text.
202     */
203    public static Event createSoftwareTextEvent(final CharSequence text, final int keyCode) {
204        return new Event(EVENT_TYPE_SOFTWARE_GENERATED_STRING, text, NOT_A_CODE_POINT, keyCode,
205                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
206                null /* suggestedWordInfo */, FLAG_NONE, null /* next */);
207    }
208
209    /**
210     * Creates an input event representing the manual pick of a punctuation suggestion.
211     * @return an event for this suggestion pick.
212     */
213    public static Event createPunctuationSuggestionPickedEvent(
214            final SuggestedWordInfo suggestedWordInfo) {
215        final int primaryCode = suggestedWordInfo.mWord.charAt(0);
216        return new Event(EVENT_TYPE_SUGGESTION_PICKED, suggestedWordInfo.mWord, primaryCode,
217                NOT_A_KEY_CODE, Constants.SUGGESTION_STRIP_COORDINATE,
218                Constants.SUGGESTION_STRIP_COORDINATE, suggestedWordInfo, FLAG_NONE,
219                null /* next */);
220    }
221
222    public static Event createNotHandledEvent() {
223        return new Event(EVENT_TYPE_NOT_HANDLED, null /* text */, NOT_A_CODE_POINT, NOT_A_KEY_CODE,
224                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
225                null /* suggestedWordInfo */, FLAG_NONE, null);
226    }
227
228    // Returns whether this is a function key like backspace, ctrl, settings... as opposed to keys
229    // that result in input like letters or space.
230    public boolean isFunctionalKeyEvent() {
231        // This logic may need to be refined in the future
232        return NOT_A_CODE_POINT == mCodePoint;
233    }
234
235    // Returns whether this event is for a dead character. @see {@link #FLAG_DEAD}
236    public boolean isDead() {
237        return 0 != (FLAG_DEAD & mFlags);
238    }
239
240    public boolean isKeyRepeat() {
241        return 0 != (FLAG_REPEAT & mFlags);
242    }
243
244    // Returns whether this is a fake key press from the suggestion strip. This happens with
245    // punctuation signs selected from the suggestion strip.
246    public boolean isSuggestionStripPress() {
247        return EVENT_TYPE_SUGGESTION_PICKED == mEventType;
248    }
249
250    public boolean isHandled() {
251        return EVENT_TYPE_NOT_HANDLED != mEventType;
252    }
253
254    public CharSequence getTextToCommit() {
255        switch (mEventType) {
256        case EVENT_TYPE_MODE_KEY:
257        case EVENT_TYPE_NOT_HANDLED:
258        case EVENT_TYPE_TOGGLE:
259            return "";
260        case EVENT_TYPE_INPUT_KEYPRESS:
261            return StringUtils.newSingleCodePointString(mCodePoint);
262        case EVENT_TYPE_GESTURE:
263        case EVENT_TYPE_SOFTWARE_GENERATED_STRING:
264        case EVENT_TYPE_SUGGESTION_PICKED:
265            return mText;
266        }
267        throw new RuntimeException("Unknown event type: " + mEventType);
268    }
269}
270