Bug 756504 - Implement DOM_KEY_LOCATION_JOYSTICK for Android game controllers. r=cpeterson
authorChristian Vielma <cvielma@gmail.com>
Wed, 12 Sep 2012 17:48:29 -0700
changeset 106961 42d6da7912e1
parent 106960 bc8901acd1e8
child 106962 4a63439012b3
push id23458
push useremorley@mozilla.com
push date2012-09-13 19:52 +0000
Treeherderresults
reviewerscpeterson
bugs756504
milestone18.0a1
Bug 756504 - Implement DOM_KEY_LOCATION_JOYSTICK for Android game controllers. r=cpeterson
mobile/android/base/GeckoEvent.java
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
widget/android/nsWindow.cpp
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -63,16 +63,27 @@ public class GeckoEvent {
     private static final int ACTIVITY_RESUMING = 24;
     private static final int SCREENSHOT = 25;
     private static final int UNUSED2_EVENT = 26;
     private static final int SCREENORIENTATION_CHANGED = 27;
     private static final int COMPOSITOR_PAUSE = 28;
     private static final int COMPOSITOR_RESUME = 29;
     private static final int PAINT_LISTEN_START_EVENT = 30;
 
+    /**
+     * These DOM_KEY_LOCATION constants mirror the DOM KeyboardEvent's constants.
+     * @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
+     */
+    private static final int DOM_KEY_LOCATION_STANDARD = 0;
+    private static final int DOM_KEY_LOCATION_LEFT = 1;
+    private static final int DOM_KEY_LOCATION_RIGHT = 2;
+    private static final int DOM_KEY_LOCATION_NUMPAD = 3;
+    private static final int DOM_KEY_LOCATION_MOBILE = 4;
+    private static final int DOM_KEY_LOCATION_JOYSTICK = 5;
+
     public static final int IME_COMPOSITION_END = 0;
     public static final int IME_COMPOSITION_BEGIN = 1;
     public static final int IME_SET_TEXT = 2;
     public static final int IME_GET_TEXT = 3;
     public static final int IME_DELETE_TEXT = 4;
     public static final int IME_SET_SELECTION = 5;
     public static final int IME_GET_SELECTION = 6;
     public static final int IME_ADD_RANGE = 7;
@@ -103,16 +114,17 @@ public class GeckoEvent {
     public int mKeyCode, mUnicodeChar;
     public int mRepeatCount;
     public int mOffset, mCount;
     public String mCharacters, mCharactersExtra;
     public int mRangeType, mRangeStyles;
     public int mRangeForeColor, mRangeBackColor;
     public Location mLocation;
     public Address  mAddress;
+    public int mDomKeyLocation;
 
     public double mBandwidth;
     public boolean mCanBeMetered;
 
     public int mNativeWindow;
 
     public short mScreenOrientation;
 
@@ -172,16 +184,85 @@ public class GeckoEvent {
         mAction = k.getAction();
         mTime = k.getEventTime();
         mMetaState = k.getMetaState();
         mFlags = k.getFlags();
         mKeyCode = k.getKeyCode();
         mUnicodeChar = k.getUnicodeChar();
         mRepeatCount = k.getRepeatCount();
         mCharacters = k.getCharacters();
+        mDomKeyLocation = isJoystickButton(mKeyCode) ? DOM_KEY_LOCATION_JOYSTICK : DOM_KEY_LOCATION_MOBILE;
+    }
+
+    /**
+     * This method tests if a key is one of the described in:
+     * https://bugzilla.mozilla.org/show_bug.cgi?id=756504#c0
+     * @param keyCode int with the key code (Android key constant from KeyEvent)
+     * @return true if the key is one of the listed above, false otherwise.
+     */
+    private static boolean isJoystickButton(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_UP:
+                return true;
+            default:
+                if (Build.VERSION.SDK_INT >= 12) {
+                    return KeyEvent.isGamepadButton(keyCode);
+                }
+                return GeckoEvent.isGamepadButton(keyCode);
+        }
+    }
+
+    /**
+     * This method is a replacement for the the KeyEvent.isGamepadButton method to be
+     * compatible with Build.VERSION.SDK_INT < 12. This is an implementantion of the
+     * same method isGamepadButton available after SDK 12.
+     * @param keyCode int with the key code (Android key constant from KeyEvent).
+     * @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}.
+     */
+    private static 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;
+        }
     }
 
     public static GeckoEvent createMotionEvent(MotionEvent m) {
         GeckoEvent event = new GeckoEvent(MOTION_EVENT);
         event.initMotionEvent(m);
         return event;
     }
 
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -23,16 +23,17 @@ jfieldID AndroidGeckoEvent::jZField = 0;
 jfieldID AndroidGeckoEvent::jDistanceField = 0;
 jfieldID AndroidGeckoEvent::jRectField = 0;
 jfieldID AndroidGeckoEvent::jNativeWindowField = 0;
 
 jfieldID AndroidGeckoEvent::jCharactersField = 0;
 jfieldID AndroidGeckoEvent::jCharactersExtraField = 0;
 jfieldID AndroidGeckoEvent::jKeyCodeField = 0;
 jfieldID AndroidGeckoEvent::jMetaStateField = 0;
