diff options
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GamepadUtils.java')
-rw-r--r-- | mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GamepadUtils.java | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GamepadUtils.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GamepadUtils.java new file mode 100644 index 000000000..e22be8fd8 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GamepadUtils.java @@ -0,0 +1,140 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.util; + +import android.annotation.TargetApi; +import android.os.Build; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; + +public final class GamepadUtils { + private static final int SONY_XPERIA_GAMEPAD_DEVICE_ID = 196611; + + private static View.OnKeyListener sClickDispatcher; + private static float sDeadZoneThresholdOverride = 1e-2f; + + private GamepadUtils() { + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) + private static boolean isGamepadKey(KeyEvent event) { + if (Build.VERSION.SDK_INT < 12) { + return false; + } + return (event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD; + } + + public static boolean isActionKey(KeyEvent event) { + return (isGamepadKey(event) && (event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_A)); + } + + public static boolean isActionKeyDown(KeyEvent event) { + return isActionKey(event) && event.getAction() == KeyEvent.ACTION_DOWN; + } + + public static boolean isBackKey(KeyEvent event) { + return (isGamepadKey(event) && (event.getKeyCode() == KeyEvent.KEYCODE_BUTTON_B)); + } + + public static void overrideDeadZoneThreshold(float threshold) { + sDeadZoneThresholdOverride = threshold; + } + + public static boolean isValueInDeadZone(MotionEvent event, int axis) { + float threshold; + if (sDeadZoneThresholdOverride >= 0) { + threshold = sDeadZoneThresholdOverride; + } else { + InputDevice.MotionRange range = event.getDevice().getMotionRange(axis); + threshold = range.getFlat() + range.getFuzz(); + } + float value = event.getAxisValue(axis); + return (Math.abs(value) < threshold); + } + + public static boolean isPanningControl(MotionEvent event) { + if (Build.VERSION.SDK_INT < 12) { + return false; + } + if ((event.getSource() & InputDevice.SOURCE_CLASS_MASK) != InputDevice.SOURCE_CLASS_JOYSTICK) { + return false; + } + if (isValueInDeadZone(event, MotionEvent.AXIS_X) + && isValueInDeadZone(event, MotionEvent.AXIS_Y) + && isValueInDeadZone(event, MotionEvent.AXIS_Z) + && isValueInDeadZone(event, MotionEvent.AXIS_RZ)) { + return false; + } + return true; + } + + public static View.OnKeyListener getClickDispatcher() { + if (sClickDispatcher == null) { + sClickDispatcher = new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (isActionKeyDown(event)) { + return v.performClick(); + } + return false; + } + }; + } + return sClickDispatcher; + } + + public static KeyEvent translateSonyXperiaGamepadKeys(int keyCode, KeyEvent event) { + // The cross and circle button mappings may be swapped in the different regions so + // determine if they are swapped so the proper key codes can be mapped to the keys + boolean areKeysSwapped = areSonyXperiaGamepadKeysSwapped(); + + // If a Sony Xperia, remap the cross and circle buttons to buttons + // A and B for the gamepad API + switch (keyCode) { + case KeyEvent.KEYCODE_BACK: + keyCode = (areKeysSwapped ? KeyEvent.KEYCODE_BUTTON_A : KeyEvent.KEYCODE_BUTTON_B); + break; + + case KeyEvent.KEYCODE_DPAD_CENTER: + keyCode = (areKeysSwapped ? KeyEvent.KEYCODE_BUTTON_B : KeyEvent.KEYCODE_BUTTON_A); + break; + + default: + return event; + } + + return new KeyEvent(event.getAction(), keyCode); + } + + public static boolean isSonyXperiaGamepadKeyEvent(KeyEvent event) { + return (event.getDeviceId() == SONY_XPERIA_GAMEPAD_DEVICE_ID && + "Sony Ericsson".equals(Build.MANUFACTURER) && + ("R800".equals(Build.MODEL) || "R800i".equals(Build.MODEL))); + } + + private static boolean areSonyXperiaGamepadKeysSwapped() { + // The cross and circle buttons on Sony Xperia phones are swapped + // in different regions + // http://developer.sonymobile.com/2011/02/13/xperia-play-game-keys/ + final char DEFAULT_O_BUTTON_LABEL = 0x25CB; + + boolean swapped = false; + int[] deviceIds = InputDevice.getDeviceIds(); + + for (int i = 0; deviceIds != null && i < deviceIds.length; i++) { + KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(deviceIds[i]); + if (keyCharacterMap != null && DEFAULT_O_BUTTON_LABEL == + keyCharacterMap.getDisplayLabel(KeyEvent.KEYCODE_DPAD_CENTER)) { + swapped = true; + break; + } + } + return swapped; + } +} |