Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org.mozilla.gecko.util;
8 import android.os.Build;
9 import android.view.InputDevice;
10 import android.view.KeyCharacterMap;
11 import android.view.KeyEvent;
12 import android.view.MotionEvent;
13 import android.view.View;
14 import android.widget.AdapterView;
15 import android.widget.ListView;
17 public final class GamepadUtils {
18 private static final int SONY_XPERIA_GAMEPAD_DEVICE_ID = 196611;
20 private static View.OnKeyListener sClickDispatcher;
21 private static float sDeadZoneThresholdOverride = 1e-2f;
23 private GamepadUtils() {
24 }
26 private static boolean isGamepadKey(KeyEvent event) {
27 if (Build.VERSION.SDK_INT >= 9) {
28 return (event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD;
29 }
30 return false;
31 }
33 public static boolean isActionKey(KeyEvent event) {
34 return (isGamepadKey(event) && (event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_A));
35 }
37 public static boolean isActionKeyDown(KeyEvent event) {
38 return isActionKey(event) && event.getAction() == KeyEvent.ACTION_DOWN;
39 }
41 public static boolean isBackKey(KeyEvent event) {
42 return (isGamepadKey(event) && (event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_B));
43 }
45 public static void overrideDeadZoneThreshold(float threshold) {
46 sDeadZoneThresholdOverride = threshold;
47 }
49 public static boolean isValueInDeadZone(MotionEvent event, int axis) {
50 if (Build.VERSION.SDK_INT < 9) {
51 return false;
52 }
54 float threshold;
55 if (sDeadZoneThresholdOverride >= 0) {
56 threshold = sDeadZoneThresholdOverride;
57 } else {
58 InputDevice.MotionRange range = event.getDevice().getMotionRange(axis);
59 threshold = range.getFlat() + range.getFuzz();
60 }
61 float value = event.getAxisValue(axis);
62 return (Math.abs(value) < threshold);
63 }
65 public static boolean isPanningControl(MotionEvent event) {
66 if (Build.VERSION.SDK_INT < 12) {
67 return false;
68 }
69 if ((event.getSource() & InputDevice.SOURCE_CLASS_MASK) != InputDevice.SOURCE_CLASS_JOYSTICK) {
70 return false;
71 }
72 if (isValueInDeadZone(event, MotionEvent.AXIS_X)
73 && isValueInDeadZone(event, MotionEvent.AXIS_Y)
74 && isValueInDeadZone(event, MotionEvent.AXIS_Z)
75 && isValueInDeadZone(event, MotionEvent.AXIS_RZ)) {
76 return false;
77 }
78 return true;
79 }
81 public static View.OnKeyListener getClickDispatcher() {
82 if (sClickDispatcher == null) {
83 sClickDispatcher = new View.OnKeyListener() {
84 @Override
85 public boolean onKey(View v, int keyCode, KeyEvent event) {
86 if (isActionKeyDown(event)) {
87 return v.performClick();
88 }
89 return false;
90 }
91 };
92 }
93 return sClickDispatcher;
94 }
96 public static KeyEvent translateSonyXperiaGamepadKeys(int keyCode, KeyEvent event) {
97 // The cross and circle button mappings may be swapped in the different regions so
98 // determine if they are swapped so the proper key codes can be mapped to the keys
99 boolean areKeysSwapped = areSonyXperiaGamepadKeysSwapped();
101 // If a Sony Xperia, remap the cross and circle buttons to buttons
102 // A and B for the gamepad API
103 switch (keyCode) {
104 case KeyEvent.KEYCODE_BACK:
105 keyCode = (areKeysSwapped ? KeyEvent.KEYCODE_BUTTON_A : KeyEvent.KEYCODE_BUTTON_B);
106 break;
108 case KeyEvent.KEYCODE_DPAD_CENTER:
109 keyCode = (areKeysSwapped ? KeyEvent.KEYCODE_BUTTON_B : KeyEvent.KEYCODE_BUTTON_A);
110 break;
112 default:
113 return event;
114 }
116 return new KeyEvent(event.getAction(), keyCode);
117 }
119 public static boolean isSonyXperiaGamepadKeyEvent(KeyEvent event) {
120 return (event.getDeviceId() == SONY_XPERIA_GAMEPAD_DEVICE_ID &&
121 "Sony Ericsson".equals(Build.MANUFACTURER) &&
122 ("R800".equals(Build.MODEL) || "R800i".equals(Build.MODEL)));
123 }
125 private static boolean areSonyXperiaGamepadKeysSwapped() {
126 // The cross and circle buttons on Sony Xperia phones are swapped
127 // in different regions
128 // http://developer.sonymobile.com/2011/02/13/xperia-play-game-keys/
129 final char DEFAULT_O_BUTTON_LABEL = 0x25CB;
131 boolean swapped = false;
132 int[] deviceIds = InputDevice.getDeviceIds();
134 for (int i= 0; deviceIds != null && i < deviceIds.length; i++) {
135 KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(deviceIds[i]);
136 if (keyCharacterMap != null && DEFAULT_O_BUTTON_LABEL ==
137 keyCharacterMap.getDisplayLabel(KeyEvent.KEYCODE_DPAD_CENTER)) {
138 swapped = true;
139 break;
140 }
141 }
142 return swapped;
143 }
144 }