improve virtual controller:

* add digital 8-Way pad
  * add on screen element size and position configuration
  * begin with cleanup
This commit is contained in:
Karim 2016-01-03 11:12:43 +01:00
parent 4c533fedfd
commit f23bb9fac1
19 changed files with 1165 additions and 1055 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="limelight-android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="moonlight-new" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle"> <facet type="android-gradle" name="Android-Gradle">
<configuration> <configuration>
@ -85,24 +85,18 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/nonRootDebug" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/tmp" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" /> <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" /> <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content> </content>

View File

@ -76,18 +76,7 @@
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.AppView" /> android:value="com.limelight.AppView" />
</activity> </activity>
<activity
android:name=".binding.input.virtual_controller.VirtualControllerConfiguration"
android:screenOrientation="landscape"
android:theme="@style/StreamTheme"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
</activity>
<activity
android:name=".binding.input.virtual_controller.VirtualControllerSettings"
android:screenOrientation="landscape"
android:theme="@android:style/Theme.Holo.Dialog"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
</activity>
<service <service
android:name=".discovery.DiscoveryService" android:name=".discovery.DiscoveryService"
android:label="mDNS PC Auto-Discovery Service" /> android:label="mDNS PC Auto-Discovery Service" />

View File

@ -287,9 +287,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
evdevHandler.start(); evdevHandler.start();
} }
if (prefConfig.virtualController_enable) if (prefConfig.virtualController_enable) {
{ // create virtual onscreen controller
virtualController = new VirtualController(conn, (FrameLayout) findViewById(R.id.surfaceView).getParent(), getApplicationContext()); virtualController = new VirtualController(conn,
(FrameLayout)findViewById(R.id.surfaceView).getParent(),
this);
} }
if (prefConfig.usbDriver) { if (prefConfig.usbDriver) {
@ -315,6 +317,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Apply the size change // Apply the size change
sv.setLayoutParams(lp); sv.setLayoutParams(lp);
// refresh virtual controller layout
if (virtualController != null) {
virtualController.refreshLayout();
}
} }
private void checkDataConnection() private void checkDataConnection()

View File

