mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-04-23 08:46:40 +00:00
Map external keyboard keycodes to the QWERTY layout that GFE expects
This commit is contained in:
@@ -107,6 +107,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private static final int THREE_FINGER_TAP_THRESHOLD = 300;
|
private static final int THREE_FINGER_TAP_THRESHOLD = 300;
|
||||||
|
|
||||||
private ControllerHandler controllerHandler;
|
private ControllerHandler controllerHandler;
|
||||||
|
private KeyboardTranslator keyboardTranslator;
|
||||||
private VirtualController virtualController;
|
private VirtualController virtualController;
|
||||||
|
|
||||||
private PreferenceConfiguration prefConfig;
|
private PreferenceConfiguration prefConfig;
|
||||||
@@ -443,9 +444,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
// Initialize the connection
|
// Initialize the connection
|
||||||
conn = new NvConnection(host, uniqueId, config, PlatformBinding.getCryptoProvider(this), serverCert);
|
conn = new NvConnection(host, uniqueId, config, PlatformBinding.getCryptoProvider(this), serverCert);
|
||||||
controllerHandler = new ControllerHandler(this, conn, this, prefConfig);
|
controllerHandler = new ControllerHandler(this, conn, this, prefConfig);
|
||||||
|
keyboardTranslator = new KeyboardTranslator();
|
||||||
|
|
||||||
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
||||||
inputManager.registerInputDeviceListener(controllerHandler, null);
|
inputManager.registerInputDeviceListener(controllerHandler, null);
|
||||||
|
inputManager.registerInputDeviceListener(keyboardTranslator, null);
|
||||||
|
|
||||||
// Initialize touch contexts
|
// Initialize touch contexts
|
||||||
for (int i = 0; i < touchContextMap.length; i++) {
|
for (int i = 0; i < touchContextMap.length; i++) {
|
||||||
@@ -886,10 +889,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
||||||
|
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
||||||
if (controllerHandler != null) {
|
if (controllerHandler != null) {
|
||||||
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
|
||||||
inputManager.unregisterInputDeviceListener(controllerHandler);
|
inputManager.unregisterInputDeviceListener(controllerHandler);
|
||||||
}
|
}
|
||||||
|
if (keyboardTranslator != null) {
|
||||||
|
inputManager.unregisterInputDeviceListener(keyboardTranslator);
|
||||||
|
}
|
||||||
|
|
||||||
if (lowLatencyWifiLock != null) {
|
if (lowLatencyWifiLock != null) {
|
||||||
lowLatencyWifiLock.release();
|
lowLatencyWifiLock.release();
|
||||||
@@ -1109,7 +1115,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
// Try the keyboard handler
|
// Try the keyboard handler
|
||||||
short translated = KeyboardTranslator.translate(event.getKeyCode());
|
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
|
||||||
if (translated == 0) {
|
if (translated == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1179,7 +1185,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
// Try the keyboard handler
|
// Try the keyboard handler
|
||||||
short translated = KeyboardTranslator.translate(event.getKeyCode());
|
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
|
||||||
if (translated == 0) {
|
if (translated == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1922,7 +1928,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyboardEvent(boolean buttonDown, short keyCode) {
|
public void keyboardEvent(boolean buttonDown, short keyCode) {
|
||||||
short keyMap = KeyboardTranslator.translate(keyCode);
|
short keyMap = keyboardTranslator.translate(keyCode, -1);
|
||||||
if (keyMap != 0) {
|
if (keyMap != 0) {
|
||||||
// handleSpecialKeys() takes the Android keycode
|
// handleSpecialKeys() takes the Android keycode
|
||||||
if (handleSpecialKeys(keyCode, buttonDown)) {
|
if (handleSpecialKeys(keyCode, buttonDown)) {
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
package com.limelight.binding.input;
|
package com.limelight.binding.input;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.hardware.input.InputManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.InputDevice;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to translate a Android key code into the codes GFE is expecting
|
* Class to translate a Android key code into the codes GFE is expecting
|
||||||
* @author Diego Waxemberg
|
* @author Diego Waxemberg
|
||||||
* @author Cameron Gutman
|
* @author Cameron Gutman
|
||||||
*/
|
*/
|
||||||
public class KeyboardTranslator {
|
public class KeyboardTranslator implements InputManager.InputDeviceListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GFE's prefix for every key code
|
* GFE's prefix for every key code
|
||||||
@@ -48,6 +55,55 @@ public class KeyboardTranslator {
|
|||||||
public static final int VK_QUOTE = 222;
|
public static final int VK_QUOTE = 222;
|
||||||
public static final int VK_PAUSE = 19;
|
public static final int VK_PAUSE = 19;
|
||||||
|
|
||||||
|
private static class KeyboardMapping {
|
||||||
|
private final InputDevice device;
|
||||||
|
private final int[] deviceKeyCodeToQwertyKeyCode;
|
||||||
|
|
||||||
|
@TargetApi(33)
|
||||||
|
public KeyboardMapping(InputDevice device) {
|
||||||
|
int maxKeyCode = KeyEvent.getMaxKeyCode();
|
||||||
|
|
||||||
|
this.device = device;
|
||||||
|
this.deviceKeyCodeToQwertyKeyCode = new int[maxKeyCode + 1];
|
||||||
|
|
||||||
|
// Any unmatched keycodes are treated as unknown
|
||||||
|
Arrays.fill(deviceKeyCodeToQwertyKeyCode, KeyEvent.KEYCODE_UNKNOWN);
|
||||||
|
|
||||||
|
for (int i = 0; i <= maxKeyCode; i++) {
|
||||||
|
int deviceKeyCode = device.getKeyCodeForKeyLocation(i);
|
||||||
|
if (deviceKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
||||||
|
deviceKeyCodeToQwertyKeyCode[deviceKeyCode] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(33)
|
||||||
|
public int getDeviceKeyCodeForQwertyKeyCode(int qwertyKeyCode) {
|
||||||
|
return device.getKeyCodeForKeyLocation(qwertyKeyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getQwertyKeyCodeForDeviceKeyCode(int deviceKeyCode) {
|
||||||
|
if (deviceKeyCode > KeyEvent.getMaxKeyCode()) {
|
||||||
|
return KeyEvent.KEYCODE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceKeyCodeToQwertyKeyCode[deviceKeyCode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final SparseArray<KeyboardMapping> keyboardMappings = new SparseArray<>();
|
||||||
|
|
||||||
|
public KeyboardTranslator() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
for (int deviceId : InputDevice.getDeviceIds()) {
|
||||||
|
InputDevice device = InputDevice.getDevice(deviceId);
|
||||||
|
if (device != null && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
|
||||||
|
keyboardMappings.set(deviceId, new KeyboardMapping(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean needsShift(int keycode) {
|
public static boolean needsShift(int keycode) {
|
||||||
switch (keycode)
|
switch (keycode)
|
||||||
{
|
{
|
||||||
@@ -65,11 +121,25 @@ public class KeyboardTranslator {
|
|||||||
/**
|
/**
|
||||||
* Translates the given keycode and returns the GFE keycode
|
* Translates the given keycode and returns the GFE keycode
|
||||||
* @param keycode the code to be translated
|
* @param keycode the code to be translated
|
||||||
|
* @param deviceId InputDevice.getId() or -1 if unknown
|
||||||
* @return a GFE keycode for the given keycode
|
* @return a GFE keycode for the given keycode
|
||||||
*/
|
*/
|
||||||
public static short translate(int keycode) {
|
public short translate(int keycode, int deviceId) {
|
||||||
int translated;
|
int translated;
|
||||||
|
|
||||||
|
// If a device ID was provided, look up the keyboard mapping
|
||||||
|
if (deviceId >= 0) {
|
||||||
|
KeyboardMapping mapping = keyboardMappings.get(deviceId);
|
||||||
|
if (mapping != null) {
|
||||||
|
// Try to map this device-specific keycode onto a QWERTY layout.
|
||||||
|
// GFE assumes incoming keycodes are from a QWERTY keyboard.
|
||||||
|
int qwertyKeyCode = mapping.getQwertyKeyCodeForDeviceKeyCode(keycode);
|
||||||
|
if (qwertyKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
||||||
|
keycode = qwertyKeyCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is a poor man's mapping between Android key codes
|
// This is a poor man's mapping between Android key codes
|
||||||
// and Windows VK_* codes. For all defined VK_ codes, see:
|
// and Windows VK_* codes. For all defined VK_ codes, see:
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||||
@@ -294,4 +364,30 @@ public class KeyboardTranslator {
|
|||||||
return (short) ((KEY_PREFIX << 8) | translated);
|
return (short) ((KEY_PREFIX << 8) | translated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputDeviceAdded(int index) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
InputDevice device = InputDevice.getDevice(index);
|
||||||
|
if (device != null && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
|
||||||
|
keyboardMappings.put(index, new KeyboardMapping(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputDeviceRemoved(int index) {
|
||||||
|
keyboardMappings.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputDeviceChanged(int index) {
|
||||||
|
keyboardMappings.remove(index);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
InputDevice device = InputDevice.getDevice(index);
|
||||||
|
if (device != null && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
|
||||||
|
keyboardMappings.set(index, new KeyboardMapping(device));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user