+jfieldID AndroidGeckoEvent::jDomKeyLocationField = 0;
 jfieldID AndroidGeckoEvent::jFlagsField = 0;
 jfieldID AndroidGeckoEvent::jUnicodeCharField = 0;
 jfieldID AndroidGeckoEvent::jRepeatCountField = 0;
 jfieldID AndroidGeckoEvent::jOffsetField = 0;
 jfieldID AndroidGeckoEvent::jCountField = 0;
 jfieldID AndroidGeckoEvent::jPointerIndexField = 0;
 jfieldID AndroidGeckoEvent::jRangeTypeField = 0;
 jfieldID AndroidGeckoEvent::jRangeStylesField = 0;
@@ -193,16 +194,17 @@ AndroidGeckoEvent::InitGeckoEventClass(J
     jYField = getField("mY", "D");
     jZField = getField("mZ", "D");
     jRectField = getField("mRect", "Landroid/graphics/Rect;");
 
     jCharactersField = getField("mCharacters", "Ljava/lang/String;");
     jCharactersExtraField = getField("mCharactersExtra", "Ljava/lang/String;");
     jKeyCodeField = getField("mKeyCode", "I");
     jMetaStateField = getField("mMetaState", "I");
+    jDomKeyLocationField = getField("mDomKeyLocation", "I");
     jFlagsField = getField("mFlags", "I");
     jUnicodeCharField = getField("mUnicodeChar", "I");
     jRepeatCountField = getField("mRepeatCount", "I");
     jOffsetField = getField("mOffset", "I");
     jCountField = getField("mCount", "I");
     jPointerIndexField = getField("mPointerIndex", "I");
     jRangeTypeField = getField("mRangeType", "I");
     jRangeStylesField = getField("mRangeStyles", "I");
@@ -460,16 +462,17 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
     switch (mType) {
         case SIZE_CHANGED:
             ReadPointArray(mPoints, jenv, jPoints, 2);
             break;
 
         case KEY_EVENT:
             mTime = jenv->GetLongField(jobj, jTimeField);
             mMetaState = jenv->GetIntField(jobj, jMetaStateField);
+            mDomKeyLocation = jenv->GetIntField(jobj, jDomKeyLocationField);
             mFlags = jenv->GetIntField(jobj, jFlagsField);
             mKeyCode = jenv->GetIntField(jobj, jKeyCodeField);
             mUnicodeChar = jenv->GetIntField(jobj, jUnicodeCharField);
             mRepeatCount = jenv->GetIntField(jobj, jRepeatCountField);
             ReadCharactersField(jenv);
             break;
 
         case MOTION_EVENT:
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -579,16 +579,17 @@ public:
     double X() { return mX; }
     double Y() { return mY; }
     double Z() { return mZ; }
     const nsIntRect& Rect() { return mRect; }
     nsAString& Characters() { return mCharacters; }
     nsAString& CharactersExtra() { return mCharactersExtra; }
     int KeyCode() { return mKeyCode; }
     int MetaState() { return mMetaState; }
+    int DomKeyLocation() { return mDomKeyLocation; }
     bool IsAltPressed() const { return (mMetaState & AndroidKeyEvent::META_ALT_MASK) != 0; }
     bool IsShiftPressed() const { return (mMetaState & AndroidKeyEvent::META_SHIFT_MASK) != 0; }
     int Flags() { return mFlags; }
     int UnicodeChar() { return mUnicodeChar; }
     int RepeatCount() const { return mRepeatCount; }
     int Offset() { return mOffset; }
     int Count() { return mCount; }
     int PointerIndex() { return mPointerIndex; }
@@ -608,16 +609,17 @@ protected:
     int64_t mTime;
     nsTArray<nsIntPoint> mPoints;
     nsTArray<nsIntPoint> mPointRadii;
     nsTArray<int> mPointIndicies;
     nsTArray<float> mOrientations;
     nsTArray<float> mPressures;
     nsIntRect mRect;
     int mFlags, mMetaState;
+    int mDomKeyLocation;
     int mKeyCode, mUnicodeChar;
     int mRepeatCount;
     int mOffset, mCount;
     int mRangeType, mRangeStyles;
     int mRangeForeColor, mRangeBackColor;
     double mX, mY, mZ;
     int mPointerIndex;
     nsString mCharacters, mCharactersExtra;
@@ -658,16 +660,17 @@ protected:
     static jfieldID jDistanceField;
     static jfieldID jRectField;
     static jfieldID jNativeWindowField;
 
     static jfieldID jCharactersField;
     static jfieldID jCharactersExtraField;
     static jfieldID jKeyCodeField;
     static jfieldID jMetaStateField;
+    static jfieldID jDomKeyLocationField;
     static jfieldID jFlagsField;
     static jfieldID jOffsetField;
     static jfieldID jCountField;
     static jfieldID jPointerIndexField;
     static jfieldID jUnicodeCharField;
     static jfieldID jRepeatCountField;
     static jfieldID jRangeTypeField;
     static jfieldID jRangeStylesField;
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1709,17 +1709,17 @@ nsWindow::InitKeyEvent(nsKeyEvent& event
         event.keyCode = domKeyCode;
         event.pluginEvent = pluginEvent;
     }
 
     event.InitBasicModifiers(gMenu,
                              key.IsAltPressed(),
                              key.IsShiftPressed(),
                              false);
-    event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE;
+    event.location = key.DomKeyLocation();
     event.time = key.Time();
 
     if (gMenu)
         gMenuConsumed = true;
 }
 
 void
 nsWindow::HandleSpecialKey(AndroidGeckoEvent *ae)