@ -1,3 +1,7 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller; package com.limelight.binding.input.virtual_controller;
import android.content.Context; import android.content.Context;
@ -10,88 +14,199 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* Created by Karim Mreisi on 30.11.2014. * This is a analog stick on screen element. It is used to get 2-Axis user input.
*/ */
public class AnalogStick extends VirtualControllerElement public class AnalogStick extends VirtualControllerElement {
{
float radius_complete = 0;
float radius_minimum = 0;
float radius_dead_zone = 0;
float radius_analog_stick = 0;
float position_pressed_x = 0; /** outer radius size in percent of the ui element */
float position_pressed_y = 0; public static final int SIZE_RADIUS_COMPLETE = 90;
/** analog stick size in percent of the ui element */
public static final int SIZE_RADIUS_ANALOG_STICK = 90;
/** dead zone size in percent of the ui element */
public static final int SIZE_RADIUS_DEADZONE = 90;
/** time frame for a double click */
public final static long timeoutDoubleClick = 250;
float position_moved_x = 0; /**
float position_moved_y = 0; * Listener interface to update registered observers.
*/
public interface AnalogStickListener {
float position_stick_x = 0; /**
float position_stick_y = 0; * onMovement event will be fired on real analog stick movement (outside of the deadzone).
* @param x horizontal position, value from -1.0 ... 0 .. 1.0
* @param y vertical position, value from -1.0 ... 0 .. 1.0
*/
void onMovement(float x, float y);
Paint paint = new Paint(); /**
* onClick event will be fired on click on the analog stick
*/
void onClick();
/**
* onDoubleClick event will be fired on a double click in a short time frame on the analog
* stick.
*/
void onDoubleClick();
/**
* onRevoke event will be fired on unpress of the analog stick.
*/
void onRevoke();
}
/**
* Movement states of the analog sick.
*/
private enum STICK_STATE {
NO_MOVEMENT,
MOVED_IN_DEAD_ZONE,
MOVED_ACTIVE
}
/**
* Click type states.
*/
private enum CLICK_STATE {
SINGLE,
DOUBLE
}
/** configuration if the analog stick should be displayed as circle or square*/
private boolean circle_stick = true; // TODO: implement square sick for simulations
/** outer radius, this size will be automatically updated on resize */
private float radius_complete = 0;
/** analog stick radius, this size will be automatically updated on resize */
private float radius_analog_stick = 0;
/** dead zone radius, this size will be automatically updated on resize */
private float radius_dead_zone = 0;
/** horizontal position in relation to the center of the element */
private float relative_x = 0;
/** vertical position in relation to the center of the element */
private float relative_y = 0;
_STICK_STATE stick_state = _STICK_STATE.NO_MOVEMENT; private double movement_radius = 0;
_CLICK_STATE click_state = _CLICK_STATE.SINGLE; private double movement_angle = 0;
List<AnalogStickListener> listeners = new ArrayList<>(); private float position_stick_x = 0;
OnTouchListener onTouchListener = null; private float position_stick_y = 0;
private long timeoutDoubleClick = 250;
private Paint paint = new Paint();
private STICK_STATE stick_state = STICK_STATE.NO_MOVEMENT;
private CLICK_STATE click_state = CLICK_STATE.SINGLE;
private List<AnalogStickListener> listeners = new ArrayList<>();
private long timeLastClick = 0; private long timeLastClick = 0;
public AnalogStick(Context context) private static double getMovementRadius(float x, float y) {
{ // corner cases
super(context); if (x == 0) {
return y > 0 ? y : -y;
}
if (y == 0) {
return x > 0 ? x : -x;
}
// return hypotenuse (pythagoras)
return Math.sqrt(x * x + y * y);
}
private static double getAngle(float way_x, float way_y) {
double angle = 0;
// prevent divisions by zero for corner cases
if (way_x == 0) {
return way_y < 0 ? Math.PI : 0;
} else if (way_y == 0) {
if (way_x > 0) {
return Math.PI * 3 / 2;
} else if (way_x < 0) {
return Math.PI * 1 / 2;
}
}
// return correct calculated angle for each quadrant
if (way_x > 0) {
if (way_y < 0) {
// first quadrant
return 3 * Math.PI / 2 + Math.atan((double) (-way_y / way_x));
} else {
// second quadrant
return Math.PI + Math.atan((double) (way_x / way_y));
}
} else {
if (way_y > 0) {
// third quadrant
return Math.PI / 2 + Math.atan((double) (way_y / -way_x));
} else {
// fourth quadrant
return 0 + Math.atan((double) (-way_x / -way_y));
}
}
}
public AnalogStick(VirtualController controller, Context context) {
super(controller, context);
// reset stick position
position_stick_x = getWidth() / 2; position_stick_x = getWidth() / 2;
position_stick_y = getHeight() / 2; position_stick_y = getHeight() / 2;
} }
public void addAnalogStickListener(AnalogStickListener listener) public void addAnalogStickListener(AnalogStickListener listener) {
{
listeners.add(listener); listeners.add(listener);
} }
public void setOnTouchListener(OnTouchListener listener) private void notifyOnMovement(float x, float y) {
{ _DBG("movement x: " + x + " movement y: " + y);
onTouchListener = listener; // notify listeners
for (AnalogStickListener listener : listeners) {
listener.onMovement(x, y);
}
} }
public void setColors(int normalColor, int pressedColor) private void notifyOnClick() {
{ _DBG("click");
// notify listeners
for (AnalogStickListener listener : listeners) {
listener.onClick();
}
}
private void notifyOnDoubleClick() {
_DBG("double click");
// notify listeners
for (AnalogStickListener listener : listeners) {
listener.onDoubleClick();
}
}
private void notifyOnRevoke() {
_DBG("revoke");
// notify listeners
for (AnalogStickListener listener : listeners) {
listener.onRevoke();
}
}
public void setColors(int normalColor, int pressedColor) {
this.normalColor = normalColor; this.normalColor = normalColor;
this.pressedColor = pressedColor; this.pressedColor = pressedColor;
} }
private double getMovementRadius(float x, float y)
{
if (x == 0)
{
return y > 0 ? y : -y;
}
if (y == 0)
{
return x > 0 ? x : -x;
}
return Math.sqrt(x * x + y * y);
}
@Override @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) protected void onSizeChanged(int w, int h, int oldw, int oldh) {
{ // calculate new radius sizes depending
radius_complete = getPercent(getCorrectWidth() / 2, 90); radius_complete = getPercent(getCorrectWidth() / 2, 90);
radius_minimum = getPercent(getCorrectWidth() / 2, 30); radius_dead_zone = getPercent(getCorrectWidth() / 2, 30);
radius_dead_zone = getPercent(getCorrectWidth() / 2, 10);
radius_analog_stick = getPercent(getCorrectWidth() / 2, 20); radius_analog_stick = getPercent(getCorrectWidth() / 2, 20);
super.onSizeChanged(w, h, oldw, oldh); super.onSizeChanged(w, h, oldw, oldh);
} }
@Override @Override
protected void onDraw(Canvas canvas) protected void onElementDraw(Canvas canvas) {
{
// set transparent background // set transparent background
canvas.drawColor(Color.TRANSPARENT); canvas.drawColor(Color.TRANSPARENT);
@ -99,293 +214,126 @@ public class AnalogStick extends VirtualControllerElement
paint.setStrokeWidth(getPercent(getCorrectWidth() / 2, 2)); paint.setStrokeWidth(getPercent(getCorrectWidth() / 2, 2));
// draw outer circle // draw outer circle
if (!isPressed() || click_state == _CLICK_STATE.SINGLE) if (!isPressed() || click_state == CLICK_STATE.SINGLE) {
{
paint.setColor(normalColor); paint.setColor(normalColor);
} } else {
else
{
paint.setColor(pressedColor); paint.setColor(pressedColor);
} }
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint); canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint);
paint.setColor(normalColor); paint.setColor(normalColor);
// draw minimum // draw dead zone
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_minimum, paint); canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_dead_zone, paint);
// draw stick depending on state (no movement, moved, active(out of dead zone)) // draw stick depending on state
switch (stick_state) switch (stick_state) {
{ case NO_MOVEMENT: {
case NO_MOVEMENT:
{
paint.setColor(normalColor); paint.setColor(normalColor);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_analog_stick, paint); canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_analog_stick, paint);
break; break;
} }
case MOVED_IN_DEAD_ZONE: case MOVED_IN_DEAD_ZONE: {
{
paint.setColor(normalColor); paint.setColor(normalColor);
canvas.drawCircle(position_stick_x, position_stick_y, radius_analog_stick, paint); canvas.drawCircle(position_stick_x, position_stick_y, radius_analog_stick, paint);
break; break;
} }
case MOVED_ACTIVE: case MOVED_ACTIVE: {
{
paint.setColor(pressedColor); paint.setColor(pressedColor);
canvas.drawCircle(position_stick_x, position_stick_y, radius_analog_stick, paint); canvas.drawCircle(position_stick_x, position_stick_y, radius_analog_stick, paint);
break; break;
} }
} }
super.onDraw(canvas);
} }
private double getAngle(float way_x, float way_y) private void updatePosition() {
{ // get 100% way
double angle = 0; float complete = (radius_complete - radius_analog_stick - radius_dead_zone);
// prevent divisions by zero // calculate relative way
if (way_x == 0) float correlated_y = (float) (Math.sin(Math.PI / 2 - movement_angle) * (movement_radius));
{ float correlated_x = (float) (Math.cos(Math.PI / 2 - movement_angle) * (movement_radius));
if (way_y > 0)
{
angle = 0;
}
else if (way_y < 0)
{
angle = Math.PI;
}
}
else if (way_y == 0)
{
if (way_x > 0)
{
angle = Math.PI * 3 / 2;
}
else if (way_x < 0)
{
angle = Math.PI * 1 / 2;
}
}
else
{
if (way_x > 0)
{
if (way_y < 0)
{ // first quadrant
angle =
3 * Math.PI / 2 + Math.atan((double) (-way_y / way_x));
}
else
{ // second quadrant
angle = Math.PI + Math.atan((double) (way_x / way_y));
}
}
else
{
if (way_y > 0)
{ // third quadrant
angle = Math.PI / 2 + Math.atan((double) (way_y / -way_x));
}
else
{ // fourth quadrant
angle = 0 + Math.atan((double) (-way_x / -way_y));
}
}
}
_DBG("angle: " + angle + " way y: " + way_y + " way x: " + way_x);
return angle;
}
private void moveActionCallback(float x, float y)
{
_DBG("movement x: " + x + " movement y: " + y);
// notify listeners
for (AnalogStickListener listener : listeners)
{
listener.onMovement(x, y);
}
}
private void clickActionCallback()
{
_DBG("click");
// notify listeners
for (AnalogStickListener listener : listeners)
{
listener.onClick();
}
}
private void doubleClickActionCallback()
{
_DBG("double click");
// notify listeners
for (AnalogStickListener listener : listeners)
{
listener.onDoubleClick();
}
}
private void revokeActionCallback()
{
_DBG("revoke");
// notify listeners
for (AnalogStickListener listener : listeners)
{
listener.onRevoke();
}
}
private void updatePosition()
{
// get real way for each axis
float way_center_x = -(getWidth() / 2 - position_moved_x);
float way_center_y = -(getHeight() / 2 - position_moved_y);
// get radius and angel of movement from center
double movement_radius = getMovementRadius(way_center_x, way_center_y);
double movement_angle = getAngle(way_center_x, way_center_y);
// get dead zone way for each axis
float way_pressed_x = position_pressed_x - position_moved_x;
float way_pressed_y = position_pressed_y - position_moved_y;
// get radius and angel from pressed position
double movement_dead_zone_radius = getMovementRadius(way_pressed_x, way_pressed_y);
// chop radius if out of outer circle
if (movement_radius > (radius_complete - radius_analog_stick))
{
movement_radius = radius_complete - radius_analog_stick;
}
// calculate new positions
float correlated_y =
(float) (Math.sin(Math.PI / 2 - movement_angle) * (movement_radius));
float correlated_x =
(float) (Math.cos(Math.PI / 2 - movement_angle) * (movement_radius));
float complete = (radius_complete - radius_analog_stick - radius_minimum);
float movement_x;
float movement_y;
movement_x = -(1 / complete) * (correlated_x - (correlated_x > 0 ? radius_minimum : -radius_minimum));
movement_y = (1 / complete) * (correlated_y - (correlated_y > 0 ? radius_minimum : -radius_minimum));
// update positions
position_stick_x = getWidth() / 2 - correlated_x; position_stick_x = getWidth() / 2 - correlated_x;
position_stick_y = getHeight() / 2 - correlated_y; position_stick_y = getHeight() / 2 - correlated_y;
// check if analog stick is outside of dead zone and minimum // set active depending on dead zone
if (movement_radius > radius_minimum && movement_dead_zone_radius > radius_dead_zone) stick_state = movement_radius > radius_dead_zone ?
{ STICK_STATE.MOVED_ACTIVE : STICK_STATE.MOVED_IN_DEAD_ZONE;
// set active
stick_state = _STICK_STATE.MOVED_ACTIVE;
}
if (stick_state == _STICK_STATE.MOVED_ACTIVE) // trigger move event if state active
{ if (stick_state == STICK_STATE.MOVED_ACTIVE) {
moveActionCallback(movement_x, movement_y); notifyOnMovement(-(1 / complete) *
(correlated_x - (correlated_x > 0 ? radius_dead_zone : -radius_dead_zone)), (1 / complete) *
(correlated_y - (correlated_y > 0 ? radius_dead_zone : -radius_dead_zone)));
} }
} }
@Override @Override
public boolean onTouchEvent(MotionEvent event) public boolean onElementTouchEvent(MotionEvent event) {
{ // save last click state
// get masked (not specific to a pointer) action CLICK_STATE lastClickState = click_state;
int action = event.getActionMasked();
_CLICK_STATE lastClickState = click_state;
position_moved_x = event.getX(); // get absolute way for each axis
position_moved_y = event.getY(); relative_x = -(getWidth() / 2 - event.getX());
relative_y = -(getHeight() / 2 - event.getY());
switch (action) // get radius and angel of movement from center
{ movement_radius = getMovementRadius(relative_x, relative_y);
movement_angle = getAngle(relative_x, relative_y);
// chop radius if out of outer circle and already pressed
if (movement_radius > (radius_complete - radius_analog_stick)) {
// not pressed already, so ignore event from outer circle
if (!isPressed()) {
return false;
}
movement_radius = radius_complete - radius_analog_stick;
}
// handle event depending on action
switch (event.getActionMasked()) {
// down event (touch event)
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_DOWN: {
{ // set to dead zoned, will be corrected in update position if necessary
setPressed(true); stick_state = STICK_STATE.MOVED_IN_DEAD_ZONE;
position_pressed_x = position_moved_x;
position_pressed_y = position_moved_y;
stick_state = _STICK_STATE.MOVED_IN_DEAD_ZONE;
// check for double click // check for double click
if (lastClickState == _CLICK_STATE.SINGLE && timeLastClick + timeoutDoubleClick > System.currentTimeMillis()) if (lastClickState == CLICK_STATE.SINGLE &&
{ timeLastClick + timeoutDoubleClick > System.currentTimeMillis()) {
click_state = _CLICK_STATE.DOUBLE; click_state = CLICK_STATE.DOUBLE;
notifyOnDoubleClick();
doubleClickActionCallback(); } else {
click_state = CLICK_STATE.SINGLE;
notifyOnClick();
} }
else // reset last click timestamp
{
click_state = _CLICK_STATE.SINGLE;
clickActionCallback();
}
timeLastClick = System.currentTimeMillis(); timeLastClick = System.currentTimeMillis();
// set item pressed and update
setPressed(true);
break; break;
} }
// up event (revoke touch)
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP: {
{
setPressed(false); setPressed(false);
stick_state = _STICK_STATE.NO_MOVEMENT;
revokeActionCallback();
break; break;
} }
} }
if (isPressed()) if (isPressed()) {
{ // when is pressed calculate new positions (will trigger movement if necessary) // when is pressed calculate new positions (will trigger movement if necessary)
updatePosition(); updatePosition();
} else {
stick_state = STICK_STATE.NO_MOVEMENT;
notifyOnRevoke();
// not longer pressed reset analog stick
notifyOnMovement(0, 0);
} }
else // refresh view
{ // not longer pressed reset analog stick
moveActionCallback(0, 0);
}
// to get view refreshed
invalidate(); invalidate();
// accept the touch event
return true; return true;
} }
private enum _STICK_STATE
{
NO_MOVEMENT,
MOVED_IN_DEAD_ZONE,
MOVED_ACTIVE
}
private enum _CLICK_STATE
{
SINGLE,
DOUBLE
}
public interface AnalogStickListener
{
void onMovement(float x, float y);
void onClick();
void onRevoke();
void onDoubleClick();
}
} }

