mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-19 05:15:46 -04:00
Android: Multiple fixes
- Fix possible crash when applying settings worker thread (no JNIEnv). - Fix settings not applying until restarting the app. - Support analog controller - auto-binding of axixes. Currently no touchscreen controller for the joysticks. - Add option to auto-hide the touchscreen controller.
This commit is contained in:
@ -23,7 +23,9 @@ public class AndroidHostInterface
|
||||
// TODO: Find a better place for this.
|
||||
public native void setControllerType(int index, String typeName);
|
||||
public native void setControllerButtonState(int index, int buttonCode, boolean pressed);
|
||||
public native void setControllerAxisState(int index, int axisCode, float value);
|
||||
public static native int getControllerButtonCode(String controllerType, String buttonName);
|
||||
public static native int getControllerAxisCode(String controllerType, String axisName);
|
||||
|
||||
public native void refreshGameList(boolean invalidateCache, boolean invalidateDatabase);
|
||||
public native GameListEntry[] getGameListEntries();
|
||||
|
@ -38,6 +38,9 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||
editor.putBoolean(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
private String getStringSetting(String key, String defaultValue) {
|
||||
return mPreferences.getString(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Touchscreen controller overlay
|
||||
@ -154,15 +157,17 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||
}
|
||||
});
|
||||
|
||||
// Hook up controller input.
|
||||
final String controllerType = getStringSetting("Controller1/Type", "DigitalController");
|
||||
Log.i("EmulationActivity", "Controller type: " + controllerType);
|
||||
mContentView.initControllerKeyMapping(controllerType);
|
||||
|
||||
// Create touchscreen controller.
|
||||
FrameLayout activityLayout = findViewById(R.id.frameLayout);
|
||||
mTouchscreenController = new TouchscreenControllerView(this);
|
||||
activityLayout.addView(mTouchscreenController);
|
||||
mTouchscreenController.init(0, "DigitalController", AndroidHostInterface.getInstance());
|
||||
setTouchscreenControllerVisibility(true);
|
||||
|
||||
// Hook up controller input.
|
||||
mContentView.initControllerKeyMapping("DigitalController");
|
||||
mTouchscreenController.init(0, controllerType);
|
||||
setTouchscreenControllerVisibility(getBooleanSetting("Controller1/EnableTouchscreenController", true));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -181,6 +186,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||
getMenuInflater().inflate(R.menu.menu_emulation, menu);
|
||||
menu.findItem(R.id.show_controller).setChecked(mTouchscreenControllerVisible);
|
||||
menu.findItem(R.id.enable_speed_limiter).setChecked(getBooleanSetting("Main/SpeedLimiterEnabled", true));
|
||||
menu.findItem(R.id.show_controller).setChecked(getBooleanSetting("Controller1/EnableTouchscreenController", true));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,10 @@ import android.content.Context;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
public class EmulationSurfaceView extends SurfaceView {
|
||||
@ -48,7 +50,49 @@ public class EmulationSurfaceView extends SurfaceView {
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
final int source = event.getSource();
|
||||
if ((source & InputDevice.SOURCE_JOYSTICK) == 0)
|
||||
return super.onGenericMotionEvent(event);
|
||||
|
||||
final InputDevice device = event.getDevice();
|
||||
for (int axis : AXISES) {
|
||||
Integer mapping = mControllerAxisMapping.containsKey(axis) ? mControllerAxisMapping.get(axis) : null;
|
||||
Pair<Integer, Integer> buttonMapping = mControllerAxisButtonMapping.containsKey(axis) ? mControllerAxisButtonMapping.get(axis) : null;
|
||||
if (mapping == null && buttonMapping == null)
|
||||
continue;
|
||||
|
||||
final float axisValue = event.getAxisValue(axis);
|
||||
float emuValue;
|
||||
|
||||
final InputDevice.MotionRange range = device.getMotionRange(axis, source);
|
||||
if (range != null) {
|
||||
final float transformedValue = (axisValue - range.getMin()) / range.getRange();
|
||||
emuValue = (transformedValue * 2.0f) - 1.0f;
|
||||
} else {
|
||||
emuValue = axisValue;
|
||||
}
|
||||
Log.d("EmulationSurfaceView", String.format("axis %d value %f emuvalue %f", axis, axisValue, emuValue));
|
||||
if (mapping != null) {
|
||||
AndroidHostInterface.getInstance().setControllerAxisState(0, mapping, emuValue);
|
||||
} else {
|
||||
final float DEAD_ZONE = 0.25f;
|
||||
AndroidHostInterface.getInstance().setControllerButtonState(0, buttonMapping.first, (emuValue <= -DEAD_ZONE));
|
||||
AndroidHostInterface.getInstance().setControllerButtonState(0, buttonMapping.second, (emuValue >= DEAD_ZONE));
|
||||
Log.d("EmulationSurfaceView", String.format("using emuValue %f for buttons %d %d", emuValue, buttonMapping.first, buttonMapping.second));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ArrayMap<Integer, Integer> mControllerKeyMapping;
|
||||
private ArrayMap<Integer, Integer> mControllerAxisMapping;
|
||||
private ArrayMap<Integer, Pair<Integer, Integer>> mControllerAxisButtonMapping;
|
||||
static final int[] AXISES = new int[]{MotionEvent.AXIS_X, MotionEvent.AXIS_Y, MotionEvent.AXIS_RX,
|
||||
MotionEvent.AXIS_RY, MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ,
|
||||
MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y};
|
||||
|
||||
private void addControllerKeyMapping(int keyCode, String controllerType, String buttonName) {
|
||||
int mapping = AndroidHostInterface.getControllerButtonCode(controllerType, buttonName);
|
||||
@ -58,8 +102,31 @@ public class EmulationSurfaceView extends SurfaceView {
|
||||
mControllerKeyMapping.put(keyCode, mapping);
|
||||
}
|
||||
|
||||
private void addControllerAxisMapping(int axis, String controllerType, String axisName, String negativeButtonName, String positiveButtonName) {
|
||||
if (axisName != null) {
|
||||
int mapping = AndroidHostInterface.getControllerAxisCode(controllerType, axisName);
|
||||
Log.i("EmulationSurfaceView", String.format("Map axis %d to %d (%s)", axis, mapping, axisName));
|
||||
if (mapping >= 0) {
|
||||
mControllerAxisMapping.put(axis, mapping);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (negativeButtonName != null && positiveButtonName != null) {
|
||||
final int negativeMapping = AndroidHostInterface.getControllerButtonCode(controllerType, negativeButtonName);
|
||||
final int positiveMapping = AndroidHostInterface.getControllerButtonCode(controllerType, positiveButtonName);
|
||||
Log.i("EmulationSurfaceView", String.format("Map axis %d to %d %d (button %s %s)", axis, negativeMapping, positiveMapping,
|
||||
negativeButtonName, positiveButtonName));
|
||||
if (negativeMapping >= 0 && positiveMapping >= 0) {
|
||||
mControllerAxisButtonMapping.put(axis, new Pair<Integer, Integer>(negativeMapping, positiveMapping));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initControllerKeyMapping(String controllerType) {
|
||||
mControllerKeyMapping = new ArrayMap<>();
|
||||
mControllerAxisMapping = new ArrayMap<>();
|
||||
mControllerAxisButtonMapping = new ArrayMap<>();
|
||||
|
||||
// TODO: Don't hardcode...
|
||||
addControllerKeyMapping(KeyEvent.KEYCODE_DPAD_UP, controllerType, "Up");
|
||||
@ -76,6 +143,14 @@ public class EmulationSurfaceView extends SurfaceView {
|
||||
addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_X, controllerType, "Square");
|
||||
addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_R1, controllerType, "R1");
|
||||
addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_R2, controllerType, "R2");
|
||||
addControllerAxisMapping(MotionEvent.AXIS_X, controllerType, "LeftX", null, null);
|
||||
addControllerAxisMapping(MotionEvent.AXIS_Y, controllerType, "LeftY", null, null);
|
||||
addControllerAxisMapping(MotionEvent.AXIS_RX, controllerType, "RightX", null, null);
|
||||
addControllerAxisMapping(MotionEvent.AXIS_RY, controllerType, "RightY", null, null);
|
||||
addControllerAxisMapping(MotionEvent.AXIS_Z, controllerType, "L2", "L2", "L2");
|
||||
addControllerAxisMapping(MotionEvent.AXIS_RZ, controllerType, "R2", "R2", "R2");
|
||||
addControllerAxisMapping(MotionEvent.AXIS_HAT_X, controllerType, null, "Left", "Right");
|
||||
addControllerAxisMapping(MotionEvent.AXIS_HAT_Y, controllerType, null, "Up", "Down");
|
||||
}
|
||||
|
||||
private boolean handleControllerKey(int keyCode, boolean pressed) {
|
||||
@ -84,6 +159,7 @@ public class EmulationSurfaceView extends SurfaceView {
|
||||
|
||||
final int mapping = mControllerKeyMapping.get(keyCode);
|
||||
AndroidHostInterface.getInstance().setControllerButtonState(0, mapping, pressed);
|
||||
Log.d("EmulationSurfaceView", String.format("handleControllerKey %d -> %d %d", keyCode, mapping, pressed ? 1 : 0));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import android.widget.FrameLayout;
|
||||
public class TouchscreenControllerView extends FrameLayout implements TouchscreenControllerButtonView.ButtonStateChangedListener {
|
||||
private int mControllerIndex;
|
||||
private String mControllerType;
|
||||
private AndroidHostInterface mHostInterface;
|
||||
|
||||
public TouchscreenControllerView(Context context) {
|
||||
super(context);
|
||||
@ -27,14 +26,9 @@ public class TouchscreenControllerView extends FrameLayout implements Touchscree
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public void init(int controllerIndex, String controllerType,
|
||||
AndroidHostInterface hostInterface) {
|
||||
public void init(int controllerIndex, String controllerType) {
|
||||
mControllerIndex = controllerIndex;
|
||||
mControllerType = controllerType;
|
||||
mHostInterface = hostInterface;
|
||||
|
||||
if (mHostInterface != null)
|
||||
mHostInterface.setControllerType(controllerIndex, controllerType);
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
View view = inflater.inflate(R.layout.layout_touchscreen_controller, this, true);
|
||||
@ -62,25 +56,22 @@ public class TouchscreenControllerView extends FrameLayout implements Touchscree
|
||||
buttonView.setButtonName(buttonName);
|
||||
buttonView.setButtonStateChangedListener(this);
|
||||
|
||||
if (mHostInterface != null)
|
||||
{
|
||||
int code = mHostInterface.getControllerButtonCode(mControllerType, buttonName);
|
||||
buttonView.setButtonCode(code);
|
||||
Log.i("TouchscreenController", String.format("%s -> %d", buttonName, code));
|
||||
int code = AndroidHostInterface.getInstance().getControllerButtonCode(mControllerType, buttonName);
|
||||
buttonView.setButtonCode(code);
|
||||
Log.i("TouchscreenController", String.format("%s -> %d", buttonName, code));
|
||||
|
||||
if (code < 0) {
|
||||
Log.e("TouchscreenController", String.format("Unknown button name '%s' " +
|
||||
"for '%s'", buttonName, mControllerType));
|
||||
}
|
||||
if (code < 0) {
|
||||
Log.e("TouchscreenController", String.format("Unknown button name '%s' " +
|
||||
"for '%s'", buttonName, mControllerType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onButtonStateChanged(TouchscreenControllerButtonView view, boolean pressed) {
|
||||
if (mHostInterface == null || view.getButtonCode() < 0)
|
||||
if (view.getButtonCode() < 0)
|
||||
return;
|
||||
|
||||
mHostInterface.setControllerButtonState(mControllerIndex, view.getButtonCode(), pressed);
|
||||
AndroidHostInterface.getInstance().setControllerButtonState(mControllerIndex, view.getButtonCode(), pressed);
|
||||
}
|
||||
}
|
||||
|
@ -67,4 +67,12 @@
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
</string-array>
|
||||
<string-array name="settings_controller_type_entries">
|
||||
<item>Digital Controller (Gamepad)</item>
|
||||
<item>Analog Controller (DualShock)</item>
|
||||
</string-array>
|
||||
<string-array name="settings_controller_type_values">
|
||||
<item>DigitalController</item>
|
||||
<item>AnalogController</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
@ -41,11 +41,6 @@
|
||||
app:defaultValue="@string/settings_console_region_default"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<EditTextPreference
|
||||
app:key="BIOS/Path"
|
||||
app:title="@string/settings_console_bios_path"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
app:key="BIOS/PatchTTYEnable"
|
||||
app:title="@string/settings_console_tty_output"
|
||||
@ -144,4 +139,22 @@
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="Controller">
|
||||
<ListPreference
|
||||
app:key="Controller1/Type"
|
||||
app:title="Controller Type"
|
||||
app:entries="@array/settings_controller_type_entries"
|
||||
app:entryValues="@array/settings_controller_type_values"
|
||||
app:defaultValue="DigitalController"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<SwitchPreferenceCompat
|
||||
app:key="Controller1/AutoEnableAnalog"
|
||||
app:title="Enable Analog Mode On Reset"
|
||||
app:defaultValue="false" />
|
||||
<SwitchPreferenceCompat
|
||||
app:key="Controller1/EnableTouchscreenController"
|
||||
app:title="Display Touchscreen Controller"
|
||||
app:defaultValue="true" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
Reference in New Issue
Block a user