diff options
29 files changed, 2453 insertions, 885 deletions
diff --git a/api/current.xml b/api/current.xml index 6279d8d..019ca71 100644 --- a/api/current.xml +++ b/api/current.xml @@ -210656,6 +210656,17 @@ visibility="public" > </method> +<method name="getMotionAxes" + return="int[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getMotionRange" return="android.view.InputDevice.MotionRange" abstract="false" @@ -212226,6 +212237,19 @@ visibility="public" > </method> +<method name="isGamepadButton" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="keyCode" type="int"> +</parameter> +</method> <method name="isLongPress" return="boolean" abstract="false" @@ -212338,6 +212362,32 @@ visibility="public" > </method> +<method name="keyCodeFromString" + return="int" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="symbolicName" type="java.lang.String"> +</parameter> +</method> +<method name="keyCodeToString" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="keyCode" type="int"> +</parameter> +</method> <method name="metaStateHasModifiers" return="boolean" abstract="false" @@ -216602,6 +216652,32 @@ <parameter name="metaState" type="int"> </parameter> </method> +<method name="axisFromString" + return="int" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="symbolicName" type="java.lang.String"> +</parameter> +</method> +<method name="axisToString" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="axis" type="int"> +</parameter> +</method> <method name="findPointerIndex" return="int" abstract="false" @@ -217841,6 +217917,226 @@ visibility="public" > </field> +<field name="AXIS_GENERIC_1" + type="int" + transient="false" + volatile="false" + value="32" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_10" + type="int" + transient="false" + volatile="false" + value="41" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_11" + type="int" + transient="false" + volatile="false" + value="42" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_12" + type="int" + transient="false" + volatile="false" + value="43" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_13" + type="int" + transient="false" + volatile="false" + value="44" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_14" + type="int" + transient="false" + volatile="false" + value="45" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_15" + type="int" + transient="false" + volatile="false" + value="46" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_16" + type="int" + transient="false" + volatile="false" + value="47" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_2" + type="int" + transient="false" + volatile="false" + value="33" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_3" + type="int" + transient="false" + volatile="false" + value="34" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_4" + type="int" + transient="false" + volatile="false" + value="35" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_5" + type="int" + transient="false" + volatile="false" + value="36" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_6" + type="int" + transient="false" + volatile="false" + value="37" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_7" + type="int" + transient="false" + volatile="false" + value="38" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_8" + type="int" + transient="false" + volatile="false" + value="39" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_GENERIC_9" + type="int" + transient="false" + volatile="false" + value="40" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_HAT_X" + type="int" + transient="false" + volatile="false" + value="15" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_HAT_Y" + type="int" + transient="false" + volatile="false" + value="16" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_HSCROLL" + type="int" + transient="false" + volatile="false" + value="10" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_LTRIGGER" + type="int" + transient="false" + volatile="false" + value="17" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="AXIS_ORIENTATION" type="int" transient="false" @@ -217863,6 +218159,50 @@ visibility="public" > </field> +<field name="AXIS_RTRIGGER" + type="int" + transient="false" + volatile="false" + value="18" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_RX" + type="int" + transient="false" + volatile="false" + value="12" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_RY" + type="int" + transient="false" + volatile="false" + value="13" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="AXIS_RZ" + type="int" + transient="false" + volatile="false" + value="14" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="AXIS_SIZE" type="int" transient="false" @@ -217918,6 +218258,17 @@ visibility="public" > </field> +<field name="AXIS_VSCROLL" + type="int" + transient="false" + volatile="false" + value="9" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="AXIS_X" type="int" transient="false" @@ -217940,6 +218291,17 @@ visibility="public" > </field> +<field name="AXIS_Z" + type="int" + transient="false" + volatile="false" + value="11" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="CREATOR" type="android.os.Parcelable.Creator" transient="false" diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 7abbce6..def1161 100755 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -44,6 +44,7 @@ public final class InputDevice implements Parcelable { private int mKeyboardType; private final SparseArray<MotionRange> mMotionRanges = new SparseArray<MotionRange>(); + private int[] mMotionAxes; /** * A mask for input source classes. @@ -359,12 +360,31 @@ public final class InputDevice implements Parcelable { * * @see MotionEvent#AXIS_X * @see MotionEvent#AXIS_Y + * @see #getSupportedAxes() */ public MotionRange getMotionRange(int axis) { return mMotionRanges.get(axis); } - // Called by native code. + /** + * Gets the axis ids of all motion axes supported by this device. + * @return The axis ids of all motion axes supported by this device. + * + * @see #getMotionRange(int) + */ + public int[] getMotionAxes() { + synchronized (this) { + if (mMotionAxes == null) { + final int count = mMotionRanges.size(); + mMotionAxes = new int[count]; + for (int i = 0; i < count; i++) { + mMotionAxes[i] = mMotionRanges.keyAt(i); + } + } + return mMotionAxes; + } + } + private void addMotionRange(int axis, float min, float max, float flat, float fuzz) { mMotionRanges.append(axis, new MotionRange(min, max, flat, fuzz)); } @@ -388,33 +408,35 @@ public final class InputDevice implements Parcelable { } /** - * Gets the minimum value for the axis. - * @return The (inclusive) minimum value. + * Gets the inclusive minimum value for the axis. + * @return The inclusive minimum value. */ public float getMin() { return mMin; } /** - * Gets the maximum value for the axis. - * @return The (inclusive) maximum value. + * Gets the inclusive maximum value for the axis. + * @return The inclusive maximum value. */ public float getMax() { return mMax; } /** - * Gets the range of the axis (difference between maximum and minimum plus one). + * Gets the range of the axis (difference between maximum and minimum). * @return The range of values. */ public float getRange() { - return mMax - mMin + 1; + return mMax - mMin; } /** * Gets the extent of the center flat position with respect to this axis. + * <p> * For example, a flat value of 8 means that the center position is between -8 and +8. * This value is mainly useful for calibrating self-centering devices. + * </p> * @return The extent of the center flat position. */ public float getFlat() { @@ -423,8 +445,10 @@ public final class InputDevice implements Parcelable { /** * Gets the error tolerance for input device measurements with respect to this axis. + * <p> * For example, a value of 2 indicates that the measured value may be up to +/- 2 units * away from the actual value due to noise and device sensitivity limitations. + * </p> * @return The error tolerance. */ public float getFuzz() { diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 3f6a04b..81d5a6e 100755 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -21,6 +21,7 @@ import android.os.Parcelable; import android.text.method.MetaKeyKeyListener; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import android.util.SparseIntArray; import android.view.KeyCharacterMap; import android.view.KeyCharacterMap.KeyData; @@ -582,213 +583,214 @@ public class KeyEvent extends InputEvent implements Parcelable { // those new codes. This is intended to maintain a consistent // set of key code definitions across all Android devices. - // Symbolic names of all keys indexed by keycode. - // There should be exactly LAST_KEYCODE + 1 entries in this table. - private static final String[] KEYCODE_SYMBOLIC_NAMES = new String[] { - "KEYCODE_UNKNOWN", - "KEYCODE_SOFT_LEFT", - "KEYCODE_SOFT_RIGHT", - "KEYCODE_HOME", - "KEYCODE_BACK", - "KEYCODE_CALL", - "KEYCODE_ENDCALL", - "KEYCODE_0", - "KEYCODE_1", - "KEYCODE_2", - "KEYCODE_3", - "KEYCODE_4", - "KEYCODE_5", - "KEYCODE_6", - "KEYCODE_7", - "KEYCODE_8", - "KEYCODE_9", - "KEYCODE_STAR", - "KEYCODE_POUND", - "KEYCODE_DPAD_UP", - "KEYCODE_DPAD_DOWN", - "KEYCODE_DPAD_LEFT", - "KEYCODE_DPAD_RIGHT", - "KEYCODE_DPAD_CENTER", - "KEYCODE_VOLUME_UP", - "KEYCODE_VOLUME_DOWN", - "KEYCODE_POWER", - "KEYCODE_CAMERA", - "KEYCODE_CLEAR", - "KEYCODE_A", - "KEYCODE_B", - "KEYCODE_C", - "KEYCODE_D", - "KEYCODE_E", - "KEYCODE_F", - "KEYCODE_G", - "KEYCODE_H", - "KEYCODE_I", - "KEYCODE_J", - "KEYCODE_K", - "KEYCODE_L", - "KEYCODE_M", - "KEYCODE_N", - "KEYCODE_O", - "KEYCODE_P", - "KEYCODE_Q", - "KEYCODE_R", - "KEYCODE_S", - "KEYCODE_T", - "KEYCODE_U", - "KEYCODE_V", - "KEYCODE_W", - "KEYCODE_X", - "KEYCODE_Y", - "KEYCODE_Z", - "KEYCODE_COMMA", - "KEYCODE_PERIOD", - "KEYCODE_ALT_LEFT", - "KEYCODE_ALT_RIGHT", - "KEYCODE_SHIFT_LEFT", - "KEYCODE_SHIFT_RIGHT", - "KEYCODE_TAB", - "KEYCODE_SPACE", - "KEYCODE_SYM", - "KEYCODE_EXPLORER", - "KEYCODE_ENVELOPE", - "KEYCODE_ENTER", - "KEYCODE_DEL", - "KEYCODE_GRAVE", - "KEYCODE_MINUS", - "KEYCODE_EQUALS", - "KEYCODE_LEFT_BRACKET", - "KEYCODE_RIGHT_BRACKET", - "KEYCODE_BACKSLASH", - "KEYCODE_SEMICOLON", - "KEYCODE_APOSTROPHE", - "KEYCODE_SLASH", - "KEYCODE_AT", - "KEYCODE_NUM", - "KEYCODE_HEADSETHOOK", - "KEYCODE_FOCUS", - "KEYCODE_PLUS", - "KEYCODE_MENU", - "KEYCODE_NOTIFICATION", - "KEYCODE_SEARCH", - "KEYCODE_MEDIA_PLAY_PAUSE", - "KEYCODE_MEDIA_STOP", - "KEYCODE_MEDIA_NEXT", - "KEYCODE_MEDIA_PREVIOUS", - "KEYCODE_MEDIA_REWIND", - "KEYCODE_MEDIA_FAST_FORWARD", - "KEYCODE_MUTE", - "KEYCODE_PAGE_UP", - "KEYCODE_PAGE_DOWN", - "KEYCODE_PICTSYMBOLS", - "KEYCODE_SWITCH_CHARSET", - "KEYCODE_BUTTON_A", - "KEYCODE_BUTTON_B", - "KEYCODE_BUTTON_C", - "KEYCODE_BUTTON_X", - "KEYCODE_BUTTON_Y", - "KEYCODE_BUTTON_Z", - "KEYCODE_BUTTON_L1", - "KEYCODE_BUTTON_R1", - "KEYCODE_BUTTON_L2", - "KEYCODE_BUTTON_R2", - "KEYCODE_BUTTON_THUMBL", - "KEYCODE_BUTTON_THUMBR", - "KEYCODE_BUTTON_START", - "KEYCODE_BUTTON_SELECT", - "KEYCODE_BUTTON_MODE", - "KEYCODE_ESCAPE", - "KEYCODE_FORWARD_DEL", - "KEYCODE_CTRL_LEFT", - "KEYCODE_CTRL_RIGHT", - "KEYCODE_CAPS_LOCK", - "KEYCODE_SCROLL_LOCK", - "KEYCODE_META_LEFT", - "KEYCODE_META_RIGHT", - "KEYCODE_FUNCTION", - "KEYCODE_SYSRQ", - "KEYCODE_BREAK", - "KEYCODE_MOVE_HOME", - "KEYCODE_MOVE_END", - "KEYCODE_INSERT", - "KEYCODE_FORWARD", - "KEYCODE_MEDIA_PLAY", - "KEYCODE_MEDIA_PAUSE", - "KEYCODE_MEDIA_CLOSE", - "KEYCODE_MEDIA_EJECT", - "KEYCODE_MEDIA_RECORD", - "KEYCODE_F1", - "KEYCODE_F2", - "KEYCODE_F3", - "KEYCODE_F4", - "KEYCODE_F5", - "KEYCODE_F6", - "KEYCODE_F7", - "KEYCODE_F8", - "KEYCODE_F9", - "KEYCODE_F10", - "KEYCODE_F11", - "KEYCODE_F12", - "KEYCODE_NUM_LOCK", - "KEYCODE_NUMPAD_0", - "KEYCODE_NUMPAD_1", - "KEYCODE_NUMPAD_2", - "KEYCODE_NUMPAD_3", - "KEYCODE_NUMPAD_4", - "KEYCODE_NUMPAD_5", - "KEYCODE_NUMPAD_6", - "KEYCODE_NUMPAD_7", - "KEYCODE_NUMPAD_8", - "KEYCODE_NUMPAD_9", - "KEYCODE_NUMPAD_DIVIDE", - "KEYCODE_NUMPAD_MULTIPLY", - "KEYCODE_MUMPAD_SUBTRACT", - "KEYCODE_NUMPAD_ADD", - "KEYCODE_NUMPAD_DOT", - "KEYCODE_NUMPAD_COMMA", - "KEYCODE_NUMPAD_ENTER", - "KEYCODE_NUMPAD_EQUALS", - "KEYCODE_NUMPAD_LEFT_PAREN", - "KEYCODE_NUMPAD_RIGHT_PAREN", - "KEYCODE_VOLUME_MUTE", - "KEYCODE_INFO", - "KEYCODE_CHANNEL_UP", - "KEYCODE_CHANNEL_DOWN", - "KEYCODE_ZOOM_IN", - "KEYCODE_ZOOM_OUT", - "KEYCODE_TV", - "KEYCODE_WINDOW", - "KEYCODE_GUIDE", - "KEYCODE_DVR", - "KEYCODE_BOOKMARK", - "KEYCODE_CAPTIONS", - "KEYCODE_SETTINGS", - "KEYCODE_TV_POWER", - "KEYCODE_TV_INPUT", - "KEYCODE_STB_INPUT", - "KEYCODE_STB_POWER", - "KEYCODE_AVR_POWER", - "KEYCODE_AVR_INPUT", - "KEYCODE_PROG_RED", - "KEYCODE_PROG_GREEN", - "KEYCODE_PROG_YELLOW", - "KEYCODE_PROG_BLUE", - "KEYCODE_APP_SWITCH", - "KEYCODE_BUTTON_1", - "KEYCODE_BUTTON_2", - "KEYCODE_BUTTON_3", - "KEYCODE_BUTTON_4", - "KEYCODE_BUTTON_5", - "KEYCODE_BUTTON_6", - "KEYCODE_BUTTON_7", - "KEYCODE_BUTTON_8", - "KEYCODE_BUTTON_9", - "KEYCODE_BUTTON_10", - "KEYCODE_BUTTON_11", - "KEYCODE_BUTTON_12", - "KEYCODE_BUTTON_13", - "KEYCODE_BUTTON_14", - "KEYCODE_BUTTON_15", - "KEYCODE_BUTTON_16", + // Symbolic names of all key codes. + private static final SparseArray<String> KEYCODE_SYMBOLIC_NAMES = new SparseArray<String>(); + private static void populateKeycodeSymbolicNames() { + SparseArray<String> names = KEYCODE_SYMBOLIC_NAMES; + names.append(KEYCODE_UNKNOWN, "KEYCODE_UNKNOWN"); + names.append(KEYCODE_SOFT_LEFT, "KEYCODE_SOFT_LEFT"); + names.append(KEYCODE_SOFT_RIGHT, "KEYCODE_SOFT_RIGHT"); + names.append(KEYCODE_HOME, "KEYCODE_HOME"); + names.append(KEYCODE_BACK, "KEYCODE_BACK"); + names.append(KEYCODE_CALL, "KEYCODE_CALL"); + names.append(KEYCODE_ENDCALL, "KEYCODE_ENDCALL"); + names.append(KEYCODE_0, "KEYCODE_0"); + names.append(KEYCODE_1, "KEYCODE_1"); + names.append(KEYCODE_2, "KEYCODE_2"); + names.append(KEYCODE_3, "KEYCODE_3"); + names.append(KEYCODE_4, "KEYCODE_4"); + names.append(KEYCODE_5, "KEYCODE_5"); + names.append(KEYCODE_6, "KEYCODE_6"); + names.append(KEYCODE_7, "KEYCODE_7"); + names.append(KEYCODE_8, "KEYCODE_8"); + names.append(KEYCODE_9, "KEYCODE_9"); + names.append(KEYCODE_STAR, "KEYCODE_STAR"); + names.append(KEYCODE_POUND, "KEYCODE_POUND"); + names.append(KEYCODE_DPAD_UP, "KEYCODE_DPAD_UP"); + names.append(KEYCODE_DPAD_DOWN, "KEYCODE_DPAD_DOWN"); + names.append(KEYCODE_DPAD_LEFT, "KEYCODE_DPAD_LEFT"); + names.append(KEYCODE_DPAD_RIGHT, "KEYCODE_DPAD_RIGHT"); + names.append(KEYCODE_DPAD_CENTER, "KEYCODE_DPAD_CENTER"); + names.append(KEYCODE_VOLUME_UP, "KEYCODE_VOLUME_UP"); + names.append(KEYCODE_VOLUME_DOWN, "KEYCODE_VOLUME_DOWN"); + names.append(KEYCODE_POWER, "KEYCODE_POWER"); + names.append(KEYCODE_CAMERA, "KEYCODE_CAMERA"); + names.append(KEYCODE_CLEAR, "KEYCODE_CLEAR"); + names.append(KEYCODE_A, "KEYCODE_A"); + names.append(KEYCODE_B, "KEYCODE_B"); + names.append(KEYCODE_C, "KEYCODE_C"); + names.append(KEYCODE_D, "KEYCODE_D"); + names.append(KEYCODE_E, "KEYCODE_E"); + names.append(KEYCODE_F, "KEYCODE_F"); + names.append(KEYCODE_G, "KEYCODE_G"); + names.append(KEYCODE_H, "KEYCODE_H"); + names.append(KEYCODE_I, "KEYCODE_I"); + names.append(KEYCODE_J, "KEYCODE_J"); + names.append(KEYCODE_K, "KEYCODE_K"); + names.append(KEYCODE_L, "KEYCODE_L"); + names.append(KEYCODE_M, "KEYCODE_M"); + names.append(KEYCODE_N, "KEYCODE_N"); + names.append(KEYCODE_O, "KEYCODE_O"); + names.append(KEYCODE_P, "KEYCODE_P"); + names.append(KEYCODE_Q, "KEYCODE_Q"); + names.append(KEYCODE_R, "KEYCODE_R"); + names.append(KEYCODE_S, "KEYCODE_S"); + names.append(KEYCODE_T, "KEYCODE_T"); + names.append(KEYCODE_U, "KEYCODE_U"); + names.append(KEYCODE_V, "KEYCODE_V"); + names.append(KEYCODE_W, "KEYCODE_W"); + names.append(KEYCODE_X, "KEYCODE_X"); + names.append(KEYCODE_Y, "KEYCODE_Y"); + names.append(KEYCODE_Z, "KEYCODE_Z"); + names.append(KEYCODE_COMMA, "KEYCODE_COMMA"); + names.append(KEYCODE_PERIOD, "KEYCODE_PERIOD"); + names.append(KEYCODE_ALT_LEFT, "KEYCODE_ALT_LEFT"); + names.append(KEYCODE_ALT_RIGHT, "KEYCODE_ALT_RIGHT"); + names.append(KEYCODE_SHIFT_LEFT, "KEYCODE_SHIFT_LEFT"); + names.append(KEYCODE_SHIFT_RIGHT, "KEYCODE_SHIFT_RIGHT"); + names.append(KEYCODE_TAB, "KEYCODE_TAB"); + names.append(KEYCODE_SPACE, "KEYCODE_SPACE"); + names.append(KEYCODE_SYM, "KEYCODE_SYM"); + names.append(KEYCODE_EXPLORER, "KEYCODE_EXPLORER"); + names.append(KEYCODE_ENVELOPE, "KEYCODE_ENVELOPE"); + names.append(KEYCODE_ENTER, "KEYCODE_ENTER"); + names.append(KEYCODE_DEL, "KEYCODE_DEL"); + names.append(KEYCODE_GRAVE, "KEYCODE_GRAVE"); + names.append(KEYCODE_MINUS, "KEYCODE_MINUS"); + names.append(KEYCODE_EQUALS, "KEYCODE_EQUALS"); + names.append(KEYCODE_LEFT_BRACKET, "KEYCODE_LEFT_BRACKET"); + names.append(KEYCODE_RIGHT_BRACKET, "KEYCODE_RIGHT_BRACKET"); + names.append(KEYCODE_BACKSLASH, "KEYCODE_BACKSLASH"); + names.append(KEYCODE_SEMICOLON, "KEYCODE_SEMICOLON"); + names.append(KEYCODE_APOSTROPHE, "KEYCODE_APOSTROPHE"); + names.append(KEYCODE_SLASH, "KEYCODE_SLASH"); + names.append(KEYCODE_AT, "KEYCODE_AT"); + names.append(KEYCODE_NUM, "KEYCODE_NUM"); + names.append(KEYCODE_HEADSETHOOK, "KEYCODE_HEADSETHOOK"); + names.append(KEYCODE_FOCUS, "KEYCODE_FOCUS"); + names.append(KEYCODE_PLUS, "KEYCODE_PLUS"); + names.append(KEYCODE_MENU, "KEYCODE_MENU"); + names.append(KEYCODE_NOTIFICATION, "KEYCODE_NOTIFICATION"); + names.append(KEYCODE_SEARCH, "KEYCODE_SEARCH"); + names.append(KEYCODE_MEDIA_PLAY_PAUSE, "KEYCODE_MEDIA_PLAY_PAUSE"); + names.append(KEYCODE_MEDIA_STOP, "KEYCODE_MEDIA_STOP"); + names.append(KEYCODE_MEDIA_NEXT, "KEYCODE_MEDIA_NEXT"); + names.append(KEYCODE_MEDIA_PREVIOUS, "KEYCODE_MEDIA_PREVIOUS"); + names.append(KEYCODE_MEDIA_REWIND, "KEYCODE_MEDIA_REWIND"); + names.append(KEYCODE_MEDIA_FAST_FORWARD, "KEYCODE_MEDIA_FAST_FORWARD"); + names.append(KEYCODE_MUTE, "KEYCODE_MUTE"); + names.append(KEYCODE_PAGE_UP, "KEYCODE_PAGE_UP"); + names.append(KEYCODE_PAGE_DOWN, "KEYCODE_PAGE_DOWN"); + names.append(KEYCODE_PICTSYMBOLS, "KEYCODE_PICTSYMBOLS"); + names.append(KEYCODE_SWITCH_CHARSET, "KEYCODE_SWITCH_CHARSET"); + names.append(KEYCODE_BUTTON_A, "KEYCODE_BUTTON_A"); + names.append(KEYCODE_BUTTON_B, "KEYCODE_BUTTON_B"); + names.append(KEYCODE_BUTTON_C, "KEYCODE_BUTTON_C"); + names.append(KEYCODE_BUTTON_X, "KEYCODE_BUTTON_X"); + names.append(KEYCODE_BUTTON_Y, "KEYCODE_BUTTON_Y"); + names.append(KEYCODE_BUTTON_Z, "KEYCODE_BUTTON_Z"); + names.append(KEYCODE_BUTTON_L1, "KEYCODE_BUTTON_L1"); + names.append(KEYCODE_BUTTON_R1, "KEYCODE_BUTTON_R1"); + names.append(KEYCODE_BUTTON_L2, "KEYCODE_BUTTON_L2"); + names.append(KEYCODE_BUTTON_R2, "KEYCODE_BUTTON_R2"); + names.append(KEYCODE_BUTTON_THUMBL, "KEYCODE_BUTTON_THUMBL"); + names.append(KEYCODE_BUTTON_THUMBR, "KEYCODE_BUTTON_THUMBR"); + names.append(KEYCODE_BUTTON_START, "KEYCODE_BUTTON_START"); + names.append(KEYCODE_BUTTON_SELECT, "KEYCODE_BUTTON_SELECT"); + names.append(KEYCODE_BUTTON_MODE, "KEYCODE_BUTTON_MODE"); + names.append(KEYCODE_ESCAPE, "KEYCODE_ESCAPE"); + names.append(KEYCODE_FORWARD_DEL, "KEYCODE_FORWARD_DEL"); + names.append(KEYCODE_CTRL_LEFT, "KEYCODE_CTRL_LEFT"); + names.append(KEYCODE_CTRL_RIGHT, "KEYCODE_CTRL_RIGHT"); + names.append(KEYCODE_CAPS_LOCK, "KEYCODE_CAPS_LOCK"); + names.append(KEYCODE_SCROLL_LOCK, "KEYCODE_SCROLL_LOCK"); + names.append(KEYCODE_META_LEFT, "KEYCODE_META_LEFT"); + names.append(KEYCODE_META_RIGHT, "KEYCODE_META_RIGHT"); + names.append(KEYCODE_FUNCTION, "KEYCODE_FUNCTION"); + names.append(KEYCODE_SYSRQ, "KEYCODE_SYSRQ"); + names.append(KEYCODE_BREAK, "KEYCODE_BREAK"); + names.append(KEYCODE_MOVE_HOME, "KEYCODE_MOVE_HOME"); + names.append(KEYCODE_MOVE_END, "KEYCODE_MOVE_END"); + names.append(KEYCODE_INSERT, "KEYCODE_INSERT"); + names.append(KEYCODE_FORWARD, "KEYCODE_FORWARD"); + names.append(KEYCODE_MEDIA_PLAY, "KEYCODE_MEDIA_PLAY"); + names.append(KEYCODE_MEDIA_PAUSE, "KEYCODE_MEDIA_PAUSE"); + names.append(KEYCODE_MEDIA_CLOSE, "KEYCODE_MEDIA_CLOSE"); + names.append(KEYCODE_MEDIA_EJECT, "KEYCODE_MEDIA_EJECT"); + names.append(KEYCODE_MEDIA_RECORD, "KEYCODE_MEDIA_RECORD"); + names.append(KEYCODE_F1, "KEYCODE_F1"); + names.append(KEYCODE_F2, "KEYCODE_F2"); + names.append(KEYCODE_F3, "KEYCODE_F3"); + names.append(KEYCODE_F4, "KEYCODE_F4"); + names.append(KEYCODE_F5, "KEYCODE_F5"); + names.append(KEYCODE_F6, "KEYCODE_F6"); + names.append(KEYCODE_F7, "KEYCODE_F7"); + names.append(KEYCODE_F8, "KEYCODE_F8"); + names.append(KEYCODE_F9, "KEYCODE_F9"); + names.append(KEYCODE_F10, "KEYCODE_F10"); + names.append(KEYCODE_F11, "KEYCODE_F11"); + names.append(KEYCODE_F12, "KEYCODE_F12"); + names.append(KEYCODE_NUM_LOCK, "KEYCODE_NUM_LOCK"); + names.append(KEYCODE_NUMPAD_0, "KEYCODE_NUMPAD_0"); + names.append(KEYCODE_NUMPAD_1, "KEYCODE_NUMPAD_1"); + names.append(KEYCODE_NUMPAD_2, "KEYCODE_NUMPAD_2"); + names.append(KEYCODE_NUMPAD_3, "KEYCODE_NUMPAD_3"); + names.append(KEYCODE_NUMPAD_4, "KEYCODE_NUMPAD_4"); + names.append(KEYCODE_NUMPAD_5, "KEYCODE_NUMPAD_5"); + names.append(KEYCODE_NUMPAD_6, "KEYCODE_NUMPAD_6"); + names.append(KEYCODE_NUMPAD_7, "KEYCODE_NUMPAD_7"); + names.append(KEYCODE_NUMPAD_8, "KEYCODE_NUMPAD_8"); + names.append(KEYCODE_NUMPAD_9, "KEYCODE_NUMPAD_9"); + names.append(KEYCODE_NUMPAD_DIVIDE, "KEYCODE_NUMPAD_DIVIDE"); + names.append(KEYCODE_NUMPAD_MULTIPLY, "KEYCODE_NUMPAD_MULTIPLY"); + names.append(KEYCODE_NUMPAD_SUBTRACT, "KEYCODE_NUMPAD_SUBTRACT"); + names.append(KEYCODE_NUMPAD_ADD, "KEYCODE_NUMPAD_ADD"); + names.append(KEYCODE_NUMPAD_DOT, "KEYCODE_NUMPAD_DOT"); + names.append(KEYCODE_NUMPAD_COMMA, "KEYCODE_NUMPAD_COMMA"); + names.append(KEYCODE_NUMPAD_ENTER, "KEYCODE_NUMPAD_ENTER"); + names.append(KEYCODE_NUMPAD_EQUALS, "KEYCODE_NUMPAD_EQUALS"); + names.append(KEYCODE_NUMPAD_LEFT_PAREN, "KEYCODE_NUMPAD_LEFT_PAREN"); + names.append(KEYCODE_NUMPAD_RIGHT_PAREN, "KEYCODE_NUMPAD_RIGHT_PAREN"); + names.append(KEYCODE_VOLUME_MUTE, "KEYCODE_VOLUME_MUTE"); + names.append(KEYCODE_INFO, "KEYCODE_INFO"); + names.append(KEYCODE_CHANNEL_UP, "KEYCODE_CHANNEL_UP"); + names.append(KEYCODE_CHANNEL_DOWN, "KEYCODE_CHANNEL_DOWN"); + names.append(KEYCODE_ZOOM_IN, "KEYCODE_ZOOM_IN"); + names.append(KEYCODE_ZOOM_OUT, "KEYCODE_ZOOM_OUT"); + names.append(KEYCODE_TV, "KEYCODE_TV"); + names.append(KEYCODE_WINDOW, "KEYCODE_WINDOW"); + names.append(KEYCODE_GUIDE, "KEYCODE_GUIDE"); + names.append(KEYCODE_DVR, "KEYCODE_DVR"); + names.append(KEYCODE_BOOKMARK, "KEYCODE_BOOKMARK"); + names.append(KEYCODE_CAPTIONS, "KEYCODE_CAPTIONS"); + names.append(KEYCODE_SETTINGS, "KEYCODE_SETTINGS"); + names.append(KEYCODE_TV_POWER, "KEYCODE_TV_POWER"); + names.append(KEYCODE_TV_INPUT, "KEYCODE_TV_INPUT"); + names.append(KEYCODE_STB_INPUT, "KEYCODE_STB_INPUT"); + names.append(KEYCODE_STB_POWER, "KEYCODE_STB_POWER"); + names.append(KEYCODE_AVR_POWER, "KEYCODE_AVR_POWER"); + names.append(KEYCODE_AVR_INPUT, "KEYCODE_AVR_INPUT"); + names.append(KEYCODE_PROG_RED, "KEYCODE_PROG_RED"); + names.append(KEYCODE_PROG_GREEN, "KEYCODE_PROG_GREEN"); + names.append(KEYCODE_PROG_YELLOW, "KEYCODE_PROG_YELLOW"); + names.append(KEYCODE_PROG_BLUE, "KEYCODE_PROG_BLUE"); + names.append(KEYCODE_APP_SWITCH, "KEYCODE_APP_SWITCH"); + names.append(KEYCODE_BUTTON_1, "KEYCODE_BUTTON_1"); + names.append(KEYCODE_BUTTON_2, "KEYCODE_BUTTON_2"); + names.append(KEYCODE_BUTTON_3, "KEYCODE_BUTTON_3"); + names.append(KEYCODE_BUTTON_4, "KEYCODE_BUTTON_4"); + names.append(KEYCODE_BUTTON_5, "KEYCODE_BUTTON_5"); + names.append(KEYCODE_BUTTON_6, "KEYCODE_BUTTON_6"); + names.append(KEYCODE_BUTTON_7, "KEYCODE_BUTTON_7"); + names.append(KEYCODE_BUTTON_8, "KEYCODE_BUTTON_8"); + names.append(KEYCODE_BUTTON_9, "KEYCODE_BUTTON_9"); + names.append(KEYCODE_BUTTON_10, "KEYCODE_BUTTON_10"); + names.append(KEYCODE_BUTTON_11, "KEYCODE_BUTTON_11"); + names.append(KEYCODE_BUTTON_12, "KEYCODE_BUTTON_12"); + names.append(KEYCODE_BUTTON_13, "KEYCODE_BUTTON_13"); + names.append(KEYCODE_BUTTON_14, "KEYCODE_BUTTON_14"); + names.append(KEYCODE_BUTTON_15, "KEYCODE_BUTTON_15"); + names.append(KEYCODE_BUTTON_16, "KEYCODE_BUTTON_16"); }; // Symbolic names of all metakeys in bit order from least significant to most significant. @@ -1250,14 +1252,7 @@ public class KeyEvent extends InputEvent implements Parcelable { } static { - if (META_SYMBOLIC_NAMES.length != 32) { - throw new IllegalStateException( - "META_SYMBOLIC_NAMES array should contain exactly 32 entries."); - } - if (KEYCODE_SYMBOLIC_NAMES.length != LAST_KEYCODE + 1) { - throw new IllegalStateException( - "KEYCODE_SYMBOLIC_NAMES array is out of sync with the keycode constants."); - } + populateKeycodeSymbolicNames(); } private KeyEvent() { @@ -1653,6 +1648,49 @@ public class KeyEvent extends InputEvent implements Parcelable { return native_hasDefaultAction(mKeyCode); } + /** + * Returns true if the specified keycode is a gamepad button. + * @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}. + */ + public static final boolean isGamepadButton(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_BUTTON_A: + case KeyEvent.KEYCODE_BUTTON_B: + case KeyEvent.KEYCODE_BUTTON_C: + case KeyEvent.KEYCODE_BUTTON_X: + case KeyEvent.KEYCODE_BUTTON_Y: + case KeyEvent.KEYCODE_BUTTON_Z: + case KeyEvent.KEYCODE_BUTTON_L1: + case KeyEvent.KEYCODE_BUTTON_R1: + case KeyEvent.KEYCODE_BUTTON_L2: + case KeyEvent.KEYCODE_BUTTON_R2: + case KeyEvent.KEYCODE_BUTTON_THUMBL: + case KeyEvent.KEYCODE_BUTTON_THUMBR: + case KeyEvent.KEYCODE_BUTTON_START: + case KeyEvent.KEYCODE_BUTTON_SELECT: + case KeyEvent.KEYCODE_BUTTON_MODE: + case KeyEvent.KEYCODE_BUTTON_1: + case KeyEvent.KEYCODE_BUTTON_2: + case KeyEvent.KEYCODE_BUTTON_3: + case KeyEvent.KEYCODE_BUTTON_4: + case KeyEvent.KEYCODE_BUTTON_5: + case KeyEvent.KEYCODE_BUTTON_6: + case KeyEvent.KEYCODE_BUTTON_7: + case KeyEvent.KEYCODE_BUTTON_8: + case KeyEvent.KEYCODE_BUTTON_9: + case KeyEvent.KEYCODE_BUTTON_10: + case KeyEvent.KEYCODE_BUTTON_11: + case KeyEvent.KEYCODE_BUTTON_12: + case KeyEvent.KEYCODE_BUTTON_13: + case KeyEvent.KEYCODE_BUTTON_14: + case KeyEvent.KEYCODE_BUTTON_15: + case KeyEvent.KEYCODE_BUTTON_16: + return true; + default: + return false; + } + } + /** {@inheritDoc} */ @Override public final int getDeviceId() { @@ -2554,7 +2592,7 @@ public class KeyEvent extends InputEvent implements Parcelable { /** * Returns a string that represents the symbolic name of the specified action - * such as "ACTION_DOWN", or "35" (if unknown). + * such as "ACTION_DOWN", or an equivalent numeric constant such as "35" if unknown. * * @param action The action. * @return The symbolic name of the specified action. @@ -2575,52 +2613,51 @@ public class KeyEvent extends InputEvent implements Parcelable { /** * Returns a string that represents the symbolic name of the specified keycode - * such as "KEYCODE_A", "KEYCODE_DPAD_UP", or "1001" (if unknown). + * such as "KEYCODE_A", "KEYCODE_DPAD_UP", or an equivalent numeric constant + * such as "1001" if unknown. * * @param keyCode The key code. * @return The symbolic name of the specified keycode. * * @see KeyCharacterMap#getDisplayLabel - * @hide */ public static String keyCodeToString(int keyCode) { - if (keyCode >= 0 && keyCode < KEYCODE_SYMBOLIC_NAMES.length) { - return KEYCODE_SYMBOLIC_NAMES[keyCode]; - } - return Integer.toString(keyCode); + String symbolicName = KEYCODE_SYMBOLIC_NAMES.get(keyCode); + return symbolicName != null ? symbolicName : Integer.toString(keyCode); } /** - * Gets a keycode by its symbolic name such as "KEYCODE_A" or "1001" (if unknown). + * Gets a keycode by its symbolic name such as "KEYCODE_A" or an equivalent + * numeric constant such as "1001". * * @param symbolicName The symbolic name of the keycode. - * @return The keycode or -1 if not found. + * @return The keycode or {@link #KEYCODE_UNKNOWN} if not found. * @see #keycodeToString - * @hide */ public static int keyCodeFromString(String symbolicName) { if (symbolicName == null) { throw new IllegalArgumentException("symbolicName must not be null"); } - final int count = KEYCODE_SYMBOLIC_NAMES.length; + final int count = KEYCODE_SYMBOLIC_NAMES.size(); for (int i = 0; i < count; i++) { - if (symbolicName.equals(KEYCODE_SYMBOLIC_NAMES[i])) { + if (symbolicName.equals(KEYCODE_SYMBOLIC_NAMES.valueAt(i))) { return i; } } try { - return Integer.parseInt(symbolicName,10); + return Integer.parseInt(symbolicName, 10); } catch (NumberFormatException ex) { - return -1; + return KEYCODE_UNKNOWN; } } /** * Returns a string that represents the symbolic name of the specified combined meta * key modifier state flags such as "0", "META_SHIFT_ON", - * "META_ALT_ON|META_SHIFT_ON" or "0x10000000" (if unknown). + * "META_ALT_ON|META_SHIFT_ON" or an equivalent numeric constant such as "0x10000000" + * if unknown. * * @param metaState The meta state. * @return The symbolic name of the specified combined meta state flags. diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 6673be2..a1326d2 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -20,6 +20,7 @@ import android.graphics.Matrix; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.util.SparseArray; /** * Object used to report movement (mouse, pen, finger, trackball) events. This @@ -263,10 +264,22 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the X axis of a motion event. - * - * The interpretation of the X axis varies by input source. - * It may represent the X position of the center of the touch contact area, - * a relative horizontal displacement of a trackball or joystick, or something else. + * <p> + * <ul> + * <li>For a touch screen, reports the absolute X screen position of the center of + * the touch contact area. The units are display pixels. + * <li>For a touch pad, reports the absolute X surface position of the center of the touch + * contact area. The units are device-specific because the touch pad is not necessarily + * associated with a display. Use {@link InputDevice#getMotionRange(int)} to query + * the effective range of values. + * <li>For a mouse, reports the absolute X screen position of the mouse pointer. + * The units are display pixels. + * <li>For a trackball, reports the relative horizontal displacement of the trackball. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + * <li>For a joystick, reports the absolute X position of the joystick. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + * </ul> + * </p> * * @see #getX(int) * @see #getHistoricalX(int, int) @@ -277,10 +290,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the Y axis of a motion event. - * - * The interpretation of the Y axis varies by input source. - * It may represent the Y position of the center of the touch contact area, - * a relative vertical displacement of a trackball or joystick, or something else. + * <p> + * <ul> + * <li>For a touch screen, reports the absolute Y screen position of the center of + * the touch contact area. The units are display pixels. + * <li>For a touch pad, reports the absolute Y surface position of the center of the touch + * contact area. The units are device-dependent; use {@link InputDevice#getMotionRange(int)} + * to query the effective range of values. + * <li>For a mouse, reports the absolute Y screen position of the mouse pointer. + * The units are display pixels. + * <li>For a trackball, reports the relative vertical displacement of the trackball. + * The value is normalized to a range from -1.0 (up) to 1.0 (down). + * <li>For a joystick, reports the absolute Y position of the joystick. + * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near). + * </ul> + * </p> * * @see #getY(int) * @see #getHistoricalY(int, int) @@ -291,12 +315,18 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the Pressure axis of a motion event. - * - * The pressure axis specifies a normalized value that describes the approximate - * pressure applied to the device by a finger or other tool. - * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), - * although values higher than 1 may be generated depending on the calibration of - * the input device. + * <p> + * <ul> + * <li>For a touch screen or touch pad, reports the approximate pressure applied to the device + * by a finger or other tool. The value is normalized to a range from + * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1 + * may be generated depending on the calibration of the input device. + * <li>For a trackball, the value is set to 1 if the trackball button is pressed + * or 0 otherwise. + * <li>For a mouse, the value is set to 1 if the primary mouse button is pressed + * or 0 otherwise. + * </ul> + * </p> * * @see #getPressure(int) * @see #getHistoricalPressure(int, int) @@ -307,17 +337,16 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the Size axis of a motion event. - * - * The size axis specifies a normalized value that describes the approximate size - * of the pointer touch area in relation to the maximum detectable size for the device. - * It represents some approximation of the area of the screen being - * pressed; the actual value in pixels corresponding to the - * touch is normalized with the device specific range of values - * and scaled to a value between 0 and 1. The value of size can be used to - * determine fat touch events. - * - * To obtain calibrated size information in terms of pixels, use - * {@link #AXIS_TOUCH_MAJOR} or {@link #AXIS_TOOL_MAJOR} instead. + * <p> + * <ul> + * <li>For a touch screen or touch pad, reports the approximate size of the contact area in + * relation to the maximum detectable size for the device. The value is normalized + * to a range from 0 (smallest detectable size) to 1 (largest detectable size), + * although it is not a linear scale. This value is of very limited use. + * To obtain calibrated size information, use + * {@link #AXIS_TOUCH_MAJOR} or {@link #AXIS_TOOL_MAJOR}. + * </ul> + * </p> * * @see #getSize(int) * @see #getHistoricalSize(int, int) @@ -328,11 +357,17 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the TouchMajor axis of a motion event. - * - * The touch major axis specifies the length of the major axis of an ellipse that - * describes the touch area at the point of contact. - * If the device is a touch screen, the length is reported in pixels, otherwise it is - * reported in device-specific units. + * <p> + * <ul> + * <li>For a touch screen, reports the length of the major axis of an ellipse that + * represents the touch area at the point of contact. + * The units are display pixels. + * <li>For a touch pad, reports the length of the major axis of an ellipse that + * represents the touch area at the point of contact. + * The units are device-dependent; use {@link InputDevice#getMotionRange(int)} + * to query the effective range of values. + * </ul> + * </p> * * @see #getTouchMajor(int) * @see #getHistoricalTouchMajor(int, int) @@ -343,11 +378,19 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the TouchMinor axis of a motion event. - * - * The touch major axis specifies the length of the minor axis of an ellipse that - * describes the touch area at the point of contact. - * If the device is a touch screen, the length is reported in pixels, otherwise it is - * reported in device-specific units. + * <p> + * <ul> + * <li>For a touch screen, reports the length of the minor axis of an ellipse that + * represents the touch area at the point of contact. + * The units are display pixels. + * <li>For a touch pad, reports the length of the minor axis of an ellipse that + * represents the touch area at the point of contact. + * The units are device-dependent; use {@link InputDevice#getMotionRange(int)} + * to query the effective range of values. + * </ul> + * </p><p> + * When the touch is circular, the major and minor axis lengths will be equal to one another. + * </p> * * @see #getTouchMinor(int) * @see #getHistoricalTouchMinor(int, int) @@ -358,13 +401,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the ToolMajor axis of a motion event. - * - * The tool major axis specifies the length of the major axis of an ellipse that - * describes the size of the approaching tool. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. - * If the device is a touch screen, the length is reported in pixels, otherwise it is - * reported in device-specific units. + * <p> + * <ul> + * <li>For a touch screen, reports the length of the major axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * <li>For a touch pad, reports the length of the major axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * The units are device-dependent; use {@link InputDevice#getMotionRange(int)} + * to query the effective range of values. + * </ul> + * </p><p> + * When the touch is circular, the major and minor axis lengths will be equal to one another. + * </p><p> + * The tool size may be larger than the touch size since the tool may not be fully + * in contact with the touch sensor. + * </p> * * @see #getToolMajor(int) * @see #getHistoricalToolMajor(int, int) @@ -375,13 +426,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the ToolMinor axis of a motion event. - * - * The tool minor axis specifies the length of the major axis of an ellipse that - * describes the size of the approaching tool. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. - * If the device is a touch screen, the length is reported in pixels, otherwise it is - * reported in device-specific units. + * <p> + * <ul> + * <li>For a touch screen, reports the length of the minor axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * <li>For a touch pad, reports the length of the minor axis of an ellipse that + * represents the size of the approaching finger or tool used to make contact. + * The units are device-dependent; use {@link InputDevice#getMotionRange(int)} + * to query the effective range of values. + * </ul> + * </p><p> + * When the touch is circular, the major and minor axis lengths will be equal to one another. + * </p><p> + * The tool size may be larger than the touch size since the tool may not be fully + * in contact with the touch sensor. + * </p> * * @see #getToolMinor(int) * @see #getHistoricalToolMinor(int, int) @@ -392,15 +451,18 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Constant used to identify the Orientation axis of a motion event. - * - * The orientation axis specifies the orientation of the touch area and tool area in - * radians clockwise from vertical relative to the vertical plane of the device. - * An angle of 0 degrees indicates that the major axis of contact is oriented + * <p> + * <ul> + * <li>For a touch screen or touch pad, reports the orientation of the finger + * or tool in radians relative to the vertical plane of the device. + * An angle of 0 radians indicates that the major axis of contact is oriented * upwards, is perfectly circular or is of unknown orientation. A positive angle * indicates that the major axis of contact is oriented to the right. A negative angle * indicates that the major axis of contact is oriented to the left. * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians * (finger pointing fully right). + * </ul> + * </p> * * @see #getOrientation(int) * @see #getHistoricalOrientation(int, int) @@ -409,6 +471,399 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public static final int AXIS_ORIENTATION = 8; + /** + * Constant used to identify the Vertical Scroll axis of a motion event. + * <p> + * <ul> + * <li>For a mouse, reports the relative movement of vertical scroll wheel. + * The value is normalized to a range from -1.0 (up) to 1.0 (down). + * </ul> + * </p><p> + * This axis should be used to scroll views vertically. + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_VSCROLL = 9; + + /** + * Constant used to identify the Horizontal Scroll axis of a motion event. + * <p> + * <ul> + * <li>For a mouse, reports the relative movement of horizontal scroll wheel. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + * </ul> + * </p><p> + * This axis should be used to scroll views horizontally. + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_HSCROLL = 10; + + /** + * Constant used to identify the Z axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute Z position of the joystick. + * The value is normalized to a range from -1.0 (high) to 1.0 (low). + * <em>On game pads with two analog joysticks, this axis is often reinterpreted + * to report the absolute X position of the second joystick instead.</em> + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_Z = 11; + + /** + * Constant used to identify the X Rotation axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute rotation angle about the X axis. + * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_RX = 12; + + /** + * Constant used to identify the Y Rotation axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute rotation angle about the Y axis. + * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_RY = 13; + + /** + * Constant used to identify the Z Rotation axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute rotation angle about the Z axis. + * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise). + * <em>On game pads with two analog joysticks, this axis is often reinterpreted + * to report the absolute Y position of the second joystick instead.</em> + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_RZ = 14; + + /** + * Constant used to identify the Hat X axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute X position of the directional hat control. + * The value is normalized to a range from -1.0 (left) to 1.0 (right). + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_HAT_X = 15; + + /** + * Constant used to identify the Hat Y axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute Y position of the directional hat control. + * The value is normalized to a range from -1.0 (up) to 1.0 (down). + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_HAT_Y = 16; + + /** + * Constant used to identify the Left Trigger axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute position of the left trigger control. + * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed). + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_LTRIGGER = 17; + + /** + * Constant used to identify the Right Trigger axis of a motion event. + * <p> + * <ul> + * <li>For a joystick, reports the absolute position of the right trigger control. + * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed). + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_RTRIGGER = 18; + + /** + * Constant used to identify the Generic 1 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_1 = 32; + + /** + * Constant used to identify the Generic 2 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_2 = 33; + + /** + * Constant used to identify the Generic 3 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_3 = 34; + + /** + * Constant used to identify the Generic 4 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_4 = 35; + + /** + * Constant used to identify the Generic 5 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_5 = 36; + + /** + * Constant used to identify the Generic 6 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_6 = 37; + + /** + * Constant used to identify the Generic 7 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_7 = 38; + + /** + * Constant used to identify the Generic 8 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_8 = 39; + + /** + * Constant used to identify the Generic 9 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_9 = 40; + + /** + * Constant used to identify the Generic 10 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_10 = 41; + + /** + * Constant used to identify the Generic 11 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_11 = 42; + + /** + * Constant used to identify the Generic 12 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_12 = 43; + + /** + * Constant used to identify the Generic 13 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_13 = 44; + + /** + * Constant used to identify the Generic 14 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_14 = 45; + + /** + * Constant used to identify the Generic 15 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_15 = 46; + + /** + * Constant used to identify the Generic 16 axis of a motion event. + * The interpretation of a generic axis is device-specific. + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_GENERIC_16 = 47; + + // NOTE: If you add a new axis here you must also add it to: + // native/include/android/input.h + // frameworks/base/include/ui/KeycodeLabels.h + + // Symbolic names of all axes. + private static final SparseArray<String> AXIS_SYMBOLIC_NAMES = new SparseArray<String>(); + private static void populateAxisSymbolicNames() { + SparseArray<String> names = AXIS_SYMBOLIC_NAMES; + names.append(AXIS_X, "AXIS_X"); + names.append(AXIS_Y, "AXIS_Y"); + names.append(AXIS_PRESSURE, "AXIS_PRESSURE"); + names.append(AXIS_SIZE, "AXIS_SIZE"); + names.append(AXIS_TOUCH_MAJOR, "AXIS_TOUCH_MAJOR"); + names.append(AXIS_TOUCH_MINOR, "AXIS_TOUCH_MINOR"); + names.append(AXIS_TOOL_MAJOR, "AXIS_TOOL_MAJOR"); + names.append(AXIS_TOOL_MINOR, "AXIS_TOOL_MINOR"); + names.append(AXIS_ORIENTATION, "AXIS_ORIENTATION"); + names.append(AXIS_VSCROLL, "AXIS_VSCROLL"); + names.append(AXIS_HSCROLL, "AXIS_HSCROLL"); + names.append(AXIS_Z, "AXIS_Z"); + names.append(AXIS_RX, "AXIS_RX"); + names.append(AXIS_RY, "AXIS_RY"); + names.append(AXIS_RZ, "AXIS_RZ"); + names.append(AXIS_HAT_X, "AXIS_HAT_X"); + names.append(AXIS_HAT_Y, "AXIS_HAT_Y"); + names.append(AXIS_LTRIGGER, "AXIS_LTRIGGER"); + names.append(AXIS_RTRIGGER, "AXIS_RTRIGGER"); + names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1"); + names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2"); + names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3"); + names.append(AXIS_GENERIC_4, "AXIS_GENERIC_4"); + names.append(AXIS_GENERIC_5, "AXIS_GENERIC_5"); + names.append(AXIS_GENERIC_6, "AXIS_GENERIC_6"); + names.append(AXIS_GENERIC_7, "AXIS_GENERIC_7"); + names.append(AXIS_GENERIC_8, "AXIS_GENERIC_8"); + names.append(AXIS_GENERIC_9, "AXIS_GENERIC_9"); + names.append(AXIS_GENERIC_10, "AXIS_GENERIC_10"); + names.append(AXIS_GENERIC_11, "AXIS_GENERIC_11"); + names.append(AXIS_GENERIC_12, "AXIS_GENERIC_12"); + names.append(AXIS_GENERIC_13, "AXIS_GENERIC_13"); + names.append(AXIS_GENERIC_14, "AXIS_GENERIC_14"); + names.append(AXIS_GENERIC_15, "AXIS_GENERIC_15"); + names.append(AXIS_GENERIC_16, "AXIS_GENERIC_16"); + } + + static { + populateAxisSymbolicNames(); + } + // Private value for history pos that obtains the current sample. private static final int HISTORY_CURRENT = -0x80000000; @@ -1081,7 +1536,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { * Returns the orientation of the touch area and tool area in radians clockwise from vertical * for the given pointer <em>index</em> (use {@link #getPointerId(int)} to find the pointer * identifier for this index). - * An angle of 0 degrees indicates that the major axis of contact is oriented + * An angle of 0 radians indicates that the major axis of contact is oriented * upwards, is perfectly circular or is of unknown orientation. A positive angle * indicates that the major axis of contact is oriented to the right. A negative angle * indicates that the major axis of contact is oriented to the left. @@ -1737,34 +2192,40 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Returns a string that represents the symbolic name of the specified axis - * such as "AXIS_X" or an equivalent numeric constants such as "42" if unknown. + * such as "AXIS_X" or an equivalent numeric constant such as "42" if unknown. * * @param axis The axis * @return The symbolic name of the specified axis. - * @hide */ public static String axisToString(int axis) { - switch (axis) { - case AXIS_X: - return "AXIS_X"; - case AXIS_Y: - return "AXIS_Y"; - case AXIS_PRESSURE: - return "AXIS_PRESSURE"; - case AXIS_SIZE: - return "AXIS_SIZE"; - case AXIS_TOUCH_MAJOR: - return "AXIS_TOUCH_MAJOR"; - case AXIS_TOUCH_MINOR: - return "AXIS_TOUCH_MINOR"; - case AXIS_TOOL_MAJOR: - return "AXIS_TOOL_MAJOR"; - case AXIS_TOOL_MINOR: - return "AXIS_TOOL_MINOR"; - case AXIS_ORIENTATION: - return "AXIS_ORIENTATION"; - default: - return Integer.toString(axis); + String symbolicName = AXIS_SYMBOLIC_NAMES.get(axis); + return symbolicName != null ? symbolicName : Integer.toString(axis); + } + + /** + * Gets an axis by its symbolic name such as "KEYCODE_A" or an + * equivalent numeric constant such as "1001". + * + * @param symbolicName The symbolic name of the axis. + * @return The axis or -1 if not found. + * @see #keycodeToString + */ + public static int axisFromString(String symbolicName) { + if (symbolicName == null) { + throw new IllegalArgumentException("symbolicName must not be null"); + } + + final int count = AXIS_SYMBOLIC_NAMES.size(); + for (int i = 0; i < count; i++) { + if (symbolicName.equals(AXIS_SYMBOLIC_NAMES.valueAt(i))) { + return i; + } + } + + try { + return Integer.parseInt(symbolicName, 10); + } catch (NumberFormatException ex) { + return -1; } } @@ -1803,7 +2264,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public static final class PointerCoords { private static final int INITIAL_PACKED_AXIS_VALUES = 8; - private int mPackedAxisBits; // 32bits are enough for now, can raise to 64bit when needed + private long mPackedAxisBits; private float[] mPackedAxisValues; /** @@ -1823,20 +2284,14 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** - * The X coordinate of the pointer movement. - * The interpretation of the X axis varies by input source. - * It may represent the X position of the center of the touch contact area, - * a relative horizontal displacement of a trackball or joystick, or something else. + * The X component of the pointer movement. * * @see MotionEvent#AXIS_X */ public float x; /** - * The Y coordinate of the pointer movement. - * The interpretation of the Y axis varies by input source. - * It may represent the Y position of the center of the touch contact area, - * a relative vertical displacement of a trackball or joystick, or something else. + * The Y component of the pointer movement. * * @see MotionEvent#AXIS_Y */ @@ -1912,7 +2367,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * The orientation of the touch area and tool area in radians clockwise from vertical. - * An angle of 0 degrees indicates that the major axis of contact is oriented + * An angle of 0 radians indicates that the major axis of contact is oriented * upwards, is perfectly circular or is of unknown orientation. A positive angle * indicates that the major axis of contact is oriented to the right. A negative angle * indicates that the major axis of contact is oriented to the left. @@ -1947,11 +2402,11 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @param other The pointer coords object to copy. */ public void copyFrom(PointerCoords other) { - final int bits = other.mPackedAxisBits; + final long bits = other.mPackedAxisBits; mPackedAxisBits = bits; if (bits != 0) { final float[] otherValues = other.mPackedAxisValues; - final int count = Integer.bitCount(bits); + final int count = Long.bitCount(bits); float[] values = mPackedAxisValues; if (values == null || count > values.length) { values = new float[otherValues.length]; @@ -2001,12 +2456,15 @@ public final class MotionEvent extends InputEvent implements Parcelable { case AXIS_ORIENTATION: return orientation; default: { - final int bits = mPackedAxisBits; - final int axisBit = 1 << axis; + if (axis < 0 || axis > 63) { + throw new IllegalArgumentException("Axis out of range."); + } + final long bits = mPackedAxisBits; + final long axisBit = 1L << axis; if ((bits & axisBit) == 0) { return 0; } - final int index = Integer.bitCount(bits & (axisBit - 1)); + final int index = Long.bitCount(bits & (axisBit - 1L)); return mPackedAxisValues[index]; } } @@ -2051,16 +2509,19 @@ public final class MotionEvent extends InputEvent implements Parcelable { orientation = value; break; default: { - final int bits = mPackedAxisBits; - final int axisBit = 1 << axis; - final int index = Integer.bitCount(bits & (axisBit - 1)); + if (axis < 0 || axis > 63) { + throw new IllegalArgumentException("Axis out of range."); + } + final long bits = mPackedAxisBits; + final long axisBit = 1L << axis; + final int index = Long.bitCount(bits & (axisBit - 1L)); float[] values = mPackedAxisValues; if ((bits & axisBit) == 0) { if (values == null) { values = new float[INITIAL_PACKED_AXIS_VALUES]; mPackedAxisValues = values; } else { - final int count = Integer.bitCount(bits); + final int count = Long.bitCount(bits); if (count < values.length) { if (index != count) { System.arraycopy(values, index, values, index + 1, diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index ec1a373..39f99b8 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -2496,7 +2496,6 @@ public final class ViewRoot extends Handler implements ViewParent, // Deliver the event to the view. if (mView.dispatchGenericMotionEvent(event)) { - ensureTouchMode(false); if (isJoystick) { updateJoystickDirection(event, false); } @@ -2525,8 +2524,16 @@ public final class ViewRoot extends Handler implements ViewParent, final int metaState = event.getMetaState(); final int deviceId = event.getDeviceId(); final int source = event.getSource(); - final int xDirection = joystickAxisValueToDirection(event.getX()); - final int yDirection = joystickAxisValueToDirection(event.getY()); + + int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X)); + if (xDirection == 0) { + xDirection = joystickAxisValueToDirection(event.getX()); + } + + int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y)); + if (yDirection == 0) { + yDirection = joystickAxisValueToDirection(event.getY()); + } if (xDirection != mLastJoystickXDirection) { if (mLastJoystickXKeyCode != 0) { diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index 0b765fd..4a6857c 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -327,7 +327,10 @@ public class PointerLocationView extends View { .append(" ToolMajor=").append(coords.toolMajor, 3) .append(" ToolMinor=").append(coords.toolMinor, 3) .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) - .append("deg").toString()); + .append("deg") + .append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1) + .append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1) + .toString()); } public void addTouchEvent(MotionEvent event) { diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 069e40b..5ba1cff 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -207,8 +207,7 @@ static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj, outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation)); - uint32_t bits = env->GetIntField(pointerCoordsObj, - gPointerCoordsClassInfo.mPackedAxisBits); + uint64_t bits = env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits); if (bits) { jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisValues)); @@ -219,7 +218,7 @@ static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj, uint32_t index = 0; do { uint32_t axis = __builtin_ctz(bits); - uint32_t axisBit = 1 << axis; + uint64_t axisBit = 1LL << axis; bits &= ~axisBit; outRawPointerCoords->setAxisValue(axis, values[index++]); } while (bits); @@ -272,21 +271,21 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation, rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - const uint32_t unpackedAxisBits = 0 - | (1 << AMOTION_EVENT_AXIS_X) - | (1 << AMOTION_EVENT_AXIS_Y) - | (1 << AMOTION_EVENT_AXIS_PRESSURE) - | (1 << AMOTION_EVENT_AXIS_SIZE) - | (1 << AMOTION_EVENT_AXIS_TOUCH_MAJOR) - | (1 << AMOTION_EVENT_AXIS_TOUCH_MINOR) - | (1 << AMOTION_EVENT_AXIS_TOOL_MAJOR) - | (1 << AMOTION_EVENT_AXIS_TOOL_MINOR) - | (1 << AMOTION_EVENT_AXIS_ORIENTATION); - - uint32_t outBits = 0; - uint32_t remainingBits = rawPointerCoords->bits & ~unpackedAxisBits; + const uint64_t unpackedAxisBits = 0 + | (1LL << AMOTION_EVENT_AXIS_X) + | (1LL << AMOTION_EVENT_AXIS_Y) + | (1LL << AMOTION_EVENT_AXIS_PRESSURE) + | (1LL << AMOTION_EVENT_AXIS_SIZE) + | (1LL << AMOTION_EVENT_AXIS_TOUCH_MAJOR) + | (1LL << AMOTION_EVENT_AXIS_TOUCH_MINOR) + | (1LL << AMOTION_EVENT_AXIS_TOOL_MAJOR) + | (1LL << AMOTION_EVENT_AXIS_TOOL_MINOR) + | (1LL << AMOTION_EVENT_AXIS_ORIENTATION); + + uint64_t outBits = 0; + uint64_t remainingBits = rawPointerCoords->bits & ~unpackedAxisBits; if (remainingBits) { - uint32_t packedAxesCount = __builtin_popcount(remainingBits); + uint32_t packedAxesCount = __builtin_popcountll(remainingBits); jfloatArray outValuesArray = obtainPackedAxisValuesArray(env, packedAxesCount, outPointerCoordsObj); if (!outValuesArray) { @@ -300,7 +299,7 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer uint32_t index = 0; do { uint32_t axis = __builtin_ctz(remainingBits); - uint32_t axisBit = 1 << axis; + uint64_t axisBit = 1LL << axis; remainingBits &= ~axisBit; outBits |= axisBit; outValues[index++] = rawPointerCoords->getAxisValue(axis); @@ -309,7 +308,7 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer env->ReleasePrimitiveArrayCritical(outValuesArray, outValues, 0); env->DeleteLocalRef(outValuesArray); } - env->SetIntField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits); + env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits); } @@ -758,7 +757,7 @@ int register_android_view_MotionEvent(JNIEnv* env) { FIND_CLASS(gPointerCoordsClassInfo.clazz, "android/view/MotionEvent$PointerCoords"); GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, gPointerCoordsClassInfo.clazz, - "mPackedAxisBits", "I"); + "mPackedAxisBits", "J"); GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, gPointerCoordsClassInfo.clazz, "mPackedAxisValues", "[F"); GET_FIELD_ID(gPointerCoordsClassInfo.x, gPointerCoordsClassInfo.clazz, diff --git a/data/keyboards/Android.mk b/data/keyboards/Android.mk index 8cba52d..a66a884 100644 --- a/data/keyboards/Android.mk +++ b/data/keyboards/Android.mk @@ -17,3 +17,21 @@ LOCAL_PATH := $(call my-dir) include $(LOCAL_PATH)/common.mk + +# Validate all key maps. +include $(CLEAR_VARS) + +validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX) +files := \ + $(foreach file,$(keylayouts),frameworks/base/data/keyboards/$(file)) \ + $(foreach file,$(keycharmaps),frameworks/base/data/keyboards/$(file)) \ + $(foreach file,$(keyconfigs),frameworks/base/data/keyboards/$(file)) + +LOCAL_MODULE := validate_framework_keymaps +LOCAL_MODULE_TAGS := optional +LOCAL_REQUIRED_MODULES := validatekeymaps + +validate_framework_keymaps: $(files) + $(hide) $(validatekeymaps) $(files) + +include $(BUILD_PHONY_PACKAGE) diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm index 14d7c80..51a8b27 100644 --- a/data/keyboards/Generic.kcm +++ b/data/keyboards/Generic.kcm @@ -545,3 +545,129 @@ key ESCAPE { meta: fallback HOME alt: fallback MENU } + +### Gamepad buttons ### + +key BUTTON_A { + base: fallback BACK +} + +key BUTTON_B { + base: fallback BACK +} + +key BUTTON_C { + base: fallback BACK +} + +key BUTTON_X { + base: fallback DPAD_CENTER +} + +key BUTTON_Y { + base: fallback DPAD_CENTER +} + +key BUTTON_Z { + base: fallback DPAD_CENTER +} + +key BUTTON_L1 { + base: none +} + +key BUTTON_R1 { + base: none +} + +key BUTTON_L2 { + base: none +} + +key BUTTON_R2 { + base: none +} + +key BUTTON_THUMBL { + base: fallback DPAD_CENTER +} + +key BUTTON_THUMBR { + base: fallback DPAD_CENTER +} + +key BUTTON_START { + base: fallback HOME +} + +key BUTTON_SELECT { + base: fallback MENU +} + +key BUTTON_MODE { + base: fallback MENU +} + +key BUTTON_1 { + base: fallback DPAD_CENTER +} + +key BUTTON_2 { + base: fallback DPAD_CENTER +} + +key BUTTON_3 { + base: fallback DPAD_CENTER +} + +key BUTTON_4 { + base: fallback DPAD_CENTER +} + +key BUTTON_5 { + base: fallback DPAD_CENTER +} + +key BUTTON_6 { + base: fallback DPAD_CENTER +} + +key BUTTON_7 { + base: fallback DPAD_CENTER +} + +key BUTTON_8 { + base: fallback DPAD_CENTER +} + +key BUTTON_9 { + base: fallback DPAD_CENTER +} + +key BUTTON_10 { + base: fallback DPAD_CENTER +} + +key BUTTON_11 { + base: fallback DPAD_CENTER +} + +key BUTTON_12 { + base: fallback DPAD_CENTER +} + +key BUTTON_13 { + base: fallback DPAD_CENTER +} + +key BUTTON_14 { + base: fallback DPAD_CENTER +} + +key BUTTON_15 { + base: fallback DPAD_CENTER +} + +key BUTTON_16 { + base: fallback DPAD_CENTER +} diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index 0aefc31..6d925d6 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -261,7 +261,6 @@ key 233 HEADSETHOOK # key 239 "KEY_KBDILLUMUP" # key 240 "KEY_UNKNOWN" - key 288 BUTTON_1 key 289 BUTTON_2 key 290 BUTTON_3 @@ -400,3 +399,16 @@ key 484 B FUNCTION # key 502 KEY_BRL_DOT6 # key 503 KEY_BRL_DOT7 # key 504 KEY_BRL_DOT8 + + +# Joystick and game controller axes. +# Axes that are not mapped will be assigned generic axis numbers by the input subsystem. +axis 0x00 X +axis 0x01 Y +axis 0x02 Z +axis 0x03 RX +axis 0x04 RY +axis 0x05 RZ +axis 0x10 HAT_X +axis 0x11 HAT_Y +
\ No newline at end of file diff --git a/data/keyboards/Vendor_046d_Product_c216.kl b/data/keyboards/Vendor_046d_Product_c216.kl new file mode 100644 index 0000000..6743323 --- /dev/null +++ b/data/keyboards/Vendor_046d_Product_c216.kl @@ -0,0 +1,37 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Logitech Dual Action Controller +# + +key 0x120 BUTTON_A +key 0x123 BUTTON_B +key 0x121 BUTTON_X +key 0x122 BUTTON_Y +key 0x124 BUTTON_L1 +key 0x125 BUTTON_R1 +key 0x126 BUTTON_L2 +key 0x127 BUTTON_R2 +key 0x128 BUTTON_SELECT +key 0x129 BUTTON_START +key 0x12a BUTTON_THUMBL +key 0x12b BUTTON_THUMBR + +axis 0x00 X +axis 0x01 Y +axis 0x02 Z +axis 0x05 RZ +axis 0x10 HAT_X +axis 0x11 HAT_Y diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl new file mode 100644 index 0000000..f8ac6a3 --- /dev/null +++ b/data/keyboards/Vendor_054c_Product_0268.kl @@ -0,0 +1,76 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Sony Playstation(R)3 Controller +# + +key 0x124 DPAD_UP +key 0x125 DPAD_RIGHT +key 0x126 DPAD_DOWN +key 0x127 DPAD_LEFT + +key 0x120 BUTTON_SELECT +key 0x123 BUTTON_START +key 0x12f BUTTON_A +key 0x12c BUTTON_B +key 0x12e BUTTON_X +key 0x12d BUTTON_Y +key 0x12a BUTTON_L1 +key 0x12b BUTTON_R1 +key 0x128 BUTTON_L2 +key 0x129 BUTTON_R2 +key 0x121 BUTTON_THUMBL +key 0x122 BUTTON_THUMBR + +# PS key +key 0x2d0 BUTTON_1 + +# Left Analog Stick +axis 0x00 X +axis 0x01 Y + +# Right Analog Stick +axis 0x02 Z +axis 0x05 RZ + +# DPAD +# axis 0x2c -HAT_Y +# axis 0x2d +HAT_X +# axis 0x2e +HAT_Y +# axis 0x2f -HAT_X + +# L2 trigger +axis 0x30 LTRIGGER + +# R2 trigger +axis 0x31 RTRIGGER + +# L1 trigger +# axis 0x32 + +# R1 trigger +# axis 0x33 + +# Triangle +# axis 0x34 + +# Circle +# axis 0x35 + +# Cross +# axis 0x36 + +# Square +# axis 0x37 diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk index 56c287a..5b367b9 100644 --- a/data/keyboards/common.mk +++ b/data/keyboards/common.mk @@ -19,7 +19,9 @@ keylayouts := \ Generic.kl \ AVRCP.kl \ qwerty.kl \ + Vendor_046d_Product_c216.kl \ Vendor_046d_Product_c532.kl \ + Vendor_054c_Product_0268.kl \ Vendor_05ac_Product_0239.kl \ Vendor_22b8_Product_093d.kl diff --git a/include/ui/Input.h b/include/ui/Input.h index cb9327e..86ce098 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -170,10 +170,10 @@ struct InputConfiguration { * Pointer coordinate data. */ struct PointerCoords { - enum { MAX_AXES = 15 }; // 15 so that sizeof(PointerCoords) == 16 * 4 == 64 + enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64 // Bitfield of axes that are present in this structure. - uint32_t bits; // 32bits are enough for now, can raise to 64bit when needed + uint64_t bits; // Values of axes that are stored in this structure packed in order by axis id // for each axis that is present in the structure according to 'bits'. @@ -183,41 +183,9 @@ struct PointerCoords { bits = 0; } - inline float getAxisValue(int32_t axis) const { - uint32_t axisBit = 1 << axis; - if (!(bits & axisBit)) { - return 0; - } - uint32_t index = __builtin_popcount(bits & (axisBit - 1)); - return values[index]; - } - - inline status_t setAxisValue(int32_t axis, float value) { - uint32_t axisBit = 1 << axis; - uint32_t index = __builtin_popcount(bits & (axisBit - 1)); - if (!(bits & axisBit)) { - uint32_t count = __builtin_popcount(bits); - if (count >= MAX_AXES) { - tooManyAxes(axis); - return NO_MEMORY; - } - bits |= axisBit; - for (uint32_t i = count; i > index; i--) { - values[i] = values[i - 1]; - } - } - values[index] = value; - return OK; - } - - inline float* editAxisValue(int32_t axis) { - uint32_t axisBit = 1 << axis; - if (!(bits & axisBit)) { - return NULL; - } - uint32_t index = __builtin_popcount(bits & (axisBit - 1)); - return &values[index]; - } + float getAxisValue(int32_t axis) const; + status_t setAxisValue(int32_t axis, float value); + float* editAxisValue(int32_t axis); #ifdef HAVE_ANDROID_OS status_t readFromParcel(Parcel* parcel); diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h index f0a6d00..904c8f3 100644 --- a/include/ui/KeyLayoutMap.h +++ b/include/ui/KeyLayoutMap.h @@ -25,7 +25,7 @@ namespace android { /** - * Describes a mapping from keyboard scan codes to Android key codes. + * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes. */ class KeyLayoutMap { public: @@ -33,8 +33,10 @@ public: static status_t load(const String8& filename, KeyLayoutMap** outMap); - status_t map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const; - status_t findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const; + status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const; + status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const; + + status_t mapAxis(int32_t scanCode, int32_t* axis) const; private: struct Key { @@ -42,7 +44,8 @@ private: uint32_t flags; }; - KeyedVector<int32_t,Key> mKeys; + KeyedVector<int32_t, Key> mKeys; + KeyedVector<int32_t, int32_t> mAxes; KeyLayoutMap(); @@ -57,6 +60,7 @@ private: private: status_t parseKey(); + status_t parseAxis(); }; }; diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h index 50296e2..54bc968 100644 --- a/include/ui/Keyboard.h +++ b/include/ui/Keyboard.h @@ -111,6 +111,18 @@ extern int32_t getKeyCodeByLabel(const char* label); extern uint32_t getKeyFlagByLabel(const char* label); /** + * Gets a axis by its short form label, eg. "X". + * Returns -1 if unknown. + */ +extern int32_t getAxisByLabel(const char* label); + +/** + * Gets a axis label by its id. + * Returns NULL if unknown. + */ +extern const char* getAxisLabel(int32_t axisId); + +/** * Updates a meta state field when a key is pressed or released. */ extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState); diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index dbccf29..bdfbf7c 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -250,4 +250,47 @@ static const KeycodeLabel FLAGS[] = { { NULL, 0 } }; +static const KeycodeLabel AXES[] = { + { "X", 0 }, + { "Y", 1 }, + { "PRESSURE", 2 }, + { "SIZE", 3 }, + { "TOUCH_MAJOR", 4 }, + { "TOUCH_MINOR", 5 }, + { "TOOL_MAJOR", 6 }, + { "TOOL_MINOR", 7 }, + { "ORIENTATION", 8 }, + { "VSCROLL", 9 }, + { "HSCROLL", 10 }, + { "Z", 11 }, + { "RX", 12 }, + { "RY", 13 }, + { "RZ", 14 }, + { "HAT_X", 15 }, + { "HAT_Y", 16 }, + { "LTRIGGER", 17 }, + { "RTRIGGER", 18 }, + { "GENERIC_1", 32 }, + { "GENERIC_2", 33 }, + { "GENERIC_3", 34 }, + { "GENERIC_4", 35 }, + { "GENERIC_5", 36 }, + { "GENERIC_6", 37 }, + { "GENERIC_7", 38 }, + { "GENERIC_8", 39 }, + { "GENERIC_9", 40 }, + { "GENERIC_10", 41 }, + { "GENERIC_11", 42 }, + { "GENERIC_12", 43 }, + { "GENERIC_13", 44 }, + { "GENERIC_14", 45 }, + { "GENERIC_15", 46 }, + { "GENERIC_16", 47 }, + + // NOTE: If you add a new axis here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. + + { NULL, -1 } +}; + #endif // _UI_KEYCODE_LABELS_H diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index e3107d5..a80320e 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -250,11 +250,59 @@ void KeyEvent::initialize(const KeyEvent& from) { // --- PointerCoords --- +float PointerCoords::getAxisValue(int32_t axis) const { + if (axis < 0 || axis > 63) { + return 0; + } + + uint64_t axisBit = 1LL << axis; + if (!(bits & axisBit)) { + return 0; + } + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + return values[index]; +} + +status_t PointerCoords::setAxisValue(int32_t axis, float value) { + if (axis < 0 || axis > 63) { + return NAME_NOT_FOUND; + } + + uint64_t axisBit = 1LL << axis; + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + if (!(bits & axisBit)) { + uint32_t count = __builtin_popcountll(bits); + if (count >= MAX_AXES) { + tooManyAxes(axis); + return NO_MEMORY; + } + bits |= axisBit; + for (uint32_t i = count; i > index; i--) { + values[i] = values[i - 1]; + } + } + values[index] = value; + return OK; +} + +float* PointerCoords::editAxisValue(int32_t axis) { + if (axis < 0 || axis > 63) { + return NULL; + } + + uint64_t axisBit = 1LL << axis; + if (!(bits & axisBit)) { + return NULL; + } + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + return &values[index]; +} + #ifdef HAVE_ANDROID_OS status_t PointerCoords::readFromParcel(Parcel* parcel) { - bits = parcel->readInt32(); + bits = parcel->readInt64(); - uint32_t count = __builtin_popcount(bits); + uint32_t count = __builtin_popcountll(bits); if (count > MAX_AXES) { return BAD_VALUE; } @@ -266,9 +314,9 @@ status_t PointerCoords::readFromParcel(Parcel* parcel) { } status_t PointerCoords::writeToParcel(Parcel* parcel) const { - parcel->writeInt32(bits); + parcel->writeInt64(bits); - uint32_t count = __builtin_popcount(bits); + uint32_t count = __builtin_popcountll(bits); for (uint32_t i = 0; i < count; i++) { parcel->writeInt32(values[i]); } diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp index 56bc26f..2ed0e66 100644 --- a/libs/ui/KeyLayoutMap.cpp +++ b/libs/ui/KeyLayoutMap.cpp @@ -82,11 +82,11 @@ status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) { return status; } -status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const { +status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const { ssize_t index = mKeys.indexOfKey(scanCode); if (index < 0) { #if DEBUG_MAPPING - LOGD("map: scanCode=%d ~ Failed.", scanCode); + LOGD("mapKey: scanCode=%d ~ Failed.", scanCode); #endif *keyCode = AKEYCODE_UNKNOWN; *flags = 0; @@ -98,12 +98,12 @@ status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) *flags = k.flags; #if DEBUG_MAPPING - LOGD("map: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags); + LOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags); #endif return NO_ERROR; } -status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const { +status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const { const size_t N = mKeys.size(); for (size_t i=0; i<N; i++) { if (mKeys.valueAt(i).keyCode == keyCode) { @@ -113,6 +113,25 @@ status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCo return NO_ERROR; } +status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) const { + ssize_t index = mAxes.indexOfKey(scanCode); + if (index < 0) { +#if DEBUG_MAPPING + LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); +#endif + *axis = -1; + return NAME_NOT_FOUND; + } + + *axis = mAxes.valueAt(index); + +#if DEBUG_MAPPING + LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis); +#endif + return NO_ERROR; +} + + // --- KeyLayoutMap::Parser --- KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : @@ -137,6 +156,10 @@ status_t KeyLayoutMap::Parser::parse() { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseKey(); if (status) return status; + } else if (keywordToken == "axis") { + mTokenizer->skipDelimiters(WHITESPACE); + status_t status = parseAxis(); + if (status) return status; } else { LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); @@ -162,12 +185,12 @@ status_t KeyLayoutMap::Parser::parseKey() { char* end; int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); if (*end) { - LOGE("%s: Expected scan code number, got '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; } if (mMap->mKeys.indexOfKey(scanCode) >= 0) { - LOGE("%s: Duplicate entry for scan code '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; } @@ -189,12 +212,12 @@ status_t KeyLayoutMap::Parser::parseKey() { String8 flagToken = mTokenizer->nextToken(WHITESPACE); uint32_t flag = getKeyFlagByLabel(flagToken.string()); if (!flag) { - LOGE("%s: Expected flag label, got '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } if (flags & flag) { - LOGE("%s: Duplicate flag '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } @@ -211,4 +234,35 @@ status_t KeyLayoutMap::Parser::parseKey() { return NO_ERROR; } +status_t KeyLayoutMap::Parser::parseAxis() { + String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); + char* end; + int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); + if (*end) { + LOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), + scanCodeToken.string()); + return BAD_VALUE; + } + if (mMap->mAxes.indexOfKey(scanCode) >= 0) { + LOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), + scanCodeToken.string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + String8 axisToken = mTokenizer->nextToken(WHITESPACE); + int32_t axis = getAxisByLabel(axisToken.string()); + if (axis < 0) { + LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(), + axisToken.string()); + return BAD_VALUE; + } + +#if DEBUG_PARSER + LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis); +#endif + mMap->mAxes.add(scanCode, axis); + return NO_ERROR; +} + }; diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp index 6faa600..8b6300a 100644 --- a/libs/ui/Keyboard.cpp +++ b/libs/ui/Keyboard.cpp @@ -217,7 +217,7 @@ status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFil return NAME_NOT_FOUND; } -static int lookupLabel(const char* literal, const KeycodeLabel *list) { +static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) { while (list->literal) { if (strcmp(literal, list->literal) == 0) { return list->value; @@ -227,12 +227,30 @@ static int lookupLabel(const char* literal, const KeycodeLabel *list) { return list->value; } +static const char* lookupLabelByValue(int value, const KeycodeLabel *list) { + while (list->literal) { + if (list->value == value) { + return list->literal; + } + list++; + } + return NULL; +} + int32_t getKeyCodeByLabel(const char* label) { - return int32_t(lookupLabel(label, KEYCODES)); + return int32_t(lookupValueByLabel(label, KEYCODES)); } uint32_t getKeyFlagByLabel(const char* label) { - return uint32_t(lookupLabel(label, FLAGS)); + return uint32_t(lookupValueByLabel(label, FLAGS)); +} + +int32_t getAxisByLabel(const char* label) { + return int32_t(lookupValueByLabel(label, AXES)); +} + +const char* getAxisLabel(int32_t axisId) { + return lookupLabelByValue(axisId, AXES); } static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) { diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp index 7b15c38..b77489e 100644 --- a/libs/ui/tests/InputEvent_test.cpp +++ b/libs/ui/tests/InputEvent_test.cpp @@ -18,6 +18,9 @@ #include <gtest/gtest.h> #include <binder/Parcel.h> +#include <math.h> +#include <SkMatrix.h> + namespace android { class BaseTest : public testing::Test { @@ -35,7 +38,7 @@ TEST_F(PointerCoordsTest, ClearSetsBitsToZero) { PointerCoords coords; coords.clear(); - ASSERT_EQ(0U, coords.bits); + ASSERT_EQ(0ULL, coords.bits); } TEST_F(PointerCoordsTest, AxisValues) { @@ -54,7 +57,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set first axis. ASSERT_EQ(OK, coords.setAxisValue(1, 5)); - ASSERT_EQ(0x00000002U, coords.bits); + ASSERT_EQ(0x00000002ULL, coords.bits); ASSERT_EQ(5, coords.values[0]); ASSERT_EQ(0, coords.getAxisValue(0)) @@ -64,7 +67,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an axis with a higher id than all others. (appending value at the end) ASSERT_EQ(OK, coords.setAxisValue(3, 2)); - ASSERT_EQ(0x0000000aU, coords.bits); + ASSERT_EQ(0x0000000aULL, coords.bits); ASSERT_EQ(5, coords.values[0]); ASSERT_EQ(2, coords.values[1]); @@ -79,7 +82,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an axis with an id lower than all others. (prepending value at beginning) ASSERT_EQ(OK, coords.setAxisValue(0, 4)); - ASSERT_EQ(0x0000000bU, coords.bits); + ASSERT_EQ(0x0000000bULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(5, coords.values[1]); ASSERT_EQ(2, coords.values[2]); @@ -104,7 +107,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an axis with an id between the others. (inserting value in the middle) ASSERT_EQ(OK, coords.setAxisValue(2, 1)); - ASSERT_EQ(0x0000000fU, coords.bits); + ASSERT_EQ(0x0000000fULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(7, coords.values[1]); ASSERT_EQ(1, coords.values[2]); @@ -121,7 +124,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an existing axis value in place. ASSERT_EQ(OK, coords.setAxisValue(1, 6)); - ASSERT_EQ(0x0000000fU, coords.bits); + ASSERT_EQ(0x0000000fULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(6, coords.values[1]); ASSERT_EQ(1, coords.values[2]); @@ -140,15 +143,15 @@ TEST_F(PointerCoordsTest, AxisValues) { for (size_t axis = 4; axis < PointerCoords::MAX_AXES; axis++) { ASSERT_EQ(OK, coords.setAxisValue(axis, axis)); } - ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcount(coords.bits)); + ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits)); // Try to set one more axis beyond maximum number. // Ensure bits are unchanged. ASSERT_EQ(NO_MEMORY, coords.setAxisValue(PointerCoords::MAX_AXES, 100)); - ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcount(coords.bits)); + ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits)); } -TEST_F(PointerCoordsTest, ReadAndWriteParcel) { +TEST_F(PointerCoordsTest, Parcel) { Parcel parcel; PointerCoords inCoords; @@ -160,7 +163,7 @@ TEST_F(PointerCoordsTest, ReadAndWriteParcel) { parcel.setDataPosition(0); outCoords.readFromParcel(&parcel); - ASSERT_EQ(0U, outCoords.bits); + ASSERT_EQ(0ULL, outCoords.bits); // Round trip with some values. parcel.freeData(); @@ -213,16 +216,22 @@ TEST_F(KeyEventTest, Properties) { // --- MotionEventTest --- class MotionEventTest : public BaseTest { +protected: + static const nsecs_t ARBITRARY_DOWN_TIME; + static const nsecs_t ARBITRARY_EVENT_TIME; + static const float X_OFFSET; + static const float Y_OFFSET; + + void initializeEventWithHistory(MotionEvent* event); + void assertEqualsEventWithHistory(const MotionEvent* event); }; -TEST_F(MotionEventTest, Properties) { - MotionEvent event; +const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1; +const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2; +const float MotionEventTest::X_OFFSET = 1.0f; +const float MotionEventTest::Y_OFFSET = 1.1f; - // Initialize, add samples and get properties. - const nsecs_t ARBITRARY_DOWN_TIME = 1; - const nsecs_t ARBITRARY_EVENT_TIME = 2; - const float X_OFFSET = 1.0f; - const float Y_OFFSET = 1.1f; +void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { int32_t pointerIds[] = { 1, 2 }; PointerCoords pointerCoords[2]; pointerCoords[0].clear(); @@ -245,7 +254,7 @@ TEST_F(MotionEventTest, Properties) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); - event.initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, + event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, @@ -270,7 +279,7 @@ TEST_F(MotionEventTest, Properties) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128); - event.addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords); + event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211); @@ -290,128 +299,284 @@ TEST_F(MotionEventTest, Properties) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228); - event.addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords); - - ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event.getType()); - ASSERT_EQ(2, event.getDeviceId()); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event.getSource()); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event.getAction()); - ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event.getFlags()); - ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event.getEdgeFlags()); - ASSERT_EQ(AMETA_ALT_ON, event.getMetaState()); - ASSERT_EQ(X_OFFSET, event.getXOffset()); - ASSERT_EQ(Y_OFFSET, event.getYOffset()); - ASSERT_EQ(2.0f, event.getXPrecision()); - ASSERT_EQ(2.1f, event.getYPrecision()); - ASSERT_EQ(ARBITRARY_DOWN_TIME, event.getDownTime()); - - ASSERT_EQ(2U, event.getPointerCount()); - ASSERT_EQ(1, event.getPointerId(0)); - ASSERT_EQ(2, event.getPointerId(1)); - - ASSERT_EQ(2U, event.getHistorySize()); - - // Get data. - ASSERT_EQ(ARBITRARY_EVENT_TIME, event.getHistoricalEventTime(0)); - ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event.getHistoricalEventTime(1)); - ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event.getEventTime()); + event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords); +} - ASSERT_EQ(11, event.getHistoricalRawPointerCoords(0, 0)-> +void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { + // Check properties. + ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()); + ASSERT_EQ(2, event->getDeviceId()); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource()); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction()); + ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags()); + ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags()); + ASSERT_EQ(AMETA_ALT_ON, event->getMetaState()); + ASSERT_EQ(X_OFFSET, event->getXOffset()); + ASSERT_EQ(Y_OFFSET, event->getYOffset()); + ASSERT_EQ(2.0f, event->getXPrecision()); + ASSERT_EQ(2.1f, event->getYPrecision()); + ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime()); + + ASSERT_EQ(2U, event->getPointerCount()); + ASSERT_EQ(1, event->getPointerId(0)); + ASSERT_EQ(2, event->getPointerId(1)); + + ASSERT_EQ(2U, event->getHistorySize()); + + // Check data. + ASSERT_EQ(ARBITRARY_EVENT_TIME, event->getHistoricalEventTime(0)); + ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1)); + ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime()); + + ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(21, event.getHistoricalRawPointerCoords(1, 0)-> + ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(111, event.getHistoricalRawPointerCoords(0, 1)-> + ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(121, event.getHistoricalRawPointerCoords(1, 1)-> + ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(211, event.getRawPointerCoords(0)-> + ASSERT_EQ(211, event->getRawPointerCoords(0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(221, event.getRawPointerCoords(1)-> + ASSERT_EQ(221, event->getRawPointerCoords(1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(11, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); - ASSERT_EQ(21, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); - ASSERT_EQ(111, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); - ASSERT_EQ(121, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); - ASSERT_EQ(211, event.getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); - ASSERT_EQ(221, event.getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); - - ASSERT_EQ(10, event.getHistoricalRawX(0, 0)); - ASSERT_EQ(20, event.getHistoricalRawX(1, 0)); - ASSERT_EQ(110, event.getHistoricalRawX(0, 1)); - ASSERT_EQ(120, event.getHistoricalRawX(1, 1)); - ASSERT_EQ(210, event.getRawX(0)); - ASSERT_EQ(220, event.getRawX(1)); - - ASSERT_EQ(11, event.getHistoricalRawY(0, 0)); - ASSERT_EQ(21, event.getHistoricalRawY(1, 0)); - ASSERT_EQ(111, event.getHistoricalRawY(0, 1)); - ASSERT_EQ(121, event.getHistoricalRawY(1, 1)); - ASSERT_EQ(211, event.getRawY(0)); - ASSERT_EQ(221, event.getRawY(1)); - - ASSERT_EQ(X_OFFSET + 10, event.getHistoricalX(0, 0)); - ASSERT_EQ(X_OFFSET + 20, event.getHistoricalX(1, 0)); - ASSERT_EQ(X_OFFSET + 110, event.getHistoricalX(0, 1)); - ASSERT_EQ(X_OFFSET + 120, event.getHistoricalX(1, 1)); - ASSERT_EQ(X_OFFSET + 210, event.getX(0)); - ASSERT_EQ(X_OFFSET + 220, event.getX(1)); - - ASSERT_EQ(Y_OFFSET + 11, event.getHistoricalY(0, 0)); - ASSERT_EQ(Y_OFFSET + 21, event.getHistoricalY(1, 0)); - ASSERT_EQ(Y_OFFSET + 111, event.getHistoricalY(0, 1)); - ASSERT_EQ(Y_OFFSET + 121, event.getHistoricalY(1, 1)); - ASSERT_EQ(Y_OFFSET + 211, event.getY(0)); - ASSERT_EQ(Y_OFFSET + 221, event.getY(1)); - - ASSERT_EQ(12, event.getHistoricalPressure(0, 0)); - ASSERT_EQ(22, event.getHistoricalPressure(1, 0)); - ASSERT_EQ(112, event.getHistoricalPressure(0, 1)); - ASSERT_EQ(122, event.getHistoricalPressure(1, 1)); - ASSERT_EQ(212, event.getPressure(0)); - ASSERT_EQ(222, event.getPressure(1)); + ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); + ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); + ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); + ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); + ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); + ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); + + ASSERT_EQ(10, event->getHistoricalRawX(0, 0)); + ASSERT_EQ(20, event->getHistoricalRawX(1, 0)); + ASSERT_EQ(110, event->getHistoricalRawX(0, 1)); + ASSERT_EQ(120, event->getHistoricalRawX(1, 1)); + ASSERT_EQ(210, event->getRawX(0)); + ASSERT_EQ(220, event->getRawX(1)); + + ASSERT_EQ(11, event->getHistoricalRawY(0, 0)); + ASSERT_EQ(21, event->getHistoricalRawY(1, 0)); + ASSERT_EQ(111, event->getHistoricalRawY(0, 1)); + ASSERT_EQ(121, event->getHistoricalRawY(1, 1)); + ASSERT_EQ(211, event->getRawY(0)); + ASSERT_EQ(221, event->getRawY(1)); + + ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0)); + ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0)); + ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1)); + ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1)); + ASSERT_EQ(X_OFFSET + 210, event->getX(0)); + ASSERT_EQ(X_OFFSET + 220, event->getX(1)); + + ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0)); + ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0)); + ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1)); + ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1)); + ASSERT_EQ(Y_OFFSET + 211, event->getY(0)); + ASSERT_EQ(Y_OFFSET + 221, event->getY(1)); + + ASSERT_EQ(12, event->getHistoricalPressure(0, 0)); + ASSERT_EQ(22, event->getHistoricalPressure(1, 0)); + ASSERT_EQ(112, event->getHistoricalPressure(0, 1)); + ASSERT_EQ(122, event->getHistoricalPressure(1, 1)); + ASSERT_EQ(212, event->getPressure(0)); + ASSERT_EQ(222, event->getPressure(1)); + + ASSERT_EQ(13, event->getHistoricalSize(0, 0)); + ASSERT_EQ(23, event->getHistoricalSize(1, 0)); + ASSERT_EQ(113, event->getHistoricalSize(0, 1)); + ASSERT_EQ(123, event->getHistoricalSize(1, 1)); + ASSERT_EQ(213, event->getSize(0)); + ASSERT_EQ(223, event->getSize(1)); + + ASSERT_EQ(14, event->getHistoricalTouchMajor(0, 0)); + ASSERT_EQ(24, event->getHistoricalTouchMajor(1, 0)); + ASSERT_EQ(114, event->getHistoricalTouchMajor(0, 1)); + ASSERT_EQ(124, event->getHistoricalTouchMajor(1, 1)); + ASSERT_EQ(214, event->getTouchMajor(0)); + ASSERT_EQ(224, event->getTouchMajor(1)); + + ASSERT_EQ(15, event->getHistoricalTouchMinor(0, 0)); + ASSERT_EQ(25, event->getHistoricalTouchMinor(1, 0)); + ASSERT_EQ(115, event->getHistoricalTouchMinor(0, 1)); + ASSERT_EQ(125, event->getHistoricalTouchMinor(1, 1)); + ASSERT_EQ(215, event->getTouchMinor(0)); + ASSERT_EQ(225, event->getTouchMinor(1)); + + ASSERT_EQ(16, event->getHistoricalToolMajor(0, 0)); + ASSERT_EQ(26, event->getHistoricalToolMajor(1, 0)); + ASSERT_EQ(116, event->getHistoricalToolMajor(0, 1)); + ASSERT_EQ(126, event->getHistoricalToolMajor(1, 1)); + ASSERT_EQ(216, event->getToolMajor(0)); + ASSERT_EQ(226, event->getToolMajor(1)); + + ASSERT_EQ(17, event->getHistoricalToolMinor(0, 0)); + ASSERT_EQ(27, event->getHistoricalToolMinor(1, 0)); + ASSERT_EQ(117, event->getHistoricalToolMinor(0, 1)); + ASSERT_EQ(127, event->getHistoricalToolMinor(1, 1)); + ASSERT_EQ(217, event->getToolMinor(0)); + ASSERT_EQ(227, event->getToolMinor(1)); + + ASSERT_EQ(18, event->getHistoricalOrientation(0, 0)); + ASSERT_EQ(28, event->getHistoricalOrientation(1, 0)); + ASSERT_EQ(118, event->getHistoricalOrientation(0, 1)); + ASSERT_EQ(128, event->getHistoricalOrientation(1, 1)); + ASSERT_EQ(218, event->getOrientation(0)); + ASSERT_EQ(228, event->getOrientation(1)); +} + +TEST_F(MotionEventTest, Properties) { + MotionEvent event; + + // Initialize, add samples and check properties. + initializeEventWithHistory(&event); + ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event)); + + // Set source. + event.setSource(AINPUT_SOURCE_JOYSTICK); + ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); + + // Set action. + event.setAction(AMOTION_EVENT_ACTION_CANCEL); + ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction()); + + // Set meta state. + event.setMetaState(AMETA_CTRL_ON); + ASSERT_EQ(AMETA_CTRL_ON, event.getMetaState()); +} + +TEST_F(MotionEventTest, CopyFrom_KeepHistory) { + MotionEvent event; + initializeEventWithHistory(&event); + + MotionEvent copy; + copy.copyFrom(&event, true /*keepHistory*/); + + ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event)); +} + +TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) { + MotionEvent event; + initializeEventWithHistory(&event); + + MotionEvent copy; + copy.copyFrom(&event, false /*keepHistory*/); + + ASSERT_EQ(event.getPointerCount(), copy.getPointerCount()); + ASSERT_EQ(0U, copy.getHistorySize()); + + ASSERT_EQ(event.getPointerId(0), copy.getPointerId(0)); + ASSERT_EQ(event.getPointerId(1), copy.getPointerId(1)); + + ASSERT_EQ(event.getEventTime(), copy.getEventTime()); + + ASSERT_EQ(event.getX(0), copy.getX(0)); +} + +TEST_F(MotionEventTest, OffsetLocation) { + MotionEvent event; + initializeEventWithHistory(&event); + + event.offsetLocation(5.0f, -2.0f); + + ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset()); + ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset()); +} + +TEST_F(MotionEventTest, Scale) { + MotionEvent event; + initializeEventWithHistory(&event); - ASSERT_EQ(13, event.getHistoricalSize(0, 0)); - ASSERT_EQ(23, event.getHistoricalSize(1, 0)); - ASSERT_EQ(113, event.getHistoricalSize(0, 1)); - ASSERT_EQ(123, event.getHistoricalSize(1, 1)); + event.scale(2.0f); + + ASSERT_EQ(X_OFFSET * 2, event.getXOffset()); + ASSERT_EQ(Y_OFFSET * 2, event.getYOffset()); + + ASSERT_EQ(210 * 2, event.getRawX(0)); + ASSERT_EQ(211 * 2, event.getRawY(0)); + ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0)); + ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0)); + ASSERT_EQ(212, event.getPressure(0)); ASSERT_EQ(213, event.getSize(0)); - ASSERT_EQ(223, event.getSize(1)); - - ASSERT_EQ(14, event.getHistoricalTouchMajor(0, 0)); - ASSERT_EQ(24, event.getHistoricalTouchMajor(1, 0)); - ASSERT_EQ(114, event.getHistoricalTouchMajor(0, 1)); - ASSERT_EQ(124, event.getHistoricalTouchMajor(1, 1)); - ASSERT_EQ(214, event.getTouchMajor(0)); - ASSERT_EQ(224, event.getTouchMajor(1)); - - ASSERT_EQ(15, event.getHistoricalTouchMinor(0, 0)); - ASSERT_EQ(25, event.getHistoricalTouchMinor(1, 0)); - ASSERT_EQ(115, event.getHistoricalTouchMinor(0, 1)); - ASSERT_EQ(125, event.getHistoricalTouchMinor(1, 1)); - ASSERT_EQ(215, event.getTouchMinor(0)); - ASSERT_EQ(225, event.getTouchMinor(1)); - - ASSERT_EQ(16, event.getHistoricalToolMajor(0, 0)); - ASSERT_EQ(26, event.getHistoricalToolMajor(1, 0)); - ASSERT_EQ(116, event.getHistoricalToolMajor(0, 1)); - ASSERT_EQ(126, event.getHistoricalToolMajor(1, 1)); - ASSERT_EQ(216, event.getToolMajor(0)); - ASSERT_EQ(226, event.getToolMajor(1)); - - ASSERT_EQ(17, event.getHistoricalToolMinor(0, 0)); - ASSERT_EQ(27, event.getHistoricalToolMinor(1, 0)); - ASSERT_EQ(117, event.getHistoricalToolMinor(0, 1)); - ASSERT_EQ(127, event.getHistoricalToolMinor(1, 1)); - ASSERT_EQ(217, event.getToolMinor(0)); - ASSERT_EQ(227, event.getToolMinor(1)); - - ASSERT_EQ(18, event.getHistoricalOrientation(0, 0)); - ASSERT_EQ(28, event.getHistoricalOrientation(1, 0)); - ASSERT_EQ(118, event.getHistoricalOrientation(0, 1)); - ASSERT_EQ(128, event.getHistoricalOrientation(1, 1)); + ASSERT_EQ(214 * 2, event.getTouchMajor(0)); + ASSERT_EQ(215 * 2, event.getTouchMinor(0)); + ASSERT_EQ(216 * 2, event.getToolMajor(0)); + ASSERT_EQ(217 * 2, event.getToolMinor(0)); ASSERT_EQ(218, event.getOrientation(0)); - ASSERT_EQ(228, event.getOrientation(1)); +} + +TEST_F(MotionEventTest, Parcel) { + Parcel parcel; + + MotionEvent inEvent; + initializeEventWithHistory(&inEvent); + MotionEvent outEvent; + + // Round trip. + inEvent.writeToParcel(&parcel); + parcel.setDataPosition(0); + outEvent.readFromParcel(&parcel); + + ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent)); +} + +TEST_F(MotionEventTest, Transform) { + // Generate some points on a circle. + // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle + // of ARC * i degrees clockwise relative to the Y axis. + // The geometrical representation is irrelevant to the test, it's just easy to generate + // and check rotation. We set the orientation to the same angle. + // Coordinate system: down is increasing Y, right is increasing X. + const float PI_180 = float(M_PI / 180); + const float RADIUS = 10; + const float ARC = 36; + const float ROTATION = ARC * 2; + + const size_t pointerCount = 11; + int pointerIds[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + float angle = float(i * ARC * PI_180); + pointerIds[i] = i; + pointerCoords[i].clear(); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); + } + MotionEvent event; + event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, + 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + float originalRawX = 0 + 3; + float originalRawY = -RADIUS + 2; + + // Check original raw X and Y assumption. + ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); + ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); + + // Now translate the motion event so the circle's origin is at (0,0). + event.offsetLocation(-3, -2); + + // Offsetting the location should preserve the raw X and Y of the first point. + ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); + ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); + + // Apply a rotation about the origin by ROTATION degrees clockwise. + SkMatrix matrix; + matrix.setRotate(ROTATION); + event.transform(&matrix); + + // Check the points. + for (size_t i = 0; i < pointerCount; i++) { + float angle = float((i * ARC + ROTATION) * PI_180); + ASSERT_NEAR(sinf(angle) * RADIUS, event.getX(i), 0.001); + ASSERT_NEAR(-cosf(angle) * RADIUS, event.getY(i), 0.001); + ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1); + } + + // Applying the transformation should preserve the raw X and Y of the first point. + ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); + ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } } // namespace android diff --git a/native/include/android/input.h b/native/include/android/input.h index ee05020..d531489 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -322,6 +322,7 @@ enum { /* * Constants that identify each individual axis of a motion event. + * Refer to the documentation on the MotionEvent class for descriptions of each axis. */ enum { AMOTION_EVENT_AXIS_X = 0, @@ -333,6 +334,35 @@ enum { AMOTION_EVENT_AXIS_TOOL_MAJOR = 6, AMOTION_EVENT_AXIS_TOOL_MINOR = 7, AMOTION_EVENT_AXIS_ORIENTATION = 8, + AMOTION_EVENT_AXIS_VSCROLL = 9, + AMOTION_EVENT_AXIS_HSCROLL = 10, + AMOTION_EVENT_AXIS_Z = 11, + AMOTION_EVENT_AXIS_RX = 12, + AMOTION_EVENT_AXIS_RY = 13, + AMOTION_EVENT_AXIS_RZ = 14, + AMOTION_EVENT_AXIS_HAT_X = 15, + AMOTION_EVENT_AXIS_HAT_Y = 16, + AMOTION_EVENT_AXIS_LTRIGGER = 17, + AMOTION_EVENT_AXIS_RTRIGGER = 18, + AMOTION_EVENT_AXIS_GENERIC_1 = 32, + AMOTION_EVENT_AXIS_GENERIC_2 = 33, + AMOTION_EVENT_AXIS_GENERIC_3 = 34, + AMOTION_EVENT_AXIS_GENERIC_4 = 35, + AMOTION_EVENT_AXIS_GENERIC_5 = 36, + AMOTION_EVENT_AXIS_GENERIC_6 = 37, + AMOTION_EVENT_AXIS_GENERIC_7 = 38, + AMOTION_EVENT_AXIS_GENERIC_8 = 39, + AMOTION_EVENT_AXIS_GENERIC_9 = 40, + AMOTION_EVENT_AXIS_GENERIC_10 = 41, + AMOTION_EVENT_AXIS_GENERIC_11 = 42, + AMOTION_EVENT_AXIS_GENERIC_12 = 43, + AMOTION_EVENT_AXIS_GENERIC_13 = 44, + AMOTION_EVENT_AXIS_GENERIC_14 = 45, + AMOTION_EVENT_AXIS_GENERIC_15 = 46, + AMOTION_EVENT_AXIS_GENERIC_16 = 47, + + // NOTE: If you add a new axis here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. }; /* diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 066daa8..c921425 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -117,6 +117,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_POINTER; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; +import android.view.KeyCharacterMap.FallbackAction; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.media.IAudioService; @@ -1453,7 +1454,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // Check for fallback actions. - if (kcm.getFallbackAction(keyCode, metaState, mFallbackAction)) { + if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) { if (DEBUG_FALLBACK) { Slog.d(TAG, "Fallback: keyCode=" + mFallbackAction.keyCode + " metaState=" + Integer.toHexString(mFallbackAction.metaState)); @@ -1485,6 +1486,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { return null; } + private boolean getFallbackAction(KeyCharacterMap kcm, int keyCode, int metaState, + FallbackAction outFallbackAction) { + // Consult the key character map for specific fallback actions. + // For example, map NUMPAD_1 to MOVE_HOME when NUMLOCK is not pressed. + if (kcm.getFallbackAction(keyCode, metaState, outFallbackAction)) { + return true; + } + return false; + } + /** * A home key -> launch home action was detected. Take the appropriate action * given the situation with the keyguard. diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 38a896f..f79d106 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -127,9 +127,7 @@ EventHub::EventHub(void) : mOpened(false), mNeedToSendFinishedDeviceScan(false), mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); -#ifdef EV_SW memset(mSwitches, 0, sizeof(mSwitches)); -#endif } EventHub::~EventHub(void) { @@ -229,7 +227,7 @@ int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const { } Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->findScanCodes(keyCode, &scanCodes); + device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); @@ -253,7 +251,6 @@ int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const { } int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { -#ifdef EV_SW if (sw >= 0 && sw <= SW_MAX) { AutoMutex _l(mLock); @@ -262,7 +259,6 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { return getSwitchStateLocked(device, sw); } } -#endif return AKEY_STATE_UNKNOWN; } @@ -297,7 +293,8 @@ bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes, for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { scanCodes.clear(); - status_t err = device->keyMap.keyLayoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes); + status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( + keyCodes[codeIndex], &scanCodes); if (! err) { // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver @@ -312,14 +309,14 @@ bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes, return true; } -status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, +status_t EventHub::mapKey(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags); + status_t err = device->keyMap.keyLayoutMap->mapKey(scancode, outKeycode, outFlags); if (err == NO_ERROR) { return NO_ERROR; } @@ -329,7 +326,7 @@ status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, device = getDeviceLocked(mBuiltInKeyboardId); if (device && device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags); + status_t err = device->keyMap.keyLayoutMap->mapKey(scancode, outKeycode, outFlags); if (err == NO_ERROR) { return NO_ERROR; } @@ -341,6 +338,34 @@ status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, return NAME_NOT_FOUND; } +status_t EventHub::mapAxis(int32_t deviceId, int scancode, + int32_t* outAxis) const +{ + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + + if (device && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis); + if (err == NO_ERROR) { + return NO_ERROR; + } + } + + if (mBuiltInKeyboardId != -1) { + device = getDeviceLocked(mBuiltInKeyboardId); + + if (device && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis); + if (err == NO_ERROR) { + return NO_ERROR; + } + } + } + + *outAxis = -1; + return NAME_NOT_FOUND; +} + void EventHub::addExcludedDevice(const char* deviceName) { AutoMutex _l(mLock); @@ -488,7 +513,7 @@ bool EventHub::getEvent(RawEvent* outEvent) { if (iev.type == EV_KEY) { outEvent->keyCode = AKEYCODE_UNKNOWN; if (device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->map(iev.code, + status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code, &outEvent->keyCode, &outEvent->flags); LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", iev.code, outEvent->keyCode, outEvent->flags, err); @@ -731,86 +756,79 @@ int EventHub::openDevice(const char *devicePath) { loadConfiguration(device); // Figure out the kinds of events the device reports. - uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); + ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask); - LOGV("Getting keys..."); - if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { - //LOGI("MAP\n"); - //for (int i = 0; i < sizeof(key_bitmask); i++) { - // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); - //} - - // See if this is a keyboard. Ignore everything in the button range except for - // joystick and gamepad buttons which are also considered keyboards. - if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC)) - || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK), - sizeof_bit_array(BTN_DIGI)) - || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK), - sizeof_bit_array(KEY_MAX + 1))) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; + uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)]; + memset(abs_bitmask, 0, sizeof(abs_bitmask)); + ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask); - device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; - if (device->keyBitmask != NULL) { - memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); - } else { - delete device; - LOGE("out of memory allocating key bitmask"); - return -1; - } + uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)]; + memset(rel_bitmask, 0, sizeof(rel_bitmask)); + ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask); + + uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; + memset(sw_bitmask, 0, sizeof(sw_bitmask)); + ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask); + + // See if this is a keyboard. Ignore everything in the button range except for + // joystick and gamepad buttons which are handled like keyboards for the most part. + bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC)) + || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK), + sizeof_bit_array(KEY_MAX + 1)); + bool haveGamepadButtons =containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK), + sizeof_bit_array(BTN_DIGI)); + if (haveKeyboardKeys || haveGamepadButtons) { + device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; + device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; + if (device->keyBitmask != NULL) { + memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); + } else { + delete device; + LOGE("out of memory allocating key bitmask"); + return -1; } } - + // See if this is a cursor device such as a trackball or mouse. - if (test_bit(BTN_MOUSE, key_bitmask)) { - uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)]; - memset(rel_bitmask, 0, sizeof(rel_bitmask)); - LOGV("Getting relative controllers..."); - if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) { - if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) { - device->classes |= INPUT_DEVICE_CLASS_CURSOR; - } - } + if (test_bit(BTN_MOUSE, key_bitmask) + && test_bit(REL_X, rel_bitmask) + && test_bit(REL_Y, rel_bitmask)) { + device->classes |= INPUT_DEVICE_CLASS_CURSOR; } // See if this is a touch pad. - uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)]; - memset(abs_bitmask, 0, sizeof(abs_bitmask)); - LOGV("Getting absolute controllers..."); - if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) { - // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_POSITION_X, abs_bitmask) - && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { + // Is this a new modern multi-touch driver? + if (test_bit(ABS_MT_POSITION_X, abs_bitmask) + && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { + // Some joysticks such as the PS3 controller report axes that conflict + // with the ABS_MT range. Try to confirm that the device really is + // a touch screen. + if (test_bit(BTN_TOUCH, key_bitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; - - // Is this an old style single-touch driver? - } else if (test_bit(BTN_TOUCH, key_bitmask) - && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TOUCH; } + // Is this an old style single-touch driver? + } else if (test_bit(BTN_TOUCH, key_bitmask) + && test_bit(ABS_X, abs_bitmask) + && test_bit(ABS_Y, abs_bitmask)) { + device->classes |= INPUT_DEVICE_CLASS_TOUCH; } -#ifdef EV_SW // figure out the switches this device reports - uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; - memset(sw_bitmask, 0, sizeof(sw_bitmask)); - bool hasSwitches = false; - if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { - for (int i=0; i<EV_SW; i++) { - //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); - if (test_bit(i, sw_bitmask)) { - hasSwitches = true; - if (mSwitches[i] == 0) { - mSwitches[i] = device->id; - } + bool haveSwitches = false; + for (int i=0; i<EV_SW; i++) { + //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); + if (test_bit(i, sw_bitmask)) { + haveSwitches = true; + if (mSwitches[i] == 0) { + mSwitches[i] = device->id; } } } - if (hasSwitches) { + if (haveSwitches) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; } -#endif if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { // Load the virtual keys for the touch screen, if any. @@ -862,12 +880,10 @@ int EventHub::openDevice(const char *devicePath) { // See if this device is a joystick. // Ignore touchscreens because they use the same absolute axes for other purposes. + // Assumes that joysticks always have buttons and the keymap has been loaded. if (device->classes & INPUT_DEVICE_CLASS_GAMEPAD && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)) { - if (test_bit(ABS_X, abs_bitmask) - || test_bit(ABS_Y, abs_bitmask) - || test_bit(ABS_HAT0X, abs_bitmask) - || test_bit(ABS_HAT0Y, abs_bitmask)) { + if (containsNonZeroByte(abs_bitmask, 0, sizeof_bit_array(ABS_MAX + 1))) { device->classes |= INPUT_DEVICE_CLASS_JOYSTICK; } } @@ -950,7 +966,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { } Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->findScanCodes(keycode, &scanCodes); + device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); const size_t N = scanCodes.size(); for (size_t i=0; i<N && i<=KEY_MAX; i++) { int32_t sc = scanCodes.itemAt(i); @@ -972,13 +988,11 @@ int EventHub::closeDevice(const char *devicePath) { device->path.string(), device->identifier.name.string(), device->id, device->fd, device->classes); -#ifdef EV_SW for (int j=0; j<EV_SW; j++) { if (mSwitches[j] == device->id) { mSwitches[j] = 0; } } -#endif if (device->id == mBuiltInKeyboardId) { LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 52993f7..35712f5 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -167,9 +167,12 @@ public: virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const = 0; - virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, + virtual status_t mapKey(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const = 0; + virtual status_t mapAxis(int32_t deviceId, int scancode, + int32_t* outAxis) const = 0; + // exclude a particular device from opening // this can be used to ignore input devices for sensors virtual void addExcludedDevice(const char* deviceName) = 0; @@ -221,9 +224,12 @@ public: virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const; - virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, + virtual status_t mapKey(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const; + virtual status_t mapAxis(int32_t deviceId, int scancode, + int32_t* outAxis) const; + virtual void addExcludedDevice(const char* deviceName); virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; @@ -314,9 +320,7 @@ private: List<String8> mExcludedDevices; // device ids that report particular switches. -#ifdef EV_SW int32_t mSwitches[SW_MAX + 1]; -#endif static const int INPUT_BUFFER_SIZE = 64; struct input_event mInputBufferData[INPUT_BUFFER_SIZE]; diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 8f38cb2..47cfa05 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -584,15 +584,15 @@ void InputDevice::dump(String8& dump) { dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); if (!deviceInfo.getMotionRanges().isEmpty()) { dump.append(INDENT2 "Motion Ranges:\n"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_X, "X"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_Y, "Y"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_PRESSURE, "Pressure"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_SIZE, "Size"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MAJOR, "TouchMajor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MINOR, "TouchMinor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MAJOR, "ToolMajor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MINOR, "ToolMinor"); - dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_ORIENTATION, "Orientation"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_X, "X"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_Y, "Y"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_PRESSURE, "Pressure"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_SIZE, "Size"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOUCH_MAJOR, "TouchMajor"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOUCH_MINOR, "TouchMinor"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOOL_MAJOR, "ToolMajor"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOOL_MINOR, "ToolMinor"); + dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_ORIENTATION, "Orientation"); } size_t numMappers = mMappers.size(); @@ -1061,14 +1061,21 @@ void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { if (mParameters.mode == Parameters::MODE_POINTER) { float minX, minY, maxX, maxY; if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AINPUT_MOTION_RANGE_X, minX, maxX, 0.0f, 0.0f); - info->addMotionRange(AINPUT_MOTION_RANGE_Y, minY, maxY, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_X, minX, maxX, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, minY, maxY, 0.0f, 0.0f); } } else { - info->addMotionRange(AINPUT_MOTION_RANGE_X, -1.0f, 1.0f, 0.0f, mXScale); - info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale); + info->addMotionRange(AMOTION_EVENT_AXIS_X, -1.0f, 1.0f, 0.0f, mXScale); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, -1.0f, 1.0f, 0.0f, mYScale); + } + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f); + + if (mHaveVWheel) { + info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, -1.0f, 1.0f, 0.0f, 0.0f); + } + if (mHaveHWheel) { + info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, -1.0f, 1.0f, 0.0f, 0.0f); } - info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f); } void CursorInputMapper::dump(String8& dump) { @@ -1076,8 +1083,14 @@ void CursorInputMapper::dump(String8& dump) { AutoMutex _l(mLock); dump.append(INDENT2 "Cursor Input Mapper:\n"); dumpParameters(dump); + dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale); + dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale); dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); + dump.appendFormat(INDENT3 "HaveVWheel: %s\n", toString(mHaveVWheel)); + dump.appendFormat(INDENT3 "HaveHWheel: %s\n", toString(mHaveHWheel)); + dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); + dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down)); dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime); } // release lock @@ -1107,6 +1120,9 @@ void CursorInputMapper::configure() { mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; break; } + + mVWheelScale = 1.0f; + mHWheelScale = 1.0f; } void CursorInputMapper::configureParameters() { @@ -1200,6 +1216,14 @@ void CursorInputMapper::process(const RawEvent* rawEvent) { mAccumulator.fields |= Accumulator::FIELD_REL_Y; mAccumulator.relY = rawEvent->value; break; + case REL_WHEEL: + mAccumulator.fields |= Accumulator::FIELD_REL_WHEEL; + mAccumulator.relWheel = rawEvent->value; + break; + case REL_HWHEEL: + mAccumulator.fields |= Accumulator::FIELD_REL_HWHEEL; + mAccumulator.relHWheel = rawEvent->value; + break; } break; @@ -1302,6 +1326,13 @@ void CursorInputMapper::sync(nsecs_t when) { } pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mLocked.down ? 1.0f : 0.0f); + + if (mHaveVWheel && (fields & Accumulator::FIELD_REL_WHEEL)) { + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, mAccumulator.relWheel); + } + if (mHaveHWheel && (fields & Accumulator::FIELD_REL_HWHEEL)) { + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, mAccumulator.relHWheel); + } } // release lock int32_t metaState = mContext->getGlobalMetaState(); @@ -1350,35 +1381,35 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { // noticed immediately. configureSurfaceLocked(); - info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x); - info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y); + info->addMotionRange(AMOTION_EVENT_AXIS_X, mLocked.orientedRanges.x); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mLocked.orientedRanges.y); if (mLocked.orientedRanges.havePressure) { - info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mLocked.orientedRanges.pressure); } if (mLocked.orientedRanges.haveSize) { - info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, + info->addMotionRange(AMOTION_EVENT_AXIS_SIZE, mLocked.orientedRanges.size); } if (mLocked.orientedRanges.haveTouchSize) { - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, + info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, mLocked.orientedRanges.touchMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, + info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR, mLocked.orientedRanges.touchMinor); } if (mLocked.orientedRanges.haveToolSize) { - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, + info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MAJOR, mLocked.orientedRanges.toolMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, + info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MINOR, mLocked.orientedRanges.toolMinor); } if (mLocked.orientedRanges.haveOrientation) { - info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, + info->addMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, mLocked.orientedRanges.orientation); } } // release lock @@ -1803,7 +1834,7 @@ void TouchInputMapper::configureVirtualKeysLocked() { virtualKey.scanCode = virtualKeyDefinition.scanCode; int32_t keyCode; uint32_t flags; - if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode, + if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, & keyCode, & flags)) { LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); @@ -3715,7 +3746,6 @@ void MultiTouchInputMapper::configureRawAxes() { JoystickInputMapper::JoystickInputMapper(InputDevice* device) : InputMapper(device) { - initialize(); } JoystickInputMapper::~JoystickInputMapper() { @@ -3728,176 +3758,219 @@ uint32_t JoystickInputMapper::getSources() { void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); - if (mAxes.x.valid) { - info->addMotionRange(AINPUT_MOTION_RANGE_X, - mAxes.x.min, mAxes.x.max, mAxes.x.flat, mAxes.x.fuzz); - } - if (mAxes.y.valid) { - info->addMotionRange(AINPUT_MOTION_RANGE_Y, - mAxes.y.min, mAxes.y.max, mAxes.y.flat, mAxes.y.fuzz); + for (size_t i = 0; i < mAxes.size(); i++) { + const Axis& axis = mAxes.valueAt(i); + info->addMotionRange(axis.axis, axis.min, axis.max, axis.flat, axis.fuzz); } } void JoystickInputMapper::dump(String8& dump) { dump.append(INDENT2 "Joystick Input Mapper:\n"); - dump.append(INDENT3 "Raw Axes:\n"); - dumpRawAbsoluteAxisInfo(dump, mRawAxes.x, "X"); - dumpRawAbsoluteAxisInfo(dump, mRawAxes.y, "Y"); - - dump.append(INDENT3 "Normalized Axes:\n"); - dumpNormalizedAxis(dump, mAxes.x, "X"); - dumpNormalizedAxis(dump, mAxes.y, "Y"); - dumpNormalizedAxis(dump, mAxes.hat0X, "Hat0X"); - dumpNormalizedAxis(dump, mAxes.hat0Y, "Hat0Y"); -} - -void JoystickInputMapper::dumpNormalizedAxis(String8& dump, - const NormalizedAxis& axis, const char* name) { - if (axis.valid) { + dump.append(INDENT3 "Axes:\n"); + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + const char* label = getAxisLabel(axis.axis); + char name[32]; + if (label) { + strncpy(name, label, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + } else { + snprintf(name, sizeof(name), "%d", axis.axis); + } dump.appendFormat(INDENT4 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, " - "scale=%0.3f, center=%0.3f, precision=%0.3f, value=%0.3f\n", + "scale=%0.3f, offset=%0.3f\n", name, axis.min, axis.max, axis.flat, axis.fuzz, - axis.scale, axis.center, axis.precision, axis.value); - } else { - dump.appendFormat(INDENT4 "%s: unknown range\n", name); + axis.scale, axis.offset); + dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n", + mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, + axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz); } } void JoystickInputMapper::configure() { InputMapper::configure(); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mRawAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mRawAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_HAT0X, & mRawAxes.hat0X); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_HAT0Y, & mRawAxes.hat0Y); + // Collect all axes. + for (int32_t abs = 0; abs <= ABS_MAX; abs++) { + RawAbsoluteAxisInfo rawAxisInfo; + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), abs, &rawAxisInfo); + if (rawAxisInfo.valid) { + int32_t axisId; + bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisId); + if (!explicitlyMapped) { + // Axis is not explicitly mapped, will choose a generic axis later. + axisId = -1; + } + + Axis axis; + if (isCenteredAxis(axisId)) { + float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); + float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; + axis.initialize(rawAxisInfo, axisId, explicitlyMapped, + scale, offset, -1.0f, 1.0f, + rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); + } else { + float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); + axis.initialize(rawAxisInfo, axisId, explicitlyMapped, + scale, 0.0f, 0.0f, 1.0f, + rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); + } + + // To eliminate noise while the joystick is at rest, filter out small variations + // in axis values up front. + axis.filter = axis.flat * 0.25f; + + mAxes.add(abs, axis); + } + } + + // If there are too many axes, start dropping them. + // Prefer to keep explicitly mapped axes. + if (mAxes.size() > PointerCoords::MAX_AXES) { + LOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.", + getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES); + pruneAxes(true); + pruneAxes(false); + } - mAxes.x.configure(mRawAxes.x); - mAxes.y.configure(mRawAxes.y); - mAxes.hat0X.configure(mRawAxes.hat0X); - mAxes.hat0Y.configure(mRawAxes.hat0Y); + // Assign generic axis ids to remaining axes. + int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + if (axis.axis < 0) { + while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 + && haveAxis(nextGenericAxisId)) { + nextGenericAxisId += 1; + } + + if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { + axis.axis = nextGenericAxisId; + nextGenericAxisId += 1; + } else { + LOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " + "have already been assigned to other axes.", + getDeviceName().string(), mAxes.keyAt(i)); + mAxes.removeItemsAt(i--); + numAxes -= 1; + } + } + } } -void JoystickInputMapper::initialize() { - mAccumulator.clear(); +bool JoystickInputMapper::haveAxis(int32_t axis) { + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + if (mAxes.valueAt(i).axis == axis) { + return true; + } + } + return false; +} - mAxes.x.resetState(); - mAxes.y.resetState(); - mAxes.hat0X.resetState(); - mAxes.hat0Y.resetState(); +void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { + size_t i = mAxes.size(); + while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { + if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { + continue; + } + LOGI("Discarding joystick '%s' axis %d because there are too many axes.", + getDeviceName().string(), mAxes.keyAt(i)); + mAxes.removeItemsAt(i); + } +} + +bool JoystickInputMapper::isCenteredAxis(int32_t axis) { + switch (axis) { + case AMOTION_EVENT_AXIS_X: + case AMOTION_EVENT_AXIS_Y: + case AMOTION_EVENT_AXIS_Z: + case AMOTION_EVENT_AXIS_RX: + case AMOTION_EVENT_AXIS_RY: + case AMOTION_EVENT_AXIS_RZ: + case AMOTION_EVENT_AXIS_HAT_X: + case AMOTION_EVENT_AXIS_HAT_Y: + case AMOTION_EVENT_AXIS_ORIENTATION: + return true; + default: + return false; + } } void JoystickInputMapper::reset() { // Recenter all axes. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - mAccumulator.clear(); - mAccumulator.fields = Accumulator::FIELD_ALL; - sync(when); - // Reinitialize state. - initialize(); + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + axis.newValue = 0; + } + + sync(when, true /*force*/); InputMapper::reset(); } void JoystickInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { - case EV_ABS: - switch (rawEvent->scanCode) { - case ABS_X: - mAccumulator.fields |= Accumulator::FIELD_ABS_X; - mAccumulator.absX = rawEvent->value; - break; - case ABS_Y: - mAccumulator.fields |= Accumulator::FIELD_ABS_Y; - mAccumulator.absY = rawEvent->value; - break; - case ABS_HAT0X: - mAccumulator.fields |= Accumulator::FIELD_ABS_HAT0X; - mAccumulator.absHat0X = rawEvent->value; - break; - case ABS_HAT0Y: - mAccumulator.fields |= Accumulator::FIELD_ABS_HAT0Y; - mAccumulator.absHat0Y = rawEvent->value; - break; + case EV_ABS: { + ssize_t index = mAxes.indexOfKey(rawEvent->scanCode); + if (index >= 0) { + Axis& axis = mAxes.editValueAt(index); + float newValue = rawEvent->value * axis.scale + axis.offset; + if (newValue != axis.newValue) { + axis.newValue = newValue; + } } break; + } case EV_SYN: switch (rawEvent->scanCode) { case SYN_REPORT: - sync(rawEvent->when); + sync(rawEvent->when, false /*force*/); break; } break; } } -void JoystickInputMapper::sync(nsecs_t when) { - uint32_t fields = mAccumulator.fields; - if (fields == 0) { - return; // no new state changes, so nothing to do +void JoystickInputMapper::sync(nsecs_t when, bool force) { + if (!force && !haveAxesChangedSignificantly()) { + return; } int32_t metaState = mContext->getGlobalMetaState(); - bool motionAxisChanged = false; - if (fields & Accumulator::FIELD_ABS_X) { - if (mAxes.x.updateValue(mAccumulator.absX)) { - motionAxisChanged = true; - } - } - - if (fields & Accumulator::FIELD_ABS_Y) { - if (mAxes.y.updateValue(mAccumulator.absY)) { - motionAxisChanged = true; - } - } - - if (motionAxisChanged) { - PointerCoords pointerCoords; - pointerCoords.clear(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, mAxes.x.value); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, mAxes.y.value); - - int32_t pointerId = 0; - getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, 0, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, &pointerId, &pointerCoords, mAxes.x.precision, mAxes.y.precision, 0); - } - - if (fields & Accumulator::FIELD_ABS_HAT0X) { - if (mAxes.hat0X.updateValueAndDirection(mAccumulator.absHat0X)) { - notifyDirectionalAxis(mAxes.hat0X, when, metaState, - AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT); - } - } + PointerCoords pointerCoords; + pointerCoords.clear(); - if (fields & Accumulator::FIELD_ABS_HAT0Y) { - if (mAxes.hat0Y.updateValueAndDirection(mAccumulator.absHat0Y)) { - notifyDirectionalAxis(mAxes.hat0Y, when, metaState, - AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN); - } + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + pointerCoords.setAxisValue(axis.axis, axis.newValue); + axis.oldValue = axis.newValue; } - mAccumulator.clear(); + int32_t pointerId = 0; + getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, 0, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + 1, &pointerId, &pointerCoords, 0, 0, 0); } -void JoystickInputMapper::notifyDirectionalAxis(DirectionalAxis& axis, - nsecs_t when, int32_t metaState, int32_t lowKeyCode, int32_t highKeyCode) { - if (axis.lastKeyCode) { - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, 0, - AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, - axis.lastKeyCode, 0, metaState, when); - axis.lastKeyCode = 0; - } - if (axis.direction) { - axis.lastKeyCode = axis.direction > 0 ? highKeyCode : lowKeyCode; - getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, 0, - AKEY_EVENT_ACTION_DOWN, AKEY_EVENT_FLAG_FROM_SYSTEM, - axis.lastKeyCode, 0, metaState, when); +bool JoystickInputMapper::haveAxesChangedSignificantly() { + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + if (axis.newValue != axis.oldValue + && fabs(axis.newValue - axis.oldValue) > axis.filter) { + return true; + } } + return false; } - } // namespace android diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 27cb8e1..cf41535 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -481,7 +481,9 @@ private: enum { FIELD_BTN_MOUSE = 1, FIELD_REL_X = 2, - FIELD_REL_Y = 4 + FIELD_REL_Y = 4, + FIELD_REL_WHEEL = 8, + FIELD_REL_HWHEEL = 16, }; uint32_t fields; @@ -489,6 +491,8 @@ private: bool btnMouse; int32_t relX; int32_t relY; + int32_t relWheel; + int32_t relHWheel; inline void clear() { fields = 0; @@ -500,6 +504,12 @@ private: float mYScale; float mXPrecision; float mYPrecision; + + bool mHaveVWheel; + bool mHaveHWheel; + float mVWheelScale; + float mHWheelScale; + sp<PointerControllerInterface> mPointerController; struct LockedState { @@ -985,123 +995,53 @@ public: virtual void process(const RawEvent* rawEvent); private: - struct RawAxes { - RawAbsoluteAxisInfo x; - RawAbsoluteAxisInfo y; - RawAbsoluteAxisInfo hat0X; - RawAbsoluteAxisInfo hat0Y; - } mRawAxes; - - struct NormalizedAxis { - bool valid; - - static const float min = -1.0f; - static const float max = -1.0f; - - float scale; // scale factor - float center; // center offset after scaling - float precision; // precision - float flat; // size of flat region - float fuzz; // error tolerance - - float value; // most recent value - - NormalizedAxis() : valid(false), scale(0), center(0), precision(0), - flat(0), fuzz(0), value(0) { - } - - void configure(const RawAbsoluteAxisInfo& rawAxis) { - if (rawAxis.valid && rawAxis.getRange() != 0) { - valid = true; - scale = 2.0f / rawAxis.getRange(); - precision = rawAxis.getRange(); - flat = rawAxis.flat * scale; - fuzz = rawAxis.fuzz * scale; - center = float(rawAxis.minValue + rawAxis.maxValue) / rawAxis.getRange(); - } - } - - void resetState() { - value = 0; - } - - bool updateValue(int32_t rawValue) { - float newValue = rawValue * scale - center; - if (value == newValue) { - return false; - } - value = newValue; - return true; - } - }; - - struct DirectionalAxis : NormalizedAxis { - int32_t direction; // most recent direction vector: value is one of -1, 0, 1. - - int32_t lastKeyCode; // most recent key code produced - - DirectionalAxis() : lastKeyCode(0) { - } - - void resetState() { - NormalizedAxis::resetState(); - direction = 0; - lastKeyCode = 0; - } - - bool updateValueAndDirection(int32_t rawValue) { - if (!updateValue(rawValue)) { - return false; - } - if (value > flat) { - direction = 1; - } else if (value < -flat) { - direction = -1; - } else { - direction = 0; - } - return true; + struct Axis { + RawAbsoluteAxisInfo rawAxisInfo; + + int32_t axis; // axis id + bool explicitlyMapped; // true if the axis was explicitly assigned an axis id + + float scale; // scale factor from raw to normalized values + float offset; // offset to add after scaling for normalization + + float min; // normalized inclusive minimum + float max; // normalized inclusive maximum + float flat; // normalized flat region size + float fuzz; // normalized error tolerance + + float oldValue; // previous value + float newValue; // most recent value + + float filter; // filter out small variations of this size + + void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, + int32_t axis, bool explicitlyMapped, float scale, float offset, + float min, float max, float flat, float fuzz) { + this->rawAxisInfo = rawAxisInfo; + this->axis = axis; + this->explicitlyMapped = explicitlyMapped; + this->scale = scale; + this->offset = offset; + this->min = min; + this->max = max; + this->flat = flat; + this->fuzz = fuzz; + this->filter = 0; + this->oldValue = 0; + this->newValue = 0; } }; - struct Axes { - NormalizedAxis x; - NormalizedAxis y; - DirectionalAxis hat0X; - DirectionalAxis hat0Y; - } mAxes; - - struct Accumulator { - enum { - FIELD_ABS_X = 1, - FIELD_ABS_Y = 2, - FIELD_ABS_HAT0X = 4, - FIELD_ABS_HAT0Y = 8, - - FIELD_ALL = FIELD_ABS_X | FIELD_ABS_Y | FIELD_ABS_HAT0X | FIELD_ABS_HAT0Y, - }; - - uint32_t fields; - - int32_t absX; - int32_t absY; - int32_t absHat0X; - int32_t absHat0Y; - - inline void clear() { - fields = 0; - } - } mAccumulator; + // Axes indexed by raw ABS_* axis index. + KeyedVector<int32_t, Axis> mAxes; - void initialize(); - - void sync(nsecs_t when); + void sync(nsecs_t when, bool force); - void notifyDirectionalAxis(DirectionalAxis& axis, - nsecs_t when, int32_t metaState, int32_t lowKeyCode, int32_t highKeyCode); + bool haveAxis(int32_t axis); + void pruneAxes(bool ignoreExplicitlyMappedAxes); + bool haveAxesChangedSignificantly(); - static void dumpNormalizedAxis(String8& dump, - const NormalizedAxis& axis, const char* name); + static bool isCenteredAxis(int32_t axis); }; } // namespace android diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 41d67ed..648250e 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -561,7 +561,7 @@ private: return -1; } - virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, + virtual status_t mapKey(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const { Device* device = getDevice(deviceId); if (device) { @@ -579,6 +579,11 @@ private: return NAME_NOT_FOUND; } + virtual status_t mapAxis(int32_t deviceId, int scancode, + int32_t* outAxis) const { + return NAME_NOT_FOUND; + } + virtual void addExcludedDevice(const char* deviceName) { mExcludedDevices.add(String8(deviceName)); } diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp index 097b109..8ab9b6a 100644 --- a/tools/validatekeymaps/Main.cpp +++ b/tools/validatekeymaps/Main.cpp @@ -17,6 +17,7 @@ #include <ui/KeyCharacterMap.h> #include <ui/KeyLayoutMap.h> #include <ui/VirtualKeyMap.h> +#include <utils/PropertyMap.h> #include <utils/String8.h> #include <stdio.h> @@ -32,6 +33,7 @@ enum FileType { FILETYPE_KEYLAYOUT, FILETYPE_KEYCHARACTERMAP, FILETYPE_VIRTUALKEYDEFINITION, + FILETYPE_INPUTDEVICECONFIGURATION, }; @@ -39,9 +41,9 @@ static void usage() { fprintf(stderr, "Keymap Validation Tool\n\n"); fprintf(stderr, "Usage:\n"); fprintf(stderr, - " %s [*.kl] [*.kcm] [virtualkeys.*] [...]\n" - " Validates the specified key layouts, key character maps \n" - " or virtual key definitions.\n\n", + " %s [*.kl] [*.kcm] [*.idc] [virtualkeys.*] [...]\n" + " Validates the specified key layouts, key character maps, \n" + " input device configurations, or virtual key definitions.\n\n", gProgName); } @@ -54,6 +56,9 @@ static FileType getFileType(const char* filename) { if (strcmp(extension, ".kcm") == 0) { return FILETYPE_KEYCHARACTERMAP; } + if (strcmp(extension, ".idc") == 0) { + return FILETYPE_INPUTDEVICECONFIGURATION; + } } if (strstr(filename, "virtualkeys.")) { @@ -92,6 +97,16 @@ static bool validateFile(const char* filename) { break; } + case FILETYPE_INPUTDEVICECONFIGURATION: { + PropertyMap* map; + status_t status = PropertyMap::load(String8(filename), &map); + if (status) { + fprintf(stderr, "Error %d parsing input device configuration file.\n\n", status); + return false; + } + break; + } + case FILETYPE_VIRTUALKEYDEFINITION: { VirtualKeyMap* map; status_t status = VirtualKeyMap::load(String8(filename), &map); |