View File

@ -1,3 +1,7 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller; package com.limelight.binding.input.virtual_controller;
import android.content.Context; import android.content.Context;
@ -13,14 +17,42 @@ import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
/** /**
* Created by Karim on 24.01.2015. * This is a digital button on screen element. It is used to get click and double click user input.
*/ */
public class DigitalButton extends VirtualControllerElement public class DigitalButton extends VirtualControllerElement {
{
static List<DigitalButton> allButtonsList = new ArrayList<>();
List<DigitalButtonListener> listeners = new ArrayList<>(); /**
OnTouchListener onTouchListener = null; * Listener interface to update registered observers.
*/
public interface DigitalButtonListener {
/**
* onClick event will be fired on button click.
*/
void onClick();
/**
* onLongClick event will be fired on button long click.
*/
void onLongClick();
/**
* onRelease event will be fired on button unpress.
*/
void onRelease();
}
/**
*
*/
private class TimerLongClickTimerTask extends TimerTask {
@Override
public void run() {
onLongClickCallback();
}
}
private List<DigitalButtonListener> listeners = new ArrayList<DigitalButtonListener>();
private String text = ""; private String text = "";
private int icon = -1; private int icon = -1;
private long timerLongClickTimeout = 3000; private long timerLongClickTimeout = 3000;
@ -30,17 +62,14 @@ public class DigitalButton extends VirtualControllerElement
private int layer; private int layer;
private DigitalButton movingButton = null; private DigitalButton movingButton = null;
boolean inRange(float x, float y) boolean inRange(float x, float y) {
{
return (this.getX() < x && this.getX() + this.getWidth() > x) && return (this.getX() < x && this.getX() + this.getWidth() > x) &&
(this.getY() < y && this.getY() + this.getHeight() > y); (this.getY() < y && this.getY() + this.getHeight() > y);
} }
public boolean checkMovement(float x, float y, DigitalButton movingButton) public boolean checkMovement(float x, float y, DigitalButton movingButton) {
{
// check if the movement happened in the same layer // check if the movement happened in the same layer
if (movingButton.layer != this.layer) if (movingButton.layer != this.layer) {
{
return false; return false;
} }
@ -49,36 +78,27 @@ public class DigitalButton extends VirtualControllerElement
// check if the movement directly happened on the button // check if the movement directly happened on the button
if ((this.movingButton == null || movingButton == this.movingButton) if ((this.movingButton == null || movingButton == this.movingButton)
&& this.inRange(x, y)) && this.inRange(x, y)) {
{
// set button pressed state depending on moving button pressed state // set button pressed state depending on moving button pressed state
if (this.isPressed() != movingButton.isPressed()) if (this.isPressed() != movingButton.isPressed()) {
{
this.setPressed(movingButton.isPressed()); this.setPressed(movingButton.isPressed());
} }
} }
// check if the movement is outside of the range and the movement button // check if the movement is outside of the range and the movement button
// is saved moving button // is the saved moving button
else if (movingButton == this.movingButton) else if (movingButton == this.movingButton) {
{
this.setPressed(false); this.setPressed(false);
} }
// check if a change occurred // check if a change occurred
if (wasPressed != isPressed()) if (wasPressed != isPressed()) {
{ if (isPressed()) {
// is pressed set moving button and emit click event
if (isPressed())
{ // is pressed set moving button and emit click event
this.movingButton = movingButton; this.movingButton = movingButton;
onClickCallback(); onClickCallback();
} } else {
// no longer pressed reset moving button and emit release event
else
{ // no longer pressed reset moving button and emit release event
this.movingButton = null; this.movingButton = null;
onReleaseCallback(); onReleaseCallback();
} }
@ -90,51 +110,35 @@ public class DigitalButton extends VirtualControllerElement
return false; return false;
} }
private void checkMovementForAllButtons(float x, float y) private void checkMovementForAllButtons(float x, float y) {
{ for (VirtualControllerElement element : virtualController.getElements()) {
for (DigitalButton button : allButtonsList) if (element != this && element instanceof DigitalButton){
{ ((DigitalButton)element).checkMovement(x, y, this);
if (button != this)
{
button.checkMovement(x, y, this);
} }
} }
} }
public DigitalButton(int layer, Context context) public DigitalButton(VirtualController controller, int layer, Context context) {
{ super(controller, context);
super(context);
this.layer = layer; this.layer = layer;
allButtonsList.add(this);
} }
public void addDigitalButtonListener(DigitalButtonListener listener) public void addDigitalButtonListener(DigitalButtonListener listener) {
{
listeners.add(listener); listeners.add(listener);
} }
public void setOnTouchListener(OnTouchListener listener) public void setText(String text) {
{
onTouchListener = listener;
}
public void setText(String text)
{
this.text = text; this.text = text;
invalidate(); invalidate();
} }
public void setIcon(int id) public void setIcon(int id) {
{
this.icon = id; this.icon = id;
invalidate(); invalidate();
} }
@Override @Override
protected void onDraw(Canvas canvas) protected void onElementDraw(Canvas canvas) {
{
// set transparent background // set transparent background
canvas.drawColor(Color.TRANSPARENT); canvas.drawColor(Color.TRANSPARENT);
@ -146,90 +150,58 @@ public class DigitalButton extends VirtualControllerElement
paint.setColor(isPressed() ? pressedColor : normalColor); paint.setColor(isPressed() ? pressedColor : normalColor);
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
canvas.drawRect( canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, paint);
1, 1,
getWidth() - 1, getHeight() - 1,
paint
);
if (icon != -1) if (icon != -1) {
{
Drawable d = getResources().getDrawable(icon); Drawable d = getResources().getDrawable(icon);
d.setBounds(5, 5, getWidth() - 5, getHeight() - 5); d.setBounds(5, 5, getWidth() - 5, getHeight() - 5);
d.draw(canvas); d.draw(canvas);
} } else {
else
{
paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawText(text, canvas.drawText(text, getPercent(getWidth(), 50), getPercent(getHeight(), 73), paint);
getPercent(getWidth(), 50), getPercent(getHeight(), 73), }
paint);
} }
super.onDraw(canvas); private void onClickCallback() {
}
private void onClickCallback()
{
_DBG("clicked"); _DBG("clicked");
// notify listeners // notify listeners
for (DigitalButtonListener listener : listeners) for (DigitalButtonListener listener : listeners) {
{
listener.onClick(); listener.onClick();
} }
timerLongClick = new Timer(); timerLongClick = new Timer();
longClickTimerTask = new TimerLongClickTimerTask(); longClickTimerTask = new TimerLongClickTimerTask();
timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout); timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout);
} }
private void onLongClickCallback() private void onLongClickCallback() {
{
_DBG("long click"); _DBG("long click");
// notify listeners // notify listeners
for (DigitalButtonListener listener : listeners) for (DigitalButtonListener listener : listeners) {
{
listener.onLongClick(); listener.onLongClick();
} }
} }
private void onReleaseCallback() private void onReleaseCallback() {
{
_DBG("released"); _DBG("released");
// notify listeners // notify listeners
for (DigitalButtonListener listener : listeners) for (DigitalButtonListener listener : listeners) {
{
listener.onRelease(); listener.onRelease();
} }
timerLongClick.cancel(); timerLongClick.cancel();
longClickTimerTask.cancel(); longClickTimerTask.cancel();
} }
@Override @Override
public boolean onTouchEvent(MotionEvent event) public boolean onElementTouchEvent(MotionEvent event) {
{
/*
if (onTouchListener != null)
{
return onTouchListener.onTouch(this, event);
}
*/
// get masked (not specific to a pointer) action // get masked (not specific to a pointer) action
float x = getX() + event.getX(); float x = getX() + event.getX();
float y = getY() + event.getY(); float y = getY() + event.getY();
int action = event.getActionMasked(); int action = event.getActionMasked();
switch (action) switch (action) {
{
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_DOWN: {
{
movingButton = null; movingButton = null;
setPressed(true); setPressed(true);
onClickCallback(); onClickCallback();
@ -238,16 +210,14 @@ public class DigitalButton extends VirtualControllerElement
return true; return true;
} }
case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_MOVE: {
{
checkMovementForAllButtons(x, y); checkMovementForAllButtons(x, y);
return true; return true;
} }
case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP: {
{
setPressed(false); setPressed(false);
onReleaseCallback(); onReleaseCallback();
@ -257,29 +227,9 @@ public class DigitalButton extends VirtualControllerElement
return true; return true;
} }
default: default: {
{
} }
} }
return true; return true;
} }
public interface DigitalButtonListener
{
void onClick();
void onLongClick();
void onRelease();
}
private class TimerLongClickTimerTask extends TimerTask
{
@Override
public void run()
{
onLongClickCallback();
}
}
} }

