Add support for the NVIDIA relative mouse extensions for Shield devices

This commit is contained in:
Cameron Gutman 2016-01-30 04:21:20 -05:00
parent a455e75e37
commit fb15ff99ca
2 changed files with 111 additions and 9 deletions

View File

@ -4,6 +4,7 @@ package com.limelight;
import com.limelight.binding.PlatformBinding; import com.limelight.binding.PlatformBinding;
import com.limelight.binding.input.ControllerHandler; import com.limelight.binding.input.ControllerHandler;
import com.limelight.binding.input.KeyboardTranslator; import com.limelight.binding.input.KeyboardTranslator;
import com.limelight.binding.input.NvMouseHelper;
import com.limelight.binding.input.TouchContext; import com.limelight.binding.input.TouchContext;
import com.limelight.binding.input.driver.UsbDriverService; import com.limelight.binding.input.driver.UsbDriverService;
import com.limelight.binding.input.evdev.EvdevHandler; import com.limelight.binding.input.evdev.EvdevHandler;
@ -422,11 +423,15 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private final Runnable toggleGrab = new Runnable() { private final Runnable toggleGrab = new Runnable() {
@Override @Override
public void run() { public void run() {
if (evdevHandler != null) { if (grabbedInput) {
if (grabbedInput) { NvMouseHelper.setCursorVisibility(Game.this, true);
if (evdevHandler != null) {
evdevHandler.ungrabAll(); evdevHandler.ungrabAll();
} }
else { }
else {
NvMouseHelper.setCursorVisibility(Game.this, false);
if (evdevHandler != null) {
evdevHandler.regrabAll(); evdevHandler.regrabAll();
} }
} }
@ -655,13 +660,26 @@ public class Game extends Activity implements SurfaceHolder.Callback,
} }
} }
// First process the history // Get relative axis values if we can
for (int i = 0; i < event.getHistorySize(); i++) { if (NvMouseHelper.eventHasRelativeMouseAxes(event)) {
updateMousePosition((int)event.getHistoricalX(i), (int)event.getHistoricalY(i)); // Send the deltas straight from the motion event
} conn.sendMouseMove((short)NvMouseHelper.getRelativeAxisX(event),
(short)NvMouseHelper.getRelativeAxisY(event));
// Now process the current values // We have to also update the position Android thinks the cursor is at
updateMousePosition((int)event.getX(), (int)event.getY()); // in order to avoid jumping when we stop moving or click.
lastMouseX = (int)event.getX();
lastMouseY = (int)event.getY();
}
else {
// First process the history
for (int i = 0; i < event.getHistorySize(); i++) {
updateMousePosition((int)event.getHistoricalX(i), (int)event.getHistoricalY(i));
}
// Now process the current values
updateMousePosition((int)event.getX(), (int)event.getY());
}
lastButtonState = event.getButtonState(); lastButtonState = event.getButtonState();
} }
@ -828,6 +846,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
evdevHandler.stop(); evdevHandler.stop();
evdevHandler = null; evdevHandler = null;
} }
// Enable cursor visibility again
NvMouseHelper.setCursorVisibility(this, true);
} }
@Override @Override
@ -867,6 +888,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
connecting = false; connecting = false;
connected = true; connected = true;
// Hide the mouse cursor now. Doing it before
// dismissing the spinner seems to be undone
// when the spinner gets displayed.
NvMouseHelper.setCursorVisibility(this, false);
hideSystemUi(1000); hideSystemUi(1000);
} }

View File

@ -0,0 +1,76 @@
package com.limelight.binding.input;
import android.content.Context;
import android.hardware.input.InputManager;
import android.view.MotionEvent;
import com.limelight.LimeLog;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
// NVIDIA extended the Android input APIs with support for using an attached mouse in relative
// mode without having to grab the input device (which requires root). The data comes in the form
// of new AXIS_RELATIVE_X and AXIS_RELATIVE_Y constants in the mouse's MotionEvent objects and
// a new function, InputManager.setCursorVisibility(), that allows the cursor to be hidden.
//
// http://docs.nvidia.com/gameworks/index.html#technologies/mobile/game_controller_handling_mouse.htm
public class NvMouseHelper {
private static boolean nvExtensionSupported;
private static Method methodSetCursorVisibility;
private static int AXIS_RELATIVE_X;
private static int AXIS_RELATIVE_Y;
static {
try {
methodSetCursorVisibility = InputManager.class.getMethod("setCursorVisibility", boolean.class);
Field fieldRelX = MotionEvent.class.getField("AXIS_RELATIVE_X");
Field fieldRelY = MotionEvent.class.getField("AXIS_RELATIVE_Y");
AXIS_RELATIVE_X = (Integer) fieldRelX.get(null);
AXIS_RELATIVE_Y = (Integer) fieldRelY.get(null);
nvExtensionSupported = true;
} catch (Exception e) {
LimeLog.info("NvMouseHelper not supported");
nvExtensionSupported = false;
}
}
public static boolean setCursorVisibility(Context context, boolean visible) {
if (!nvExtensionSupported) {
return false;
}
try {
methodSetCursorVisibility.invoke(context.getSystemService(Context.INPUT_SERVICE), visible);
return true;
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
public static boolean eventHasRelativeMouseAxes(MotionEvent event) {
if (!nvExtensionSupported) {
return false;
}
return event.getAxisValue(AXIS_RELATIVE_X) != 0 ||
event.getAxisValue(AXIS_RELATIVE_Y) != 0;
}
public static float getRelativeAxisX(MotionEvent event) {
return event.getAxisValue(AXIS_RELATIVE_X);
}
public static float getRelativeAxisY(MotionEvent event) {
return event.getAxisValue(AXIS_RELATIVE_Y);
}
}