diff --git a/src/com/limelight/Game.java b/src/com/limelight/Game.java index 16aa7501..74dcbc70 100644 --- a/src/com/limelight/Game.java +++ b/src/com/limelight/Game.java @@ -1,26 +1,10 @@ package com.limelight; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.HashMap; - -import org.xmlpull.v1.XmlPullParserException; - import com.limelight.nvstream.NvConnection; -import com.limelight.nvstream.input.NvController; -import com.limelight.nvstream.input.NvInputPacket; +import com.limelight.nvstream.input.NvControllerPacket; import tv.ouya.console.api.OuyaController; -import android.annotation.SuppressLint; import android.app.Activity; -import android.media.AudioManager; -import android.media.MediaCodec; -import android.media.MediaExtractor; -import android.media.MediaFormat; -import android.media.MediaPlayer; -import android.net.Uri; import android.os.Bundle; import android.view.InputDevice; import android.view.KeyEvent; @@ -28,8 +12,6 @@ import android.view.MotionEvent; import android.view.SurfaceView; import android.view.Window; import android.view.WindowManager; -import android.widget.MediaController; -import android.widget.VideoView; public class Game extends Activity { @@ -40,6 +22,8 @@ public class Game extends Activity { private short rightStickY = 0x0000; private short leftStickX = 0x0000; private short leftStickY = 0x0000; + private int lastMouseX = Integer.MIN_VALUE; + private int lastMouseY = Integer.MIN_VALUE; private NvConnection conn; @@ -71,48 +55,48 @@ public class Game extends Activity { switch (keyCode) { case OuyaController.BUTTON_MENU: System.out.println("Menu Pressed"); - inputMap |= NvInputPacket.BACK_FLAG; + inputMap |= NvControllerPacket.BACK_FLAG; break; case OuyaController.BUTTON_DPAD_LEFT: - inputMap |= NvInputPacket.LEFT_FLAG; + inputMap |= NvControllerPacket.LEFT_FLAG; break; case OuyaController.BUTTON_DPAD_RIGHT: - inputMap |= NvInputPacket.RIGHT_FLAG; + inputMap |= NvControllerPacket.RIGHT_FLAG; break; case OuyaController.BUTTON_DPAD_UP: - inputMap |= NvInputPacket.UP_FLAG; + inputMap |= NvControllerPacket.UP_FLAG; break; case OuyaController.BUTTON_DPAD_DOWN: - inputMap |= NvInputPacket.DOWN_FLAG; + inputMap |= NvControllerPacket.DOWN_FLAG; break; case OuyaController.BUTTON_A: - inputMap |= NvInputPacket.B_FLAG; + inputMap |= NvControllerPacket.B_FLAG; break; case OuyaController.BUTTON_O: - inputMap |= NvInputPacket.A_FLAG; + inputMap |= NvControllerPacket.A_FLAG; break; case OuyaController.BUTTON_U: - inputMap |= NvInputPacket.X_FLAG; + inputMap |= NvControllerPacket.X_FLAG; break; case OuyaController.BUTTON_Y: - inputMap |= NvInputPacket.Y_FLAG; + inputMap |= NvControllerPacket.Y_FLAG; break; case OuyaController.BUTTON_L1: - inputMap |= NvInputPacket.LB_FLAG; + inputMap |= NvControllerPacket.LB_FLAG; break; case OuyaController.BUTTON_R1: - inputMap |= NvInputPacket.RB_FLAG; + inputMap |= NvControllerPacket.RB_FLAG; break; case OuyaController.BUTTON_L3: - inputMap |= NvInputPacket.LS_CLK_FLAG; + inputMap |= NvControllerPacket.LS_CLK_FLAG; break; case OuyaController.BUTTON_R3: - inputMap |= NvInputPacket.RS_CLK_FLAG; + inputMap |= NvControllerPacket.RS_CLK_FLAG; break; default: return super.onKeyDown(keyCode, event); } - sendInputPacket(); + sendControllerInputPacket(); return true; } @@ -120,48 +104,48 @@ public class Game extends Activity { public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case OuyaController.BUTTON_MENU: - inputMap &= ~NvInputPacket.BACK_FLAG; + inputMap &= ~NvControllerPacket.BACK_FLAG; break; case OuyaController.BUTTON_DPAD_LEFT: - inputMap &= ~NvInputPacket.LEFT_FLAG; + inputMap &= ~NvControllerPacket.LEFT_FLAG; break; case OuyaController.BUTTON_DPAD_RIGHT: - inputMap &= ~NvInputPacket.RIGHT_FLAG; + inputMap &= ~NvControllerPacket.RIGHT_FLAG; break; case OuyaController.BUTTON_DPAD_UP: - inputMap &= ~NvInputPacket.UP_FLAG; + inputMap &= ~NvControllerPacket.UP_FLAG; break; case OuyaController.BUTTON_DPAD_DOWN: - inputMap &= ~NvInputPacket.DOWN_FLAG; + inputMap &= ~NvControllerPacket.DOWN_FLAG; break; case OuyaController.BUTTON_A: - inputMap &= ~NvInputPacket.B_FLAG; + inputMap &= ~NvControllerPacket.B_FLAG; break; case OuyaController.BUTTON_O: - inputMap &= ~NvInputPacket.A_FLAG; + inputMap &= ~NvControllerPacket.A_FLAG; break; case OuyaController.BUTTON_U: - inputMap &= ~NvInputPacket.X_FLAG; + inputMap &= ~NvControllerPacket.X_FLAG; break; case OuyaController.BUTTON_Y: - inputMap &= ~NvInputPacket.Y_FLAG; + inputMap &= ~NvControllerPacket.Y_FLAG; break; case OuyaController.BUTTON_L1: - inputMap &= ~NvInputPacket.LB_FLAG; + inputMap &= ~NvControllerPacket.LB_FLAG; break; case OuyaController.BUTTON_R1: - inputMap &= ~NvInputPacket.RB_FLAG; + inputMap &= ~NvControllerPacket.RB_FLAG; break; case OuyaController.BUTTON_L3: - inputMap &= ~NvInputPacket.LS_CLK_FLAG; + inputMap &= ~NvControllerPacket.LS_CLK_FLAG; break; case OuyaController.BUTTON_R3: - inputMap &= ~NvInputPacket.RS_CLK_FLAG; + inputMap &= ~NvControllerPacket.RS_CLK_FLAG; break; default: return super.onKeyUp(keyCode, event); } - sendInputPacket(); + sendControllerInputPacket(); return true; } @@ -187,21 +171,48 @@ public class Game extends Activity { rightStickX = (short)Math.round(RS_X * 0x7FFF); rightStickY = (short)Math.round(-RS_Y * 0x7FFF); + + float L2 = event.getAxisValue(OuyaController.AXIS_L2); + float R2 = event.getAxisValue(OuyaController.AXIS_R2); + + leftTrigger = (byte)Math.round(L2 * 0xFF); + rightTrigger = (byte)Math.round(R2 * 0xFF); + + sendControllerInputPacket(); + return true; + } + else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) + { + int eventX = (int)event.getX(); + int eventY = (int)event.getY(); + + // Send a mouse move update (if neccessary) + updateMousePosition(eventX, eventY); + + // Update pointer location for delta calculation next time + lastMouseX = eventX; + lastMouseY = eventY; + return true; } - - float L2 = event.getAxisValue(OuyaController.AXIS_L2); - float R2 = event.getAxisValue(OuyaController.AXIS_R2); - leftTrigger = (byte)Math.round(L2 * 0xFF); - rightTrigger = (byte)Math.round(R2 * 0xFF); - - sendInputPacket(); - - return true; + return super.onGenericMotionEvent(event); } + private void updateMousePosition(int eventX, int eventY) { + // Send a mouse move if we already have a mouse location + // and the mouse coordinates change + if (lastMouseX != Integer.MIN_VALUE && + lastMouseY != Integer.MIN_VALUE && + !(lastMouseX == eventX && lastMouseY == eventY)) + { + System.out.printf("Delta X: 0x%x Delta Y: 0x%x\n", + (short)(eventX - lastMouseX), (short)(eventY - lastMouseY)); + conn.sendMouseMove((short)(eventX - lastMouseX), + (short)(eventY - lastMouseY)); + } + } - private void sendInputPacket() { + private void sendControllerInputPacket() { conn.sendControllerInput(inputMap, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY); } diff --git a/src/com/limelight/nvstream/NvConnection.java b/src/com/limelight/nvstream/NvConnection.java index c4fad00d..3d319d23 100644 --- a/src/com/limelight/nvstream/NvConnection.java +++ b/src/com/limelight/nvstream/NvConnection.java @@ -40,7 +40,7 @@ public class NvConnection { @Override public void run() { try { - host = InetAddress.getByName(host).toString().substring(1); + host = InetAddress.getByName(host).getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); displayToast(e.getMessage()); @@ -70,6 +70,60 @@ public class NvConnection { new NvVideoStream().startVideoStream(host, surface); } + public void sendMouseMove(final short deltaX, final short deltaY) + { + if (inputStream == null) + return; + + threadPool.execute(new Runnable() { + @Override + public void run() { + try { + inputStream.sendMouseMove(deltaX, deltaY); + } catch (IOException e) { + e.printStackTrace(); + displayToast(e.getMessage()); + } + } + }); + } + + public void sendMouseButtonDown() + { + if (inputStream == null) + return; + + threadPool.execute(new Runnable() { + @Override + public void run() { + try { + inputStream.sendMouseButtonDown(); + } catch (IOException e) { + e.printStackTrace(); + displayToast(e.getMessage()); + } + } + }); + } + + public void sendMouseButtonUp() + { + if (inputStream == null) + return; + + threadPool.execute(new Runnable() { + @Override + public void run() { + try { + inputStream.sendMouseButtonUp(); + } catch (IOException e) { + e.printStackTrace(); + displayToast(e.getMessage()); + } + } + }); + } + public void sendControllerInput(final short buttonFlags, final byte leftTrigger, final byte rightTrigger, final short leftStickX, final short leftStickY, diff --git a/src/com/limelight/nvstream/input/NvController.java b/src/com/limelight/nvstream/input/NvController.java index a8d54f84..f4616652 100644 --- a/src/com/limelight/nvstream/input/NvController.java +++ b/src/com/limelight/nvstream/input/NvController.java @@ -22,9 +22,27 @@ public class NvController { public void sendControllerInput(short buttonFlags, byte leftTrigger, byte rightTrigger, short leftStickX, short leftStickY, short rightStickX, short rightStickY) throws IOException { - out.write(new NvInputPacket(buttonFlags, leftTrigger, + out.write(new NvControllerPacket(buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY).toWire()); out.flush(); } + + public void sendMouseButtonDown() throws IOException + { + out.write(new NvMouseButtonPacket(true).toWire()); + out.flush(); + } + + public void sendMouseButtonUp() throws IOException + { + out.write(new NvMouseButtonPacket(false).toWire()); + out.flush(); + } + + public void sendMouseMove(short deltaX, short deltaY) throws IOException + { + out.write(new NvMouseMovePacket(deltaX, deltaY).toWire()); + out.flush(); + } } diff --git a/src/com/limelight/nvstream/input/NvControllerPacket.java b/src/com/limelight/nvstream/input/NvControllerPacket.java new file mode 100644 index 00000000..75452914 --- /dev/null +++ b/src/com/limelight/nvstream/input/NvControllerPacket.java @@ -0,0 +1,88 @@ +package com.limelight.nvstream.input; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class NvControllerPacket extends NvInputPacket { + public static final byte[] HEADER = + { + 0x0A, + 0x00, + 0x00, + 0x00, + 0x00, + 0x14 + }; + + public static final byte[] TAIL = + { + (byte)0x9C, + 0x00, + 0x00, + 0x00, + 0x55, + 0x00 + }; + + public static final int PACKET_TYPE = 0x18; + + public static final short A_FLAG = 0x1000; + public static final short B_FLAG = 0x2000; + public static final short X_FLAG = 0x4000; + public static final short Y_FLAG = (short)0x8000; + public static final short UP_FLAG = 0x0001; + public static final short DOWN_FLAG = 0x0002; + public static final short LEFT_FLAG = 0x0004; + public static final short RIGHT_FLAG = 0x0008; + public static final short LB_FLAG = 0x0100; + public static final short RB_FLAG = 0x0200; + public static final short PLAY_FLAG = 0x0010; + public static final short BACK_FLAG = 0x0020; + public static final short LS_CLK_FLAG = 0x0040; + public static final short RS_CLK_FLAG = 0x0080; + + public static final short PAYLOAD_LENGTH = 24; + public static final short PACKET_LENGTH = PAYLOAD_LENGTH + + NvInputPacket.HEADER_LENGTH; + + private short buttonFlags; + private byte leftTrigger; + private byte rightTrigger; + private short leftStickX; + private short leftStickY; + private short rightStickX; + private short rightStickY; + + public NvControllerPacket(short buttonFlags, byte leftTrigger, byte rightTrigger, + short leftStickX, short leftStickY, + short rightStickX, short rightStickY) + { + super(PACKET_TYPE); + + this.buttonFlags = buttonFlags; + this.leftTrigger = leftTrigger; + this.rightTrigger = rightTrigger; + this.leftStickX = leftStickX; + this.leftStickY = leftStickY; + this.rightStickX = rightStickX; + this.rightStickY = rightStickY; + } + + public byte[] toWire() + { + ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.LITTLE_ENDIAN); + + bb.put(toWireHeader()); + bb.put(HEADER); + bb.putShort(buttonFlags); + bb.put(leftTrigger); + bb.put(rightTrigger); + bb.putShort(leftStickX); + bb.putShort(leftStickY); + bb.putShort(rightStickX); + bb.putShort(rightStickY); + bb.put(TAIL); + + return bb.array(); + } + } \ No newline at end of file diff --git a/src/com/limelight/nvstream/input/NvInputPacket.java b/src/com/limelight/nvstream/input/NvInputPacket.java index 4168ddbf..ec98b2de 100644 --- a/src/com/limelight/nvstream/input/NvInputPacket.java +++ b/src/com/limelight/nvstream/input/NvInputPacket.java @@ -3,83 +3,24 @@ package com.limelight.nvstream.input; import java.nio.ByteBuffer; import java.nio.ByteOrder; -public class NvInputPacket { - public static final byte[] HEADER = - { - 0x00, - 0x00, - 0x00, - 0x18, - 0x0A, - 0x00, - 0x00, - 0x00, - 0x00, - 0x14 - }; +public abstract class NvInputPacket { + public static final int HEADER_LENGTH = 0x4; + + protected int packetType; + + public NvInputPacket(int packetType) + { + this.packetType = packetType; + } + + public abstract byte[] toWire(); + + public byte[] toWireHeader() + { + ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN); - public static final byte[] TAIL = - { - (byte)0x9C, - 0x00, - 0x00, - 0x00, - 0x55, - 0x00 - }; + bb.putInt(packetType); - public static final short A_FLAG = 0x1000; - public static final short B_FLAG = 0x2000; - public static final short X_FLAG = 0x4000; - public static final short Y_FLAG = (short)0x8000; - public static final short UP_FLAG = 0x0001; - public static final short DOWN_FLAG = 0x0002; - public static final short LEFT_FLAG = 0x0004; - public static final short RIGHT_FLAG = 0x0008; - public static final short LB_FLAG = 0x0100; - public static final short RB_FLAG = 0x0200; - public static final short PLAY_FLAG = 0x0010; - public static final short BACK_FLAG = 0x0020; - public static final short LS_CLK_FLAG = 0x0040; - public static final short RS_CLK_FLAG = 0x0080; - - public static final short PACKET_LENGTH = 28; - - private short buttonFlags; - private byte leftTrigger; - private byte rightTrigger; - private short leftStickX; - private short leftStickY; - private short rightStickX; - private short rightStickY; - - public NvInputPacket(short buttonFlags, byte leftTrigger, byte rightTrigger, - short leftStickX, short leftStickY, - short rightStickX, short rightStickY) - { - this.buttonFlags = buttonFlags; - this.leftTrigger = leftTrigger; - this.rightTrigger = rightTrigger; - this.leftStickX = leftStickX; - this.leftStickY = leftStickY; - this.rightStickX = rightStickX; - this.rightStickY = rightStickY; - } - - public byte[] toWire() - { - ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.LITTLE_ENDIAN); - - bb.put(HEADER); - bb.putShort(buttonFlags); - bb.put(leftTrigger); - bb.put(rightTrigger); - bb.putShort(leftStickX); - bb.putShort(leftStickY); - bb.putShort(rightStickX); - bb.putShort(rightStickY); - bb.put(TAIL); - - return bb.array(); - } - } \ No newline at end of file + return bb.array(); + } +} diff --git a/src/com/limelight/nvstream/input/NvMouseButtonPacket.java b/src/com/limelight/nvstream/input/NvMouseButtonPacket.java new file mode 100644 index 00000000..8cb87ac7 --- /dev/null +++ b/src/com/limelight/nvstream/input/NvMouseButtonPacket.java @@ -0,0 +1,36 @@ +package com.limelight.nvstream.input; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class NvMouseButtonPacket extends NvInputPacket { + + private byte buttonEventType; + + public static final int PACKET_TYPE = 0x5; + public static final int PAYLOAD_LENGTH = 5; + public static final int PACKET_LENGTH = PAYLOAD_LENGTH + + NvInputPacket.HEADER_LENGTH; + + public static final byte PRESS_EVENT = 0x07; + public static final byte RELEASE_EVENT = 0x08; + + public NvMouseButtonPacket(boolean leftButtonDown) + { + super(PACKET_TYPE); + + buttonEventType = leftButtonDown ? + PRESS_EVENT : RELEASE_EVENT; + } + + @Override + public byte[] toWire() { + ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH).order(ByteOrder.BIG_ENDIAN); + + bb.put(toWireHeader()); + bb.put(buttonEventType); + bb.putInt(1); // FIXME: button index? + + return bb.array(); + } +} diff --git a/src/com/limelight/nvstream/input/NvMouseMovePacket.java b/src/com/limelight/nvstream/input/NvMouseMovePacket.java new file mode 100644 index 00000000..edafa9c7 --- /dev/null +++ b/src/com/limelight/nvstream/input/NvMouseMovePacket.java @@ -0,0 +1,42 @@ +package com.limelight.nvstream.input; + +import java.nio.ByteBuffer; + +public class NvMouseMovePacket extends NvInputPacket { + + private static final byte[] HEADER = + { + 0x06, + 0x00, + 0x00, + 0x00 + }; + + public static final int PACKET_TYPE = 0x8; + public static final int PAYLOAD_LENGTH = 8; + public static final int PACKET_LENGTH = PAYLOAD_LENGTH + + NvInputPacket.HEADER_LENGTH; + + private short deltaX; + private short deltaY; + + public NvMouseMovePacket(short deltaX, short deltaY) + { + super(PACKET_TYPE); + + this.deltaX = deltaX; + this.deltaY = deltaY; + } + + @Override + public byte[] toWire() { + ByteBuffer bb = ByteBuffer.allocate(PACKET_LENGTH); + + bb.put(toWireHeader()); + bb.put(HEADER); + bb.putShort(deltaX); + bb.putShort(deltaY); + + return bb.array(); + } +}