View File

@ -1,3 +1,7 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller; package com.limelight.binding.input.virtual_controller;
import android.content.Context; import android.content.Context;
@ -9,11 +13,7 @@ import android.view.MotionEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** public class DigitalPad extends VirtualControllerElement {
* Created by Karim Mreisi on 23.01.2015.
*/
public class DigitalPad extends VirtualControllerElement
{
public final static int DIGITAL_PAD_DIRECTION_NO_DIRECTION = 0; public final static int DIGITAL_PAD_DIRECTION_NO_DIRECTION = 0;
int direction = DIGITAL_PAD_DIRECTION_NO_DIRECTION; int direction = DIGITAL_PAD_DIRECTION_NO_DIRECTION;
public final static int DIGITAL_PAD_DIRECTION_LEFT = 1; public final static int DIGITAL_PAD_DIRECTION_LEFT = 1;
@ -21,26 +21,17 @@ public class DigitalPad extends VirtualControllerElement
public final static int DIGITAL_PAD_DIRECTION_RIGHT = 4; public final static int DIGITAL_PAD_DIRECTION_RIGHT = 4;
public final static int DIGITAL_PAD_DIRECTION_DOWN = 8; public final static int DIGITAL_PAD_DIRECTION_DOWN = 8;
List<DigitalPadListener> listeners = new ArrayList<DigitalPadListener>(); List<DigitalPadListener> listeners = new ArrayList<DigitalPadListener>();
OnTouchListener onTouchListener = null;
public DigitalPad(Context context) public DigitalPad(VirtualController controller, Context context) {
{ super(controller, context);
super(context);
} }
public void addDigitalPadListener(DigitalPadListener listener) public void addDigitalPadListener(DigitalPadListener listener) {
{
listeners.add(listener); listeners.add(listener);
} }
public void setOnTouchListener(OnTouchListener listener)
{
onTouchListener = listener;
}
@Override @Override
protected void onDraw(Canvas canvas) protected void onElementDraw(Canvas canvas) {
{
// set transparent background // set transparent background
canvas.drawColor(Color.TRANSPARENT); canvas.drawColor(Color.TRANSPARENT);
@ -50,8 +41,7 @@ public class DigitalPad extends VirtualControllerElement
paint.setTextAlign(Paint.Align.CENTER); paint.setTextAlign(Paint.Align.CENTER);
paint.setStrokeWidth(3); paint.setStrokeWidth(3);
if (direction == DIGITAL_PAD_DIRECTION_NO_DIRECTION) if (direction == DIGITAL_PAD_DIRECTION_NO_DIRECTION) {
{
// draw no direction rect // draw no direction rect
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
paint.setColor(normalColor); paint.setColor(normalColor);
@ -84,7 +74,7 @@ public class DigitalPad extends VirtualControllerElement
); );
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
canvas.drawLine( canvas.drawLine(
0, getPercent(getWidth(), 33), 0, getPercent(getHeight(), 33),
getPercent(getWidth(), 33), 0, getPercent(getWidth(), 33), 0,
paint paint
); );
@ -169,87 +159,60 @@ public class DigitalPad extends VirtualControllerElement
getPercent(getWidth(), 0), getPercent(getHeight(), 66), getPercent(getWidth(), 0), getPercent(getHeight(), 66),
paint paint
); );
super.onDraw(canvas);
} }
private void newDirectionCallback(int direction) private void newDirectionCallback(int direction) {
{
_DBG("direction: " + direction); _DBG("direction: " + direction);
// notify listeners // notify listeners
for (DigitalPadListener listener : listeners) for (DigitalPadListener listener : listeners) {
{
listener.onDirectionChange(direction); listener.onDirectionChange(direction);
} }
} }
@Override @Override
public boolean onTouchEvent(MotionEvent event) public boolean onElementTouchEvent(MotionEvent event) {
{
if (onTouchListener != null)
{
return onTouchListener.onTouch(this, event);
}
// get masked (not specific to a pointer) action // get masked (not specific to a pointer) action
int action = event.getActionMasked(); switch (event.getActionMasked()) {
switch (action)
{
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_DOWN:
{ case MotionEvent.ACTION_MOVE: {
direction = 0; direction = 0;
if (event.getX() < getPercent(getWidth(), 33)) if (event.getX() < getPercent(getWidth(), 33)) {
{
direction |= DIGITAL_PAD_DIRECTION_LEFT; direction |= DIGITAL_PAD_DIRECTION_LEFT;
} }
if (event.getX() > getPercent(getWidth(), 66)) {
if (event.getX() > getPercent(getWidth(), 66))
{
direction |= DIGITAL_PAD_DIRECTION_RIGHT; direction |= DIGITAL_PAD_DIRECTION_RIGHT;
} }
if (event.getY() > getPercent(getHeight(), 66)) {
if (event.getY() > getPercent(getHeight(), 66))
{
direction |= DIGITAL_PAD_DIRECTION_DOWN; direction |= DIGITAL_PAD_DIRECTION_DOWN;
} }
if (event.getY() < getPercent(getHeight(), 33)) {
if (event.getY() < getPercent(getHeight(), 33))
{
direction |= DIGITAL_PAD_DIRECTION_UP; direction |= DIGITAL_PAD_DIRECTION_UP;
} }
newDirectionCallback(direction); newDirectionCallback(direction);
invalidate(); invalidate();
return true; return true;
} }
case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP: {
{
direction = 0; direction = 0;
newDirectionCallback(direction); newDirectionCallback(direction);
invalidate(); invalidate();
return true; return true;
} }
default: default: {
{
} }
} }
return true; return true;
} }
public interface DigitalPadListener public interface DigitalPadListener {
{
void onDirectionChange(int direction); void onDirectionChange(int direction);
} }
} }

View File

