Event.java revision 835965a75e7dad3026911b6615efa502905f3eab
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_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_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_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_MODE_KEY = 3; 52 // An event corresponding to a gesture. 53 final public static int EVENT_GESTURE = 4; 54 // An event corresponding to the manual pick of a suggestion. 55 final public static int EVENT_SUGGESTION_PICKED = 5; 56 // An event corresponding to a string generated by some software process. 57 final public static int EVENT_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 69 final private int mType; // The type of event - one of the constants above 70 // The code point associated with the event, if relevant. This is a unicode code point, and 71 // has nothing to do with other representations of the key. It is only relevant if this event 72 // is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point 73 // associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when 74 // it's not relevant. 75 final public int mCodePoint; 76 77 // If applicable, this contains the string that should be input. 78 final public CharSequence mText; 79 80 // The key code associated with the event, if relevant. This is relevant whenever this event 81 // has been triggered by a key press, but not for a gesture for example. This has conceptually 82 // no link to the code point, although keys that enter a straight code point may often set 83 // this to be equal to mCodePoint for convenience. If this is not a key, this must contain 84 // NOT_A_KEY_CODE. 85 final public int mKeyCode; 86 87 // Coordinates of the touch event, if relevant. If useful, we may want to replace this with 88 // a MotionEvent or something in the future. This is only relevant when the keypress is from 89 // a software keyboard obviously, unless there are touch-sensitive hardware keyboards in the 90 // future or some other awesome sauce. 91 final public int mX; 92 final public int mY; 93 94 // Some flags that can't go into the key code. It's a bit field of FLAG_* 95 final private int mFlags; 96 97 // If this is of type EVENT_SUGGESTION_PICKED, this must not be null (and must be null in 98 // other cases). 99 final public SuggestedWordInfo mSuggestedWordInfo; 100 101 // The next event, if any. Null if there is no next event yet. 102 final public Event mNextEvent; 103 104 // This method is private - to create a new event, use one of the create* utility methods. 105 private Event(final int type, final CharSequence text, final int codePoint, final int keyCode, 106 final int x, final int y, final SuggestedWordInfo suggestedWordInfo, final int flags, 107 final Event next) { 108 mType = type; 109 mText = text; 110 mCodePoint = codePoint; 111 mKeyCode = keyCode; 112 mX = x; 113 mY = y; 114 mSuggestedWordInfo = suggestedWordInfo; 115 mFlags = flags; 116 mNextEvent = next; 117 // Sanity checks 118 // mSuggestedWordInfo is non-null if and only if the type is SUGGESTION_PICKED 119 if (EVENT_SUGGESTION_PICKED == mType) { 120 if (null == mSuggestedWordInfo) { 121 throw new RuntimeException("Wrong event: SUGGESTION_PICKED event must have a " 122 + "non-null SuggestedWordInfo"); 123 } 124 } else { 125 if (null != mSuggestedWordInfo) { 126 throw new RuntimeException("Wrong event: only SUGGESTION_PICKED events may have " + 127 "a non-null SuggestedWordInfo"); 128 } 129 } 130 } 131 132 public static Event createSoftwareKeypressEvent(final int codePoint, final int keyCode, 133 final int x, final int y) { 134 return new Event(EVENT_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, x, y, 135 null /* suggestedWordInfo */, FLAG_NONE, null); 136 } 137 138 public static Event createHardwareKeypressEvent(final int codePoint, final int keyCode, 139 final Event next) { 140 return new Event(EVENT_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, 141 Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE, 142 null /* suggestedWordInfo */, FLAG_NONE, next); 143 } 144 145 // This creates an input event for a dead character. @see {@link #FLAG_DEAD} 146 public static Event createDeadEvent(final int codePoint, final int keyCode, final Event next) { 147 // TODO: add an argument or something if we ever create a software layout with dead keys. 148 return new Event(EVENT_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, 149 Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE, 150 null /* suggestedWordInfo */, FLAG_DEAD, next); 151 } 152 153 /** 154 * Create an input event with nothing but a code point. This is the most basic possible input 155 * event; it contains no information on many things the IME requires to function correctly, 156 * so avoid using it unless really nothing is known about this input. 157 * @param codePoint the code point. 158 * @return an event for this code point. 159 */ 160 public static Event createEventForCodePointFromUnknownSource(final int codePoint) { 161 // TODO: should we have a different type of event for this? After all, it's not a key press. 162 return new Event(EVENT_INPUT_KEYPRESS, null /* text */, codePoint, NOT_A_KEY_CODE, 163 Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, 164 null /* suggestedWordInfo */, FLAG_NONE, null /* next */); 165 } 166 167 /** 168 * Creates an input event with a code point and x, y coordinates. This is typically used when 169 * resuming a previously-typed word, when the coordinates are still known. 170 * @param codePoint the code point to input. 171 * @param x the X coordinate. 172 * @param y the Y coordinate. 173 * @return an event for this code point and coordinates. 174 */ 175 public static Event createEventForCodePointFromAlreadyTypedText(final int codePoint, 176 final int x, final int y) { 177 // TODO: should we have a different type of event for this? After all, it's not a key press. 178 return new Event(EVENT_INPUT_KEYPRESS, null /* text */, codePoint, NOT_A_KEY_CODE, x, y, 179 null /* suggestedWordInfo */, FLAG_NONE, null /* next */); 180 } 181 182 /** 183 * Creates an input event representing the manual pick of a suggestion. 184 * @return an event for this suggestion pick. 185 */ 186 public static Event createSuggestionPickedEvent(final SuggestedWordInfo suggestedWordInfo) { 187 return new Event(EVENT_SUGGESTION_PICKED, suggestedWordInfo.mWord, 188 NOT_A_CODE_POINT, NOT_A_KEY_CODE, 189 Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE, 190 suggestedWordInfo, FLAG_NONE, null); 191 } 192 193 /** 194 * Creates an input event with a CharSequence. This is used by some software processes whose 195 * output is a string, possibly with styling. Examples include press on a multi-character key, 196 * or combination that outputs a string. 197 * @param text the CharSequence associated with this event. 198 * @param keyCode the key code, or NOT_A_KEYCODE if not applicable. 199 * @return an event for this text. 200 */ 201 public static Event createSoftwareTextEvent(final CharSequence text, final int keyCode) { 202 return new Event(EVENT_SOFTWARE_GENERATED_STRING, text, NOT_A_CODE_POINT, keyCode, 203 Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, 204 null /* suggestedWordInfo */, FLAG_NONE, null /* next */); 205 } 206 207 public static Event createNotHandledEvent() { 208 return new Event(EVENT_NOT_HANDLED, null /* text */, NOT_A_CODE_POINT, NOT_A_KEY_CODE, 209 Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, 210 null /* suggestedWordInfo */, FLAG_NONE, null); 211 } 212 213 // Returns whether this event is for a dead character. @see {@link #FLAG_DEAD} 214 public boolean isDead() { 215 return 0 != (FLAG_DEAD & mFlags); 216 } 217 218 // Returns whether this is a fake key press from the suggestion strip. This happens with 219 // punctuation signs selected from the suggestion strip. 220 public boolean isSuggestionStripPress() { 221 return EVENT_INPUT_KEYPRESS == mType && Constants.SUGGESTION_STRIP_COORDINATE == mX; 222 } 223 224 public boolean isHandled() { 225 return EVENT_NOT_HANDLED != mType; 226 } 227 228 public CharSequence getTextToCommit() { 229 switch (mType) { 230 case EVENT_MODE_KEY: 231 case EVENT_NOT_HANDLED: 232 return ""; 233 case EVENT_INPUT_KEYPRESS: 234 case EVENT_TOGGLE: 235 return StringUtils.newSingleCodePointString(mCodePoint); 236 case EVENT_GESTURE: 237 case EVENT_SOFTWARE_GENERATED_STRING: 238 return mText; 239 } 240 throw new RuntimeException("Unknown event type: " + mType); 241 } 242} 243