Event.java revision 46e17983c69650415c6469a80c46154cb4299f9d
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;
21
22/**
23 * Class representing a generic input event as handled by Latin IME.
24 *
25 * This contains information about the origin of the event, but it is generalized and should
26 * represent a software keypress, hardware keypress, or d-pad move alike.
27 * Very importantly, this does not necessarily result in inputting one character, or even anything
28 * at all - it may be a dead key, it may be a partial input, it may be a special key on the
29 * keyboard, it may be a cancellation of a keypress (e.g. in a soft keyboard the finger of the
30 * user has slid out of the key), etc. It may also be a batch input from a gesture or handwriting
31 * for example.
32 * The combiner should figure out what to do with this.
33 */
34public class Event {
35    // Should the types below be represented by separate classes instead? It would be cleaner
36    // but probably a bit too much
37    // An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard.
38    final public static int EVENT_NOT_HANDLED = 0;
39    // A key press that is part of input, for example pressing an alphabetic character on a
40    // hardware qwerty keyboard. It may be part of a sequence that will be re-interpreted later
41    // through combination.
42    final public static int EVENT_INPUT_KEYPRESS = 1;
43    // A toggle event is triggered by a key that affects the previous character. An example would
44    // be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with
45    // repeated presses.
46    final public static int EVENT_TOGGLE = 2;
47    // A mode event instructs the combiner to change modes. The canonical example would be the
48    // hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard
49    // if handled at the combiner level.
50    final public static int EVENT_MODE_KEY = 3;
51    // An event corresponding to a gesture.
52    final public static int EVENT_GESTURE = 4;
53    // An event corresponding to the manual pick of a suggestion.
54    final public static int EVENT_SUGGESTION_PICKED = 5;
55
56    // 0 is a valid code point, so we use -1 here.
57    final public static int NOT_A_CODE_POINT = -1;
58    // -1 is a valid key code, so we use 0 here.
59    final public static int NOT_A_KEY_CODE = 0;
60
61    final private static int FLAG_NONE = 0;
62    // This event is a dead character, usually input by a dead key. Examples include dead-acute
63    // or dead-abovering.
64    final private static int FLAG_DEAD = 0x1;
65
66    final private int mType; // The type of event - one of the constants above
67    // The code point associated with the event, if relevant. This is a unicode code point, and
68    // has nothing to do with other representations of the key. It is only relevant if this event
69    // is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point
70    // associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when
71    // it's not relevant.
72    final public int mCodePoint;
73
74    // The key code associated with the event, if relevant. This is relevant whenever this event
75    // has been triggered by a key press, but not for a gesture for example. This has conceptually
76    // no link to the code point, although keys that enter a straight code point may often set
77    // this to be equal to mCodePoint for convenience. If this is not a key, this must contain
78    // NOT_A_KEY_CODE.
79    final public int mKeyCode;
80
81    // Coordinates of the touch event, if relevant. If useful, we may want to replace this with
82    // a MotionEvent or something in the future. This is only relevant when the keypress is from
83    // a software keyboard obviously, unless there are touch-sensitive hardware keyboards in the
84    // future or some other awesome sauce.
85    final public int mX;
86    final public int mY;
87
88    // Some flags that can't go into the key code. It's a bit field of FLAG_*
89    final private int mFlags;
90
91    // If this is of type EVENT_SUGGESTION_PICKED, this must not be null (and must be null in
92    // other cases).
93    final public SuggestedWordInfo mSuggestedWordInfo;
94
95    // The next event, if any. Null if there is no next event yet.
96    final public Event mNextEvent;
97
98    // This method is private - to create a new event, use one of the create* utility methods.
99    private Event(final int type, final int codePoint, final int keyCode, final int x, final int y,
100            final SuggestedWordInfo suggestedWordInfo, final int flags, final Event next) {
101        mType = type;
102        mCodePoint = codePoint;
103        mKeyCode = keyCode;
104        mX = x;
105        mY = y;
106        mSuggestedWordInfo = suggestedWordInfo;
107        mFlags = flags;
108        mNextEvent = next;
109        // Sanity checks
110        // mSuggestedWordInfo is non-null if and only if the type is SUGGESTION_PICKED
111        if (EVENT_SUGGESTION_PICKED == mType) {
112            if (null == mSuggestedWordInfo) {
113                throw new RuntimeException("Wrong event: SUGGESTION_PICKED event must have a "
114                        + "non-null SuggestedWordInfo");
115            }
116        } else {
117            if (null != mSuggestedWordInfo) {
118                throw new RuntimeException("Wrong event: only SUGGESTION_PICKED events may have " +
119                        "a non-null SuggestedWordInfo");
120            }
121        }
122    }
123
124    public static Event createSoftwareKeypressEvent(final int codePoint, final int keyCode,
125            final int x, final int y) {
126        return new Event(EVENT_INPUT_KEYPRESS, codePoint, keyCode, x, y,
127                null /* suggestedWordInfo */, FLAG_NONE, null);
128    }
129
130    public static Event createHardwareKeypressEvent(final int codePoint, final int keyCode,
131            final Event next) {
132        return new Event(EVENT_INPUT_KEYPRESS, codePoint, keyCode,
133                Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE,
134                null /* suggestedWordInfo */, FLAG_NONE, next);
135    }
136
137    // This creates an input event for a dead character. @see {@link #FLAG_DEAD}
138    public static Event createDeadEvent(final int codePoint, final int keyCode, final Event next) {
139        // TODO: add an argument or something if we ever create a software layout with dead keys.
140        return new Event(EVENT_INPUT_KEYPRESS, codePoint, keyCode,
141                Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE,
142                null /* suggestedWordInfo */, FLAG_DEAD, next);
143    }
144
145    /**
146     * Create an input event with nothing but a code point. This is the most basic possible input
147     * event; it contains no information on many things the IME requires to function correctly,
148     * so avoid using it unless really nothing is known about this input.
149     * @param codePoint the code point.
150     * @return an event for this code point.
151     */
152    public static Event createEventForCodePointFromUnknownSource(final int codePoint) {
153        // TODO: should we have a different type of event for this? After all, it's not a key press.
154        return new Event(EVENT_INPUT_KEYPRESS, codePoint, NOT_A_KEY_CODE,
155                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
156                null /* suggestedWordInfo */, FLAG_NONE, null /* next */);
157    }
158
159    /**
160     * Creates an input event with a code point and x, y coordinates. This is typically used when
161     * resuming a previously-typed word, when the coordinates are still known.
162     * @param codePoint the code point to input.
163     * @param x the X coordinate.
164     * @param y the Y coordinate.
165     * @return an event for this code point and coordinates.
166     */
167    public static Event createEventForCodePointFromAlreadyTypedText(final int codePoint,
168            final int x, final int y) {
169        // TODO: should we have a different type of event for this? After all, it's not a key press.
170        return new Event(EVENT_INPUT_KEYPRESS, codePoint, NOT_A_KEY_CODE, x, y,
171                null /* suggestedWordInfo */, FLAG_NONE, null /* next */);
172    }
173
174    /**
175     * Creates an input event representing the manual pick of a suggestion.
176     * @return an event for this suggestion pick.
177     */
178    public static Event createSuggestionPickedEvent(final SuggestedWordInfo suggestedWordInfo) {
179        return new Event(EVENT_SUGGESTION_PICKED, NOT_A_CODE_POINT, NOT_A_KEY_CODE,
180                Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE,
181                suggestedWordInfo, FLAG_NONE, null);
182    }
183
184    public static Event createNotHandledEvent() {
185        return new Event(EVENT_NOT_HANDLED, NOT_A_CODE_POINT, NOT_A_KEY_CODE,
186                Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
187                null /* suggestedWordInfo */, FLAG_NONE, null);
188    }
189
190    // Returns whether this event is for a dead character. @see {@link #FLAG_DEAD}
191    public boolean isDead() {
192        return 0 != (FLAG_DEAD & mFlags);
193    }
194
195    // Returns whether this is a fake key press from the suggestion strip. This happens with
196    // punctuation signs selected from the suggestion strip.
197    public boolean isSuggestionStripPress() {
198        return EVENT_INPUT_KEYPRESS == mType && Constants.SUGGESTION_STRIP_COORDINATE == mX;
199    }
200
201    // TODO: remove this method - we should not have to test this
202    public boolean isCommittable() {
203        return EVENT_INPUT_KEYPRESS == mType || EVENT_MODE_KEY == mType || EVENT_TOGGLE == mType;
204    }
205
206    public boolean isHandled() {
207        return EVENT_NOT_HANDLED != mType;
208    }
209}
210