@ -0,0 +1,49 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller;
import android.content.Context;
import com.limelight.nvstream.input.ControllerPacket;
public class LeftAnalogStick extends AnalogStick {
public LeftAnalogStick(final VirtualController controller, final Context context) {
super(controller, context);
addAnalogStickListener(new AnalogStick.AnalogStickListener() {
@Override
public void onMovement(float x, float y) {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.leftStickX = (short) (x * 0x7FFE);
inputContext.leftStickY = (short) (y * 0x7FFE);
controller.sendControllerInputContext();
}
@Override
public void onClick() {
}
@Override
public void onDoubleClick() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.inputMap |= ControllerPacket.LS_CLK_FLAG;
controller.sendControllerInputContext();
}
@Override
public void onRevoke() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.inputMap &= ~ControllerPacket.LS_CLK_FLAG;
controller.sendControllerInputContext();
}
});
}
}

View File

@ -0,0 +1,35 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller;
import android.content.Context;
public class LeftTrigger extends DigitalButton {
public LeftTrigger(final VirtualController controller, final int layer, final Context context) {
super(controller, layer, context);
addDigitalButtonListener(new DigitalButton.DigitalButtonListener() {
@Override
public void onClick() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.leftTrigger = (byte)0xFF;
controller.sendControllerInputContext();
}
@Override
public void onLongClick() {}
@Override
public void onRelease() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.leftTrigger = (byte)0x00;
controller.sendControllerInputContext();
}
});
}
}

View File

@ -0,0 +1,49 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller;
import android.content.Context;
import com.limelight.nvstream.input.ControllerPacket;
public class RightAnalogStick extends AnalogStick {
public RightAnalogStick(final VirtualController controller, final Context context) {
super(controller, context);
addAnalogStickListener(new AnalogStick.AnalogStickListener() {
@Override
public void onMovement(float x, float y) {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.rightStickX = (short) (x * 0x7FFE);
inputContext.rightStickY = (short) (y * 0x7FFE);
controller.sendControllerInputContext();
}
@Override
public void onClick() {
}
@Override
public void onDoubleClick() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.inputMap |= ControllerPacket.RS_CLK_FLAG;
controller.sendControllerInputContext();
}
@Override
public void onRevoke() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.inputMap &= ~ControllerPacket.RS_CLK_FLAG;
controller.sendControllerInputContext();
}
});
}
}

View File

@ -0,0 +1,35 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller;
import android.content.Context;
public class RightTrigger extends DigitalButton {
public RightTrigger(final VirtualController controller, final int layer, final Context context) {
super(controller, layer, context);
addDigitalButtonListener(new DigitalButton.DigitalButtonListener() {
@Override
public void onClick() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.rightTrigger = (byte)0xFF;
controller.sendControllerInputContext();
}
@Override
public void onLongClick() {}
@Override
public void onRelease() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.rightTrigger = (byte)0x00;
controller.sendControllerInputContext();
}
});
}
}

View File

@ -1,467 +1,148 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller; package com.limelight.binding.input.virtual_controller;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.view.View; import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.Toast;
import com.limelight.R; import com.limelight.R;
import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.ControllerPacket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** public class VirtualController {
* Created by Karim Mreisi on 30.11.2014. public class ControllerInputContext {
*/ public short inputMap = 0x0000;
public class VirtualController public byte leftTrigger = 0x00;
{ public byte rightTrigger = 0x00;
private static final boolean _PRINT_DEBUG_INFORMATION = false; public short rightStickX = 0x0000;
NvConnection connection = null; public short rightStickY = 0x0000;
public short leftStickX = 0x0000;
public short leftStickY = 0x0000;
}
public enum ControllerMode {
Active,
Configuration
}
private static final boolean _PRINT_DEBUG_INFORMATION = true;
private NvConnection connection = null;
private Context context = null; private Context context = null;
private short inputMap = 0x0000;
private byte leftTrigger = 0x00;
private byte rightTrigger = 0x00;
private short rightStickX = 0x0000;
private short rightStickY = 0x0000;
private short leftStickX = 0x0000;
private short leftStickY = 0x0000;
private FrameLayout frame_layout = null; private FrameLayout frame_layout = null;
private RelativeLayout relative_layout = null; private RelativeLayout relative_layout = null;
private RelativeLayout.LayoutParams layoutParamsButtonStart = null; ControllerMode currentMode = ControllerMode.Active;
private RelativeLayout.LayoutParams layoutParamsButtonSelect = null; ControllerInputContext inputContext = new ControllerInputContext();
private RelativeLayout.LayoutParams layoutParamsDPad = null;
private RelativeLayout.LayoutParams layoutParamsButtonA = null;
private RelativeLayout.LayoutParams layoutParamsButtonB = null;
private RelativeLayout.LayoutParams layoutParamsButtonX = null;
private RelativeLayout.LayoutParams layoutParamsButtonY = null;
private RelativeLayout.LayoutParams layoutParamsButtonLT = null;
private RelativeLayout.LayoutParams layoutParamsButtonRT = null;
private RelativeLayout.LayoutParams layoutParamsButtonLB = null;
private RelativeLayout.LayoutParams layoutParamsButtonRB = null;
private RelativeLayout.LayoutParams layoutParamsStick = null;
private RelativeLayout.LayoutParams layoutParamsStick2 = null;
private RelativeLayout.LayoutParams layoutParamsButtonConfigure = null; private RelativeLayout.LayoutParams layoutParamsButtonConfigure = null;
private Button buttonConfigure = null;
private DigitalButton buttonStart = null; private List<VirtualControllerElement> elements = new ArrayList<VirtualControllerElement>();
private DigitalButton buttonSelect = null;
private DigitalPad digitalPad = null; public VirtualController(final NvConnection conn, FrameLayout layout, final Context context) {
private DigitalButton buttonA = null;
private DigitalButton buttonB = null;
private DigitalButton buttonX = null;
private DigitalButton buttonY = null;
private DigitalButton buttonLT = null;
private DigitalButton buttonRT = null;
private DigitalButton buttonLB = null;
private DigitalButton buttonRB = null;
private AnalogStick stick = null;
private AnalogStick stick2 = null;
private DigitalButton buttonConfigure = null;
public VirtualController(final NvConnection conn, FrameLayout layout, final Context context)
{
this.connection = conn; this.connection = conn;
this.frame_layout = layout; this.frame_layout = layout;
this.context = context; this.context = context;
relative_layout = new RelativeLayout(context); relative_layout = new RelativeLayout(context);
relative_layout.addOnLayoutChangeListener(new View.OnLayoutChangeListener()
{
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
{
refreshLayout();
}
});
frame_layout.addView(relative_layout); frame_layout.addView(relative_layout);
digitalPad = new DigitalPad(context); buttonConfigure = new Button(context);
digitalPad.addDigitalPadListener(new DigitalPad.DigitalPadListener() buttonConfigure.setBackgroundResource(R.drawable.settings);
{ buttonConfigure.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onDirectionChange(int direction) public void onClick(View v) {
{ if (currentMode == ControllerMode.Configuration) {
do currentMode = ControllerMode.Active;
{ } else {
if (direction == DigitalPad.DIGITAL_PAD_DIRECTION_NO_DIRECTION) currentMode = ControllerMode.Configuration;
{
inputMap &= ~ControllerPacket.LEFT_FLAG;
inputMap &= ~ControllerPacket.RIGHT_FLAG;
inputMap &= ~ControllerPacket.UP_FLAG;
inputMap &= ~ControllerPacket.DOWN_FLAG;
break;
} }
Toast.makeText(context, "CHANGE MODE " + currentMode, Toast.LENGTH_SHORT).show();
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) > 0) relative_layout.invalidate();
{
inputMap |= ControllerPacket.LEFT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) > 0)
{
inputMap |= ControllerPacket.RIGHT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) > 0)
{
inputMap |= ControllerPacket.UP_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) > 0)
{
inputMap |= ControllerPacket.DOWN_FLAG;
}
}
while (false);
sendControllerInputPacket();
} }
}); });
buttonX = createDigitalButton("X", ControllerPacket.X_FLAG, context);
buttonY = createDigitalButton("Y", ControllerPacket.Y_FLAG, context);
buttonA = createDigitalButton("A", ControllerPacket.A_FLAG, context);
buttonB = createDigitalButton("B", ControllerPacket.B_FLAG, context);
buttonLT = new DigitalButton(2, context);
buttonLT.setText("LT");
buttonLT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
{
@Override
public void onClick()
{
leftTrigger = (byte) (1 * 0xFF);
sendControllerInputPacket();
} }
@Override public void removeElements() {
public void onLongClick() for (VirtualControllerElement element : elements) {
{ relative_layout.removeView(element);
elements.remove(element);
}
} }
@Override public void addElement(VirtualControllerElement element, int x, int y, int width, int height) {
public void onRelease() elements.add(element);
{ RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(width, height);
leftTrigger = (byte) (0 * 0xFF); layoutParams.setMargins(x, y, 0, 0);
sendControllerInputPacket(); relative_layout.addView(element, layoutParams);
}
});
buttonRT = new DigitalButton(2, context);
buttonRT.setText("RT");
buttonRT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
{
@Override
public void onClick()
{
rightTrigger = (byte) (0xFF);
sendControllerInputPacket();
} }
@Override public List<VirtualControllerElement> getElements() {
public void onLongClick() return elements;
{
} }
@Override private static final void _DBG(String text) {
public void onRelease() if (_PRINT_DEBUG_INFORMATION) {
{
rightTrigger = (byte) (0);
sendControllerInputPacket();
}
});
buttonLB = createDigitalButton("LB", ControllerPacket.LB_FLAG, context);
buttonRB = createDigitalButton("RB", ControllerPacket.RB_FLAG, context);
stick = new AnalogStick(context);
stick.addAnalogStickListener(new AnalogStick.AnalogStickListener()
{
@Override
public void onMovement(float x, float y)
{
leftStickX = (short) (x * 0x7FFE);
leftStickY = (short) (y * 0x7FFE);
_DBG("LEFT STICK MOVEMENT X: " + leftStickX + " Y: " + leftStickY);
sendControllerInputPacket();
}
@Override
public void onClick()
{
}
@Override
public void onDoubleClick()
{
inputMap |= ControllerPacket.LS_CLK_FLAG;
sendControllerInputPacket();
}
@Override
public void onRevoke()
{
inputMap &= ~ControllerPacket.LS_CLK_FLAG;
sendControllerInputPacket();
}
});
stick2 = new AnalogStick(context);
stick2.addAnalogStickListener(new AnalogStick.AnalogStickListener()
{
@Override
public void onMovement(float x, float y)
{
rightStickX = (short) (x * 0x7FFE);
rightStickY = (short) (y * 0x7FFE);
_DBG("RIGHT STICK MOVEMENT X: " + rightStickX + " Y: " + rightStickY);
sendControllerInputPacket();
}
@Override
public void onClick()
{
}
@Override
public void onDoubleClick()
{
inputMap |= ControllerPacket.RS_CLK_FLAG;
sendControllerInputPacket();
}
@Override
public void onRevoke()
{
inputMap &= ~ControllerPacket.RS_CLK_FLAG;
sendControllerInputPacket();
}
});
buttonStart = createDigitalButton("START", ControllerPacket.PLAY_FLAG, context);
buttonSelect =
createDigitalButton("SELECT", ControllerPacket.SPECIAL_BUTTON_FLAG, context);
buttonConfigure = new DigitalButton(1, context);
buttonConfigure.setIcon(R.drawable.settings);
buttonConfigure.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
{
@Override
public void onClick()
{
}
@Override
public void onLongClick()
{
openSettingsDialog();
}
@Override
public void onRelease()
{
}
});
refreshLayout();
}
private static final void _DBG(String text)
{
if (_PRINT_DEBUG_INFORMATION)
{
System.out.println("VirtualController: " + text); System.out.println("VirtualController: " + text);
} }
} }
private int getPercentageV(int percent) public void refreshLayout() {
{ relative_layout.removeAllViews();
return (int) (((float) frame_layout.getHeight() / (float) 100) * (float) percent); removeElements();
layoutParamsButtonConfigure = new RelativeLayout.LayoutParams(50, 50);
relative_layout.addView(buttonConfigure, layoutParamsButtonConfigure);
VirtualControllerConfigurationLoader.createDefaultLayout(this, context);
} }
private int getPercentageH(int percent) public ControllerMode getControllerMode () {
{ return currentMode;
return (int) (((float) frame_layout.getWidth() / (float) 100) * (float) percent);
} }
private void setPercentilePosition(RelativeLayout.LayoutParams parm, float pos_x, float pos_y) public ControllerInputContext getControllerInputContext () {
{ return inputContext;
parm.setMargins( }
(int) (((float) frame_layout.getWidth() / (float) 100 * pos_x) - ((float) parm.width / (float) 2)),
(int) (((float) frame_layout.getHeight() / (float) 100 * pos_y) - ((float) parm.height / (float) 2)), public void sendControllerInputContext() {
0, sendControllerInputPacket();
0 }
private void sendControllerInputPacket() {
try {
_DBG("INPUT_MAP + " + inputContext.inputMap);
_DBG("LEFT_TRIGGER " + inputContext.leftTrigger);
_DBG("RIGHT_TRIGGER " + inputContext.rightTrigger);
_DBG("LEFT STICK X: " + inputContext.leftStickX + " Y: " + inputContext.leftStickY);
_DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY);
_DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY);
if (connection != null) {
connection.sendControllerInput(
inputContext.inputMap,
inputContext.leftTrigger,
inputContext.rightTrigger,
inputContext.leftStickX,
inputContext.leftStickY,
inputContext.rightStickX,
inputContext.rightStickY
); );
} }
} catch (Exception e) {
public void openSettingsDialog()
{
Intent virtualControllerConfiguration =
new Intent(context, VirtualControllerSettings.class);
virtualControllerConfiguration.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(virtualControllerConfiguration);
}
void refreshLayout()
{
relative_layout.removeAllViews();
layoutParamsDPad =
new RelativeLayout.LayoutParams(getPercentageV(30), getPercentageV(30));
layoutParamsStick =
new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40));
layoutParamsStick2 =
new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40));
layoutParamsButtonA =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonB =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonX =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonY =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonLT =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonRT =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonLB =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonRB =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
layoutParamsButtonStart =
new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8));
layoutParamsButtonSelect =
new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8));
layoutParamsButtonConfigure =
new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
setPercentilePosition(layoutParamsDPad, 10, 35);
setPercentilePosition(layoutParamsStick, 22, 78);
setPercentilePosition(layoutParamsStick2, 78, 78);
setPercentilePosition(layoutParamsButtonA, 85, 52);
setPercentilePosition(layoutParamsButtonB, 92, 47);
setPercentilePosition(layoutParamsButtonX, 85, 40);
setPercentilePosition(layoutParamsButtonY, 92, 35);
setPercentilePosition(layoutParamsButtonLT, 95, 68);
setPercentilePosition(layoutParamsButtonRT, 95, 80);
setPercentilePosition(layoutParamsButtonLB, 85, 28);
setPercentilePosition(layoutParamsButtonRB, 92, 23);
setPercentilePosition(layoutParamsButtonSelect, 43, 94);
setPercentilePosition(layoutParamsButtonStart, 57, 94);
setPercentilePosition(layoutParamsButtonConfigure, 93, 7);
relative_layout.addView(digitalPad, layoutParamsDPad);
relative_layout.addView(stick, layoutParamsStick);
relative_layout.addView(stick2, layoutParamsStick2);
relative_layout.addView(buttonA, layoutParamsButtonA);
relative_layout.addView(buttonB, layoutParamsButtonB);
relative_layout.addView(buttonX, layoutParamsButtonX);
relative_layout.addView(buttonY, layoutParamsButtonY);
relative_layout.addView(buttonLT, layoutParamsButtonLT);
relative_layout.addView(buttonRT, layoutParamsButtonRT);
relative_layout.addView(buttonLB, layoutParamsButtonLB);
relative_layout.addView(buttonRB, layoutParamsButtonRB);
relative_layout.addView(buttonSelect, layoutParamsButtonSelect);
relative_layout.addView(buttonStart, layoutParamsButtonStart);
relative_layout.addView(buttonConfigure, layoutParamsButtonConfigure);
}
private DigitalButton createDigitalButton(String text, final int key, Context context)
{
DigitalButton button = new DigitalButton(1, context);
button.setText(text);
button.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
{
@Override
public void onClick()
{
inputMap |= key;
sendControllerInputPacket();
}
@Override
public void onLongClick()
{
}
@Override
public void onRelease()
{
inputMap &= ~key;
sendControllerInputPacket();
}
});
return button;
}
private void sendControllerInputPacket()
{
try
{
_DBG("INPUT_MAP + " + inputMap);
_DBG("LEFT_TRIGGER " + leftTrigger);
_DBG("RIGHT_TRIGGER " + rightTrigger);
_DBG("LEFT STICK X: " + leftStickX + " Y: " + leftStickY);
_DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
_DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
if (connection != null)
{
connection.sendControllerInput(inputMap, leftTrigger, rightTrigger,
leftStickX, leftStickY, rightStickX, rightStickY);
}
}
catch (Exception e)
{
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@ -1,43 +0,0 @@
package com.limelight.binding.input.virtual_controller;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.limelight.R;
/**
* Created by Karim Mreisi on 22.01.2015.
*/
public class VirtualControllerConfiguration extends Activity
{
VirtualController virtualController;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// We don't want a title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
// Full-screen and don't let the display go off
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Inflate the content
setContentView(R.layout.activity_configure_virtual_controller);
FrameLayout frameLayout =
(FrameLayout) findViewById(R.id.configure_virtual_controller_frameLayout);
// start with configuration constructor
virtualController = new VirtualController(null, frameLayout, this);
Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
}
}

View File

@ -0,0 +1,269 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import com.limelight.nvstream.input.ControllerPacket;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class VirtualControllerConfigurationLoader {
private static final String PROFILE_PATH = "profiles";
private static int getPercent(
int percent,
int total) {
return (int) (((float) total / (float) 100) * (float) percent);
}
private static DigitalPad createDigitalPad(
final VirtualController controller,
final Context context) {
DigitalPad digitalPad = new DigitalPad(controller, context);
digitalPad.addDigitalPadListener(new DigitalPad.DigitalPadListener() {
@Override
public void onDirectionChange(int direction) {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
if (direction == DigitalPad.DIGITAL_PAD_DIRECTION_NO_DIRECTION) {
inputContext.inputMap &= ~ControllerPacket.LEFT_FLAG;
inputContext.inputMap &= ~ControllerPacket.RIGHT_FLAG;
inputContext.inputMap &= ~ControllerPacket.UP_FLAG;
inputContext.inputMap &= ~ControllerPacket.DOWN_FLAG;
controller.sendControllerInputContext();
return;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) > 0) {
inputContext.inputMap |= ControllerPacket.LEFT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) > 0) {
inputContext.inputMap |= ControllerPacket.RIGHT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) > 0) {
inputContext.inputMap |= ControllerPacket.UP_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) > 0) {
inputContext.inputMap |= ControllerPacket.DOWN_FLAG;
}
controller.sendControllerInputContext();
}
});
return digitalPad;
}
private static DigitalButton createDigitalButton(
final int keyShort,
final int keyLong,
final int layer,
final String text,
final int icon,
final VirtualController controller,
final Context context) {
DigitalButton button = new DigitalButton(controller, layer, context);
button.setText(text);
button.setIcon(icon);
button.addDigitalButtonListener(new DigitalButton.DigitalButtonListener() {
@Override
public void onClick() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.inputMap |= keyShort;
controller.sendControllerInputContext();
}
@Override
public void onLongClick() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.inputMap |= keyLong;
controller.sendControllerInputContext();
}
@Override
public void onRelease() {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
inputContext.inputMap &= ~keyShort;
inputContext.inputMap &= ~keyLong;
controller.sendControllerInputContext();
}
});
return button;
}
private static DigitalButton createLeftTrigger(
final int layer,
final String text,
final int icon,
final VirtualController controller,
final Context context) {
LeftTrigger button = new LeftTrigger(controller, layer, context);
button.setText(text);
button.setIcon(icon);
return button;
}
private static DigitalButton createRightTrigger(
final int layer,
final String text,
final int icon,
final VirtualController controller,
final Context context) {
RightTrigger button = new RightTrigger(controller, layer, context);
button.setText(text);
button.setIcon(icon);
return button;
}
private static AnalogStick createLeftStick(
final VirtualController controller,
final Context context) {
return new LeftAnalogStick(controller, context);
}
private static AnalogStick createRightStick(
final VirtualController controller,
final Context context) {
return new RightAnalogStick(controller, context);
}
public static void createDefaultLayout(final VirtualController controller, final Context context) {
DisplayMetrics screen = context.getResources().getDisplayMetrics();
controller.addElement(createDigitalPad(controller, context),
getPercent(5, screen.widthPixels),
getPercent(10, screen.heightPixels),
getPercent(30, screen.widthPixels),
getPercent(40, screen.heightPixels)
);
controller.addElement(createDigitalButton(
ControllerPacket.A_FLAG, 0, 1, "A", -1, controller, context),
getPercent(75, screen.widthPixels),
getPercent(40, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
controller.addElement(createDigitalButton(
ControllerPacket.B_FLAG, 0, 1, "B", -1, controller, context),
getPercent(85, screen.widthPixels),
getPercent(30, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
controller.addElement(createDigitalButton(
ControllerPacket.X_FLAG, 0, 1, "X", -1, controller, context),
getPercent(65, screen.widthPixels),
getPercent(30, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
controller.addElement(createDigitalButton(
ControllerPacket.Y_FLAG, 0, 1, "Y", -1, controller, context),
getPercent(75, screen.widthPixels),
getPercent(20, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
controller.addElement(createLeftTrigger(
0, "LT", -1, controller, context),
getPercent(65, screen.widthPixels),
getPercent(20, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
controller.addElement(createRightTrigger(
0, "RT", -1, controller, context),
getPercent(85, screen.widthPixels),
getPercent(20, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
controller.addElement(createLeftStick(controller, context),
getPercent(5, screen.widthPixels),
getPercent(50, screen.heightPixels),
getPercent(40, screen.widthPixels),
getPercent(50, screen.heightPixels)
);
controller.addElement(createRightStick(controller, context),
getPercent(55, screen.widthPixels),
getPercent(50, screen.heightPixels),
getPercent(40, screen.widthPixels),
getPercent(50, screen.heightPixels)
);
controller.addElement(createDigitalButton(
ControllerPacket.SPECIAL_BUTTON_FLAG, 0, 2, "SELECT", -1, controller, context),
getPercent(40, screen.widthPixels),
getPercent(90, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
controller.addElement(createDigitalButton(
ControllerPacket.PLAY_FLAG, 0, 3, "PLAY", -1, controller, context),
getPercent(50, screen.widthPixels),
getPercent(90, screen.heightPixels),
getPercent(10, screen.widthPixels),
getPercent(10, screen.heightPixels)
);
}
/*
NOT IMPLEMENTED YET,
this should later be used to store and load a profile for the virtual controller
public static void saveProfile(final String name,
final VirtualController controller,
final Context context) {
SharedPreferences preferences = context.getSharedPreferences(PROFILE_PATH + "/" +
name, Activity.MODE_PRIVATE);
JSONArray elementConfigurations = new JSONArray();
for (VirtualControllerElement element : controller.getElements()) {
JSONObject elementConfiguration = new JSONObject();
try {
elementConfiguration.put("TYPE", element.getClass().getName());
elementConfiguration.put("CONFIGURATION", element.getConfiguration());
elementConfigurations.put(elementConfiguration);
} catch (Exception e) {
e.printStackTrace();
}
}
SharedPreferences.Editor editor= preferences.edit();
editor.putString("ELEMENTS", elementConfigurations.toString());
}
public static void loadFromPreferences(final VirtualController controller) {
}
*/
}

View File

@ -1,45 +1,280 @@
/**
* Created by Karim Mreisi.
*/
package com.limelight.binding.input.virtual_controller; package com.limelight.binding.input.virtual_controller;
import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.RelativeLayout;
/** import org.json.JSONObject;
* Created by Karim on 27.01.2015.
*/ //import yuku.ambilwarna.AmbilWarnaDialog;
public abstract class VirtualControllerElement extends View
{ public abstract class VirtualControllerElement extends View {
protected static boolean _PRINT_DEBUG_INFORMATION = false; protected static boolean _PRINT_DEBUG_INFORMATION = false;
protected VirtualController virtualController;
protected int normalColor = 0xF0888888; protected int normalColor = 0xF0888888;
protected int pressedColor = 0xF00000FF; protected int pressedColor = 0xF00000FF;
protected VirtualControllerElement(Context context) protected int startSize_x;
{ protected int startSize_y;
super(context);
float position_pressed_x = 0;
float position_pressed_y = 0;
private enum Mode {
Normal,
Resize,
Move
} }
protected static final void _DBG(String text) private Mode currentMode = Mode.Normal;
{
if (_PRINT_DEBUG_INFORMATION) protected VirtualControllerElement(VirtualController controller, Context context) {
{ super(context);
this.virtualController = controller;
}
protected void moveElement(int pressed_x, int pressed_y, int x, int y) {
int newPos_x = (int)getX() + x - pressed_x;
int newPos_y = (int)getY() + y - pressed_y;
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = newPos_x > 0 ? newPos_x : 0;
layoutParams.topMargin = newPos_y > 0 ? newPos_y : 0;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
requestLayout();
}
protected void resizeElement(int pressed_x, int pressed_y, int width, int height) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
int newHeight = height + (startSize_y - pressed_y);
int newWidth = width + (startSize_x - pressed_x);
layoutParams.height = newHeight > 20 ? newHeight : 20;
layoutParams.width = newWidth > 20 ? newWidth : 20;
requestLayout();
}
@Override
protected void onDraw(Canvas canvas) {
if (virtualController.getControllerMode() == VirtualController.ControllerMode.
Configuration) {
Paint paint = new Paint();
paint.setColor(pressedColor);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, 0,
getWidth(), getHeight(),
paint);
}
onElementDraw(canvas);
super.onDraw(canvas);
}
/*
protected void actionShowNormalColorChooser() {
AmbilWarnaDialog colorDialog = new AmbilWarnaDialog(getContext(), normalColor, true, new AmbilWarnaDialog.OnAmbilWarnaListener() {
@Override
public void onCancel(AmbilWarnaDialog dialog)
{}
@Override
public void onOk(AmbilWarnaDialog dialog, int color) {
normalColor = color;
invalidate();
}
});
colorDialog.show();
}
protected void actionShowPressedColorChooser() {
AmbilWarnaDialog colorDialog = new AmbilWarnaDialog(getContext(), normalColor, true, new AmbilWarnaDialog.OnAmbilWarnaListener() {
@Override
public void onCancel(AmbilWarnaDialog dialog) {
}
@Override
public void onOk(AmbilWarnaDialog dialog, int color) {
pressedColor = color;
invalidate();
}
});
colorDialog.show();
}
*/
protected void actionEnableMove() {
currentMode = Mode.Move;
}
protected void actionEnableResize() {
currentMode = Mode.Resize;
}
protected void actionCancel() {
currentMode = Mode.Normal;
invalidate();
}
protected void showConfigurationDialog() {
try {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getContext());
alertBuilder.setTitle("Configuration");
CharSequence functions[] = new CharSequence[]{
"Move",
"Resize",
/*election
"Set n
Disable color sormal color",
"Set pressed color",
*/
"Cancel"
};
alertBuilder.setItems(functions, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0: { // move
actionEnableMove();
break;
}
case 1: { // resize
actionEnableResize();
break;
}
/*
case 2: { // set default color
actionShowNormalColorChooser();
break;
}
case 3: { // set pressed color
actionShowPressedColorChooser();
break;
}
*/
default: { // cancel
actionCancel();
break;
}
}
}
});
AlertDialog alert = alertBuilder.create();
// show menu
alert.show();
}catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (virtualController.getControllerMode() == VirtualController.ControllerMode.Active) {
return onElementTouchEvent(event);
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
position_pressed_x = event.getX();
position_pressed_y = event.getY();
startSize_x = getWidth();
startSize_y = getHeight();
return true;
}
case MotionEvent.ACTION_MOVE: {
switch (currentMode) {
case Move: {
moveElement(
(int) position_pressed_x,
(int) position_pressed_y,
(int) event.getX(),
(int) event.getY());
break;
}
case Resize: {
resizeElement(
(int) position_pressed_x,
(int) position_pressed_y,
(int) event.getX(),
(int) event.getY());
break;
}
case Normal: {
break;
}
}
return true;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: {
currentMode = Mode.Normal;
showConfigurationDialog();
return true;
}
default: {
}
}
return true;
}
abstract protected void onElementDraw(Canvas canvas);
abstract public boolean onElementTouchEvent(MotionEvent event);
protected static final void _DBG(String text) {
if (_PRINT_DEBUG_INFORMATION) {
System.out.println(text); System.out.println(text);
} }
} }
public void setColors(int normalColor, int pressedColor) public void setColors(int normalColor, int pressedColor) {
{
this.normalColor = normalColor; this.normalColor = normalColor;
this.pressedColor = pressedColor; this.pressedColor = pressedColor;
invalidate(); invalidate();
} }
protected final float getPercent(float value, float percent) protected final float getPercent(float value, float percent) {
{
return value / 100 * percent; return value / 100 * percent;
} }
protected final int getCorrectWidth() protected final int getCorrectWidth() {
{
return getWidth() > getHeight() ? getHeight() : getWidth(); return getWidth() > getHeight() ? getHeight() : getWidth();
} }
/**
public JSONObject getConfiguration () {
JSONObject configuration = new JSONObject();
return configuration;
}
public void loadConfiguration (JSONObject configuration) {
}
*/
} }

View File

@ -1,29 +0,0 @@
package com.limelight.binding.input.virtual_controller;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.widget.Toast;
import com.limelight.R;
/**
* Created by Karim on 26.01.2015.
*/
public class VirtualControllerSettings extends Activity
{
private VirtualController controller = null;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// We don't want a title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
// Inflate the content
setContentView(R.layout.activity_virtual_controller_settings);
Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
}
}

View File

@ -188,7 +188,6 @@ public class PreferenceConfiguration {
config.multiController = prefs.getBoolean(MULTI_CONTROLLER_PREF_STRING, DEFAULT_MULTI_CONTROLLER); config.multiController = prefs.getBoolean(MULTI_CONTROLLER_PREF_STRING, DEFAULT_MULTI_CONTROLLER);
config.enable51Surround = prefs.getBoolean(ENABLE_51_SURROUND_PREF_STRING, DEFAULT_ENABLE_51_SURROUND); config.enable51Surround = prefs.getBoolean(ENABLE_51_SURROUND_PREF_STRING, DEFAULT_ENABLE_51_SURROUND);
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER); config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
config.virtualController_enable = prefs.getBoolean(VIRTUAL_CONTROLLER_ENABLE, VIRTUAL_CONTROLLER_ENABLE_DEFAULT); config.virtualController_enable = prefs.getBoolean(VIRTUAL_CONTROLLER_ENABLE, VIRTUAL_CONTROLLER_ENABLE_DEFAULT);
return config; return config;

View File

@ -11,8 +11,6 @@ import android.preference.PreferenceManager;
import com.limelight.PcView; import com.limelight.PcView;
import com.limelight.R; import com.limelight.R;
import com.limelight.binding.input.virtual_controller.VirtualController;
import com.limelight.binding.input.virtual_controller.VirtualControllerConfiguration;
import com.limelight.utils.UiHelper; import com.limelight.utils.UiHelper;
import java.util.Locale; import java.util.Locale;
@ -82,19 +80,6 @@ public class StreamSettings extends Activity {
return true; return true;
} }
}); });
Preference siteVirtualControllerButton = (Preference)findPreference("button_open_virtual_controller_configuration");
siteVirtualControllerButton.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener()
{
@Override
public boolean onPreferenceClick(Preference arg0)
{
Intent virtualControllerConfiguration = new Intent(getActivity(), VirtualControllerConfiguration.class);
startActivity(virtualControllerConfiguration);
return true;
}
});
} }
} }
} }

View File

@ -50,6 +50,11 @@
android:title="@string/title_checkbox_xb1_driver" android:title="@string/title_checkbox_xb1_driver"
android:summary="@string/summary_checkbox_xb1_driver" android:summary="@string/summary_checkbox_xb1_driver"
android:defaultValue="true" /> android:defaultValue="true" />
<CheckBoxPreference
android:key="virtual_controller_checkbox_enable"
android:title="Enable virtual onscreen controller"
android:summary="Show virtual controller overlay on game screen"
android:defaultValue="true"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/category_host_settings"> <PreferenceCategory android:title="@string/category_host_settings">
<CheckBoxPreference <CheckBoxPreference
@ -90,15 +95,4 @@
android:summary="@string/summary_video_format" android:summary="@string/summary_video_format"
android:defaultValue="auto" /> android:defaultValue="auto" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="Virtual Controller">
<CheckBoxPreference
android:key="virtual_controller_checkbox_enable"
android:title="Enable virtual controller"
android:summary="Show virtual controller overlay on game screen"
android:defaultValue="true"/>
<Preference android:title="Site virtual controller items"
android:key="button_open_virtual_controller_configuration"
android:summary="tbd"/>
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="limelight-android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id="moonlight-new" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle"> <facet type="java-gradle" name="Java-Gradle">
<configuration> <configuration>