Android: Start to get controller working
This commit is contained in:
parent
de1288bdca
commit
10b550bb63
|
@ -44,6 +44,11 @@
|
|||
android:label="@string/ScanRomsActivity_title"
|
||||
android:theme="@style/Theme.Project64.Apearance" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name="emu.project64.profile.ControllerProfileActivity"
|
||||
android:label="@string/ControllerProfileActivity_title"
|
||||
android:theme="@style/Theme.Project64.Apearance" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name="emu.project64.game.GameActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.graphics.Point;
|
|||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.WindowManager;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
|
@ -47,6 +48,8 @@ public class AndroidDevice
|
|||
|
||||
public static final boolean IS_ACTION_BAR_AVAILABLE = AndroidDevice.IS_HONEYCOMB;
|
||||
|
||||
public static boolean MapVolumeKeys = false;
|
||||
|
||||
public final static int nativeWidth;
|
||||
public final static int nativeHeight;
|
||||
static
|
||||
|
@ -72,6 +75,24 @@ public class AndroidDevice
|
|||
nativeHeight = _nativeHeight;
|
||||
}
|
||||
|
||||
public static List<Integer> getUnmappableKeyCodes ()
|
||||
{
|
||||
List<Integer> unmappables = new ArrayList<Integer>();
|
||||
unmappables.add( KeyEvent.KEYCODE_MENU );
|
||||
if( IS_HONEYCOMB )
|
||||
{
|
||||
// Back key is needed to show/hide the action bar in HC+
|
||||
unmappables.add( KeyEvent.KEYCODE_BACK );
|
||||
}
|
||||
if( !MapVolumeKeys )
|
||||
{
|
||||
unmappables.add( KeyEvent.KEYCODE_VOLUME_UP );
|
||||
unmappables.add( KeyEvent.KEYCODE_VOLUME_DOWN );
|
||||
unmappables.add( KeyEvent.KEYCODE_VOLUME_MUTE );
|
||||
}
|
||||
return unmappables;
|
||||
}
|
||||
|
||||
public static ArrayList<String> getStorageDirectories()
|
||||
{
|
||||
BufferedReader bufReader = null;
|
||||
|
|
|
@ -11,9 +11,7 @@ import java.util.ArrayList;
|
|||
import java.util.Set;
|
||||
|
||||
import emu.project64.AndroidDevice;
|
||||
import emu.project64.Project64Application;
|
||||
import emu.project64.R;
|
||||
import emu.project64.hack.MogaHack;
|
||||
import emu.project64.input.AbstractController;
|
||||
import emu.project64.input.PeripheralController;
|
||||
import emu.project64.input.TouchController;
|
||||
|
@ -23,12 +21,8 @@ import emu.project64.input.provider.AbstractProvider;
|
|||
import emu.project64.input.provider.AxisProvider;
|
||||
import emu.project64.input.provider.KeyProvider;
|
||||
import emu.project64.input.provider.KeyProvider.ImeFormula;
|
||||
import emu.project64.input.provider.MogaProvider;
|
||||
import emu.project64.jni.NativeExports;
|
||||
import emu.project64.jni.NativeVideo;
|
||||
import emu.project64.jni.NativeXperiaTouchpad;
|
||||
import emu.project64.jni.SettingsID;
|
||||
import emu.project64.jni.SystemEvent;
|
||||
import emu.project64.jni.UISettingID;
|
||||
import emu.project64.jni.VideoSettingID;
|
||||
import emu.project64.persistent.ConfigFile;
|
||||
|
@ -39,19 +33,16 @@ import android.annotation.TargetApi;
|
|||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Vibrator;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
|
@ -69,7 +60,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
private ArrayList<AbstractController> mControllers;
|
||||
private VisibleTouchMap mTouchscreenMap;
|
||||
private KeyProvider mKeyProvider;
|
||||
private Controller mMogaController;
|
||||
|
||||
// Internal flags
|
||||
private boolean mStarted = false;
|
||||
|
@ -87,20 +77,14 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
{
|
||||
mActivity = activity;
|
||||
mControllers = new ArrayList<AbstractController>();
|
||||
mMogaController = Controller.getInstance(mActivity);
|
||||
}
|
||||
|
||||
@TargetApi(11)
|
||||
public void onCreateBegin(Bundle savedInstanceState)
|
||||
{
|
||||
if (LOG_GAMELIFECYCLEHANDLER)
|
||||
{
|
||||
Log.i("GameLifecycleHandler", "onCreateBegin - Start");
|
||||
}
|
||||
// Initialize MOGA controller API
|
||||
// TODO: Remove hack after MOGA SDK is fixed
|
||||
// mMogaController.init();
|
||||
MogaHack.init(mMogaController, mActivity);
|
||||
|
||||
// For Honeycomb, let the action bar overlay the rendered view (rather
|
||||
// than squeezing it)
|
||||
|
@ -122,7 +106,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
}
|
||||
}
|
||||
|
||||
@TargetApi(11)
|
||||
public void onCreateEnd(Bundle savedInstanceState)
|
||||
{
|
||||
if (LOG_GAMELIFECYCLEHANDLER)
|
||||
|
@ -157,13 +140,22 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
mSurface.getHolder().addCallback(this);
|
||||
mSurface.createGLContext((ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE));
|
||||
|
||||
//CreateTouchScreenControls();
|
||||
//View inputSource = mOverlay;
|
||||
//initControllers(inputSource);
|
||||
// Configure the action bar introduced in higher Android versions
|
||||
/*if (AndroidDevice.IS_ACTION_BAR_AVAILABLE)
|
||||
{
|
||||
mActivity.getActionBar().hide();
|
||||
ColorDrawable color = new ColorDrawable(Color.parseColor("#303030"));
|
||||
color.setAlpha(50 /*mGlobalPrefs.displayActionBarTransparency*/ /*);
|
||||
mActivity.getActionBar().setBackgroundDrawable(color);
|
||||
}
|
||||
|
||||
// Override the peripheral controllers' key provider, to add some extra
|
||||
// functionality
|
||||
//inputSource.setOnKeyListener(this);
|
||||
CreateTouchScreenControls();*/
|
||||
|
||||
// Initialize user interface devices
|
||||
initControllers(mOverlay);
|
||||
|
||||
// Override the peripheral controllers' key provider, to add some extra functionality
|
||||
mOverlay.setOnKeyListener(this);
|
||||
if (LOG_GAMELIFECYCLEHANDLER)
|
||||
{
|
||||
Log.i("GameLifecycleHandler", "onCreateEnd done");
|
||||
|
@ -186,8 +178,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
}
|
||||
mIsResumed = true;
|
||||
tryRunning();
|
||||
|
||||
mMogaController.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -325,7 +315,6 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
{
|
||||
Log.i("GameLifecycleHandler", "onDestroy");
|
||||
}
|
||||
mMogaController.exit();
|
||||
}
|
||||
|
||||
public void onSettingDone()
|
||||
|
@ -343,30 +332,27 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
|
||||
private void CreateTouchScreenControls()
|
||||
{
|
||||
/*boolean isTouchscreenAnimated = false; // mGlobalPrefs.isTouchscreenAnimated
|
||||
boolean isTouchscreenHidden = false; // !isTouchscreenEnabled ||
|
||||
// globalPrefs.touchscreenTransparency
|
||||
// == 0;
|
||||
boolean isTouchscreenAnimated = false; //mGlobalPrefs.isTouchscreenAnimated
|
||||
boolean isTouchscreenHidden = false; //!isTouchscreenEnabled || globalPrefs.touchscreenTransparency == 0;
|
||||
String profilesDir = AndroidDevice.PACKAGE_DIRECTORY + "/profiles";
|
||||
String touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
|
||||
ConfigFile touchscreenConfigFile = new ConfigFile(touchscreenProfiles_cfg);
|
||||
ConfigFile touchscreenConfigFile = new ConfigFile( touchscreenProfiles_cfg );
|
||||
ConfigSection section = touchscreenConfigFile.get(mlayout);
|
||||
if (section == null)
|
||||
{
|
||||
mlayout = "Analog";
|
||||
section = touchscreenConfigFile.get(mlayout);
|
||||
}
|
||||
Profile touchscreenProfile = new Profile(true, section);
|
||||
Profile touchscreenProfile = new Profile( true, section);
|
||||
int touchscreenTransparency = 100;
|
||||
String touchscreenSkinsDir = AndroidDevice.PACKAGE_DIRECTORY + "/skins/touchscreen";
|
||||
String touchscreenSkin = touchscreenSkinsDir + "/Outline";
|
||||
|
||||
// The touch map and overlay are needed to display frame rate and/or
|
||||
// controls
|
||||
mTouchscreenMap = new VisibleTouchMap(mActivity.getResources());
|
||||
mTouchscreenMap.load(touchscreenSkin, touchscreenProfile, isTouchscreenAnimated, mtouchscreenScale, touchscreenTransparency);
|
||||
mOverlay.initialize(mTouchscreenMap, !isTouchscreenHidden, isTouchscreenAnimated);*/
|
||||
}
|
||||
// The touch map and overlay are needed to display frame rate and/or controls
|
||||
mTouchscreenMap = new VisibleTouchMap( mActivity.getResources() );
|
||||
mTouchscreenMap.load(touchscreenSkin, touchscreenProfile, isTouchscreenAnimated, mtouchscreenScale, touchscreenTransparency );
|
||||
mOverlay.initialize( mTouchscreenMap, !isTouchscreenHidden, isTouchscreenAnimated );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKey(View view, int keyCode, KeyEvent event)
|
||||
|
@ -385,33 +371,32 @@ public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.C
|
|||
private void initControllers(View inputSource)
|
||||
{
|
||||
// By default, send Player 1 rumbles through phone vibrator
|
||||
/*Vibrator vibrator = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
Vibrator vibrator = (Vibrator) mActivity.getSystemService( Context.VIBRATOR_SERVICE );
|
||||
int touchscreenAutoHold = 0;
|
||||
boolean isTouchscreenFeedbackEnabled = false;
|
||||
Set<Integer> autoHoldableButtons = null;
|
||||
|
||||
// Create the touchscreen controller
|
||||
TouchController touchscreenController = new TouchController(mTouchscreenMap, inputSource, mOverlay, vibrator,
|
||||
touchscreenAutoHold, isTouchscreenFeedbackEnabled, autoHoldableButtons);
|
||||
mControllers.add(touchscreenController);
|
||||
TouchController touchscreenController = new TouchController( mTouchscreenMap,
|
||||
inputSource, mOverlay, vibrator, touchscreenAutoHold,
|
||||
isTouchscreenFeedbackEnabled, autoHoldableButtons );
|
||||
mControllers.add( touchscreenController );
|
||||
|
||||
// Create the input providers shared among all peripheral controllers
|
||||
String profile_name = NativeExports.UISettingsLoadString(UISettingID.Controller_CurrentProfile.getValue());
|
||||
ConfigFile ControllerConfigFile = new ConfigFile(
|
||||
NativeExports.UISettingsLoadString(UISettingID.Controller_ConfigFile.getValue()));
|
||||
ConfigSection section = ControllerConfigFile.get(profile_name);
|
||||
String profile_name = NativeExports.SettingsLoadString(UISettingID.ControllerCurrentProfile.toString());
|
||||
ConfigFile ControllerConfigFile = new ConfigFile(NativeExports.SettingsLoadString(UISettingID.ControllerConfigFile.toString()));
|
||||
ConfigSection section = ControllerConfigFile.get( profile_name );
|
||||
if (section != null)
|
||||
{
|
||||
Profile ControllerProfile = new Profile(false, section);
|
||||
InputMap map = new InputMap(ControllerProfile.get("map"));
|
||||
Profile ControllerProfile = new Profile( false, section );
|
||||
InputMap map = new InputMap( ControllerProfile.get( "map" ) );
|
||||
|
||||
mKeyProvider = new KeyProvider(inputSource, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes());
|
||||
MogaProvider mogaProvider = new MogaProvider(mMogaController);
|
||||
AbstractProvider axisProvider = AndroidDevice.IS_HONEYCOMB_MR1 ? new AxisProvider(inputSource) : null;
|
||||
int Deadzone = NativeExports.UISettingsLoadDword(UISettingID.Controller_Deadzone.getValue());
|
||||
int Sensitivity = NativeExports.UISettingsLoadDword(UISettingID.Controller_Sensitivity.getValue());
|
||||
mControllers.add(new PeripheralController(1, map, Deadzone, Sensitivity, mKeyProvider, axisProvider, mogaProvider));
|
||||
}*/
|
||||
mKeyProvider = new KeyProvider( inputSource, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
|
||||
AbstractProvider axisProvider = AndroidDevice.IS_HONEYCOMB_MR1 ? new AxisProvider( inputSource ) : null;
|
||||
int Deadzone = NativeExports.SettingsLoadDword(UISettingID.ControllerDeadzone.toString());
|
||||
int Sensitivity = NativeExports.SettingsLoadDword(UISettingID.ControllerSensitivity.toString());
|
||||
mControllers.add(new PeripheralController(1, map, Deadzone, Sensitivity, mKeyProvider, axisProvider));
|
||||
}
|
||||
}
|
||||
|
||||
private void tryRunning()
|
||||
|
|
|
@ -0,0 +1,471 @@
|
|||
package emu.project64.profile;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import emu.project64.AndroidDevice;
|
||||
import emu.project64.R;
|
||||
import emu.project64.input.AbstractController;
|
||||
import emu.project64.input.map.InputMap;
|
||||
import emu.project64.input.provider.AbstractProvider;
|
||||
import emu.project64.input.provider.AxisProvider;
|
||||
import emu.project64.input.provider.KeyProvider;
|
||||
import emu.project64.jni.NativeExports;
|
||||
import emu.project64.jni.UISettingID;
|
||||
import emu.project64.persistent.ConfigFile;
|
||||
|
||||
public class ControllerProfileActivity extends AppCompatActivity implements AbstractProvider.OnInputListener, View.OnClickListener
|
||||
{
|
||||
// Visual settings
|
||||
private static final float UNMAPPED_BUTTON_ALPHA = 0.2f;
|
||||
private static final int UNMAPPED_BUTTON_FILTER = 0x66FFFFFF;
|
||||
private static final int MIN_LAYOUT_WIDTH_DP = 480;
|
||||
|
||||
// Controller profile objects
|
||||
private ConfigFile mConfigFile;
|
||||
private Profile mProfile;
|
||||
|
||||
// Input listening
|
||||
private KeyProvider mKeyProvider;
|
||||
private AxisProvider mAxisProvider;
|
||||
|
||||
// Widgets
|
||||
private final Button[] mN64Buttons = new Button[InputMap.NUM_MAPPABLES];
|
||||
private TextView mFeedbackText;
|
||||
|
||||
@Override
|
||||
public void onCreate( Bundle savedInstanceState )
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Load the profile; fail fast if there are any programmer usage errors
|
||||
String name = NativeExports.SettingsLoadString(UISettingID.ControllerCurrentProfile.toString());
|
||||
if(TextUtils.isEmpty(name))
|
||||
{
|
||||
throw new Error("Invalid usage: profile name cannot be null or empty");
|
||||
}
|
||||
mConfigFile = new ConfigFile(NativeExports.SettingsLoadString(UISettingID.ControllerConfigFile.toString()));
|
||||
ConfigFile.ConfigSection Section = mConfigFile.get( name );
|
||||
if (Section == null)
|
||||
{
|
||||
//profile not found create it
|
||||
mConfigFile.put(name, "map", "-");
|
||||
Section = mConfigFile.get( name );
|
||||
if(Section == null)
|
||||
{
|
||||
throw new Error( "Invalid usage: profile name not found in config file" );
|
||||
}
|
||||
}
|
||||
mProfile = new Profile(false, Section);
|
||||
|
||||
// Set up input listeners
|
||||
mKeyProvider = new KeyProvider( KeyProvider.ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
|
||||
mKeyProvider.registerListener( this );
|
||||
if( AndroidDevice.IS_HONEYCOMB_MR1 )
|
||||
{
|
||||
mAxisProvider = new AxisProvider();
|
||||
mAxisProvider.registerListener( this );
|
||||
}
|
||||
|
||||
// Initialize the layout
|
||||
initLayoutDefault();
|
||||
|
||||
// Refresh everything
|
||||
refreshAllButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
|
||||
// Lazily persist the profile data; only need to do it on pause
|
||||
mProfile.writeTo( mConfigFile );
|
||||
mConfigFile.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
if (item.getItemId() == android.R.id.home)
|
||||
{
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
finish();
|
||||
}
|
||||
|
||||
private void initLayoutDefault()
|
||||
{
|
||||
WindowManager manager = (WindowManager) getSystemService( Context.WINDOW_SERVICE );
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
manager.getDefaultDisplay().getMetrics( metrics );
|
||||
float ScaleFactor = (float) DisplayMetrics.DENSITY_DEFAULT / (float) metrics.densityDpi;
|
||||
int widthDp = Math.round( metrics.widthPixels * ScaleFactor );
|
||||
|
||||
// For narrow screens, use an alternate layout
|
||||
if( widthDp < MIN_LAYOUT_WIDTH_DP )
|
||||
{
|
||||
setContentView( R.layout.controller_profile_activity_port );
|
||||
}
|
||||
else
|
||||
{
|
||||
setContentView( R.layout.controller_profile_activity );
|
||||
}
|
||||
|
||||
// Add the tool bar to the activity (which supports the fancy menu/arrow animation)
|
||||
Toolbar toolbar = findViewById( R.id.toolbar );
|
||||
toolbar.setTitle( getString(R.string.gamepad_title) );
|
||||
setSupportActionBar( toolbar );
|
||||
ActionBar actionbar = getSupportActionBar();
|
||||
|
||||
if (AndroidDevice.IS_ICE_CREAM_SANDWICH)
|
||||
{
|
||||
actionbar.setHomeButtonEnabled(true);
|
||||
actionbar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
// Initialize and refresh the widgets
|
||||
initWidgets();
|
||||
}
|
||||
|
||||
private void initWidgets()
|
||||
{
|
||||
// Get the text view object
|
||||
mFeedbackText = findViewById( R.id.textFeedback );
|
||||
mFeedbackText.setText( "" );
|
||||
|
||||
// Create a button list to simplify highlighting and mapping
|
||||
setupButton( R.id.buttonDR, AbstractController.DPD_R );
|
||||
setupButton( R.id.buttonDL, AbstractController.DPD_L );
|
||||
setupButton( R.id.buttonDD, AbstractController.DPD_D );
|
||||
setupButton( R.id.buttonDU, AbstractController.DPD_U );
|
||||
setupButton( R.id.buttonS, AbstractController.START );
|
||||
setupButton( R.id.buttonZ, AbstractController.BTN_Z );
|
||||
setupButton( R.id.buttonB, AbstractController.BTN_B );
|
||||
setupButton( R.id.buttonA, AbstractController.BTN_A );
|
||||
setupButton( R.id.buttonCR, AbstractController.CPD_R );
|
||||
setupButton( R.id.buttonCL, AbstractController.CPD_L );
|
||||
setupButton( R.id.buttonCD, AbstractController.CPD_D );
|
||||
setupButton( R.id.buttonCU, AbstractController.CPD_U );
|
||||
setupButton( R.id.buttonR, AbstractController.BTN_R );
|
||||
setupButton( R.id.buttonL, AbstractController.BTN_L );
|
||||
setupButton( R.id.buttonAR, InputMap.AXIS_R );
|
||||
setupButton( R.id.buttonAL, InputMap.AXIS_L );
|
||||
setupButton( R.id.buttonAD, InputMap.AXIS_D );
|
||||
setupButton( R.id.buttonAU, InputMap.AXIS_U );
|
||||
}
|
||||
|
||||
private void setupButton( int resId, int index )
|
||||
{
|
||||
mN64Buttons[index] = findViewById( resId );
|
||||
if( mN64Buttons[index] != null )
|
||||
{
|
||||
mN64Buttons[index].setOnClickListener( this );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view)
|
||||
{
|
||||
// Handle button clicks in the mapping screen
|
||||
for( int i = 0; i < mN64Buttons.length; i++ )
|
||||
{
|
||||
// Find the button that was pressed
|
||||
if( view.equals( mN64Buttons[i] ) )
|
||||
{
|
||||
// Popup a dialog to listen to input codes from user
|
||||
Button button = (Button) view;
|
||||
popupListener( button.getText(), i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private interface PromptInputCodeListener
|
||||
{
|
||||
void onDialogClosed( int inputCode, int hardwareId, int which );
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a dialog to prompt the user for an input code.
|
||||
*
|
||||
* @param context The activity context.
|
||||
* @param title The title of the dialog.
|
||||
* @param message The message to be shown inside the dialog.
|
||||
* @param neutralButtonText The text to be shown on the neutral button, or null.
|
||||
* @param listener The listener to process the input code, when provided.
|
||||
*/
|
||||
public static void promptInputCode( Context context, CharSequence title, CharSequence message,
|
||||
CharSequence neutralButtonText, final PromptInputCodeListener listener )
|
||||
{
|
||||
final ArrayList<AbstractProvider> providers = new ArrayList<>();
|
||||
|
||||
// Create a widget to dispatch key/motion event data
|
||||
FrameLayout view = new FrameLayout( context );
|
||||
EditText dummyImeListener = new EditText( context );
|
||||
dummyImeListener.setVisibility( View.INVISIBLE );
|
||||
dummyImeListener.setHeight( 0 );
|
||||
view.addView( dummyImeListener );
|
||||
|
||||
// Set the focus parameters of the view so that it will dispatch events
|
||||
view.setFocusable( true );
|
||||
view.setFocusableInTouchMode( true );
|
||||
view.requestFocus();
|
||||
|
||||
// Create the input event providers
|
||||
providers.add( new KeyProvider(view,KeyProvider.ImeFormula.DEFAULT,AndroidDevice.getUnmappableKeyCodes()));
|
||||
if( AndroidDevice.IS_HONEYCOMB_MR1 )
|
||||
{
|
||||
providers.add( new AxisProvider(view));
|
||||
}
|
||||
|
||||
// Notify the client when the user clicks the dialog's positive button
|
||||
DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick( DialogInterface dialog, int which )
|
||||
{
|
||||
for( AbstractProvider provider : providers )
|
||||
{
|
||||
provider.unregisterAllListeners();
|
||||
}
|
||||
listener.onDialogClosed( 0, 0, which );
|
||||
}
|
||||
};
|
||||
|
||||
final AlertDialog dialog = new AlertDialog.Builder( context ).setTitle( title ).setMessage( message ).setCancelable( false )
|
||||
.setNegativeButton( context.getString( android.R.string.cancel ), clickListener )
|
||||
.setPositiveButton( context.getString( android.R.string.ok ), clickListener )
|
||||
.setNeutralButton( neutralButtonText, clickListener ).setPositiveButton( null, null )
|
||||
.setView( view ).create();
|
||||
|
||||
AbstractProvider.OnInputListener inputListener = new AbstractProvider.OnInputListener()
|
||||
{
|
||||
@Override
|
||||
public void onInput( int[] inputCodes, float[] strengths, int hardwareId )
|
||||
{
|
||||
if( inputCodes == null || strengths == null )
|
||||
return;
|
||||
|
||||
// Find the strongest input
|
||||
float maxStrength = 0;
|
||||
int strongestInputCode = 0;
|
||||
for( int i = 0; i < inputCodes.length; i++ )
|
||||
{
|
||||
// Identify the strongest input
|
||||
float strength = strengths[i];
|
||||
if( strength > maxStrength )
|
||||
{
|
||||
maxStrength = strength;
|
||||
strongestInputCode = inputCodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Call the overloaded method with the strongest found
|
||||
onInput( strongestInputCode, maxStrength, hardwareId );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInput( int inputCode, float strength, int hardwareId )
|
||||
{
|
||||
if( inputCode != 0 && strength > AbstractProvider.STRENGTH_THRESHOLD )
|
||||
{
|
||||
for( AbstractProvider provider : providers )
|
||||
provider.unregisterAllListeners();
|
||||
listener.onDialogClosed( inputCode, hardwareId, DialogInterface.BUTTON_POSITIVE );
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Connect the upstream event listeners
|
||||
for( AbstractProvider provider : providers )
|
||||
{
|
||||
provider.registerListener( inputListener );
|
||||
}
|
||||
|
||||
// Launch the dialog
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void popupListener( CharSequence title, final int index )
|
||||
{
|
||||
final InputMap map = new InputMap( mProfile.get( "map" ) );
|
||||
String message = getString( R.string.inputMapActivity_popupMessage,map.getMappedCodeInfo( index ) );
|
||||
String btnText = getString( R.string.inputMapActivity_popupUnmap );
|
||||
|
||||
PromptInputCodeListener listener = new PromptInputCodeListener()
|
||||
{
|
||||
@Override
|
||||
public void onDialogClosed( int inputCode, int hardwareId, int which )
|
||||
{
|
||||
if( which != DialogInterface.BUTTON_NEGATIVE )
|
||||
{
|
||||
if( which == DialogInterface.BUTTON_POSITIVE )
|
||||
{
|
||||
map.map( inputCode, index );
|
||||
}
|
||||
else
|
||||
{
|
||||
map.unmapCommand( index );
|
||||
}
|
||||
mProfile.put( "map", map.serialize() );
|
||||
refreshAllButtons();
|
||||
}
|
||||
}
|
||||
};
|
||||
promptInputCode( this, title, message, btnText, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown( int keyCode, KeyEvent event )
|
||||
{
|
||||
return mKeyProvider.onKey( keyCode, event ) || super.onKeyDown( keyCode, event );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp( int keyCode, KeyEvent event )
|
||||
{
|
||||
return mKeyProvider.onKey( keyCode, event ) || super.onKeyUp( keyCode, event );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent( MotionEvent event )
|
||||
{
|
||||
if( !AndroidDevice.IS_HONEYCOMB_MR1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return mAxisProvider.onGenericMotion( event ) || super.onGenericMotionEvent( event );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInput(int inputCode, float strength, int hardwareId)
|
||||
{
|
||||
refreshButton( inputCode, strength );
|
||||
refreshFeedbackText( inputCode, strength );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInput(int[] inputCodes, float[] strengths, int hardwareId)
|
||||
{
|
||||
float maxStrength = AbstractProvider.STRENGTH_THRESHOLD;
|
||||
int strongestInputCode = 0;
|
||||
for( int i = 0; i < inputCodes.length; i++ )
|
||||
{
|
||||
int inputCode = inputCodes[i];
|
||||
float strength = strengths[i];
|
||||
|
||||
// Cache the strongest input
|
||||
if( strength > maxStrength )
|
||||
{
|
||||
maxStrength = strength;
|
||||
strongestInputCode = inputCode;
|
||||
}
|
||||
|
||||
refreshButton( inputCode, strength );
|
||||
}
|
||||
refreshFeedbackText( strongestInputCode, maxStrength );
|
||||
}
|
||||
|
||||
private void refreshFeedbackText( int inputCode, float strength )
|
||||
{
|
||||
// Update the feedback text (not all layouts include this, so check null)
|
||||
if( mFeedbackText != null )
|
||||
{
|
||||
mFeedbackText.setText( strength > AbstractProvider.STRENGTH_THRESHOLD ? AbstractProvider.getInputName( inputCode ) : "" );
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshButton( int inputCode, float strength )
|
||||
{
|
||||
InputMap map = new InputMap( mProfile.get( "map" ) );
|
||||
int command = map.get( inputCode );
|
||||
if( command != InputMap.UNMAPPED )
|
||||
{
|
||||
Button button = mN64Buttons[command];
|
||||
refreshButton( button, strength, true );
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshButton( Button button, float strength, boolean isMapped )
|
||||
{
|
||||
if( button != null )
|
||||
{
|
||||
button.setPressed( strength > AbstractProvider.STRENGTH_THRESHOLD );
|
||||
|
||||
// Fade any buttons that aren't mapped
|
||||
if( AndroidDevice.IS_HONEYCOMB )
|
||||
{
|
||||
if( isMapped )
|
||||
{
|
||||
button.setAlpha( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
button.setAlpha( UNMAPPED_BUTTON_ALPHA );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For older APIs try something similar (not quite the same)
|
||||
if( isMapped )
|
||||
{
|
||||
button.getBackground().clearColorFilter();
|
||||
}
|
||||
else
|
||||
{
|
||||
button.getBackground().setColorFilter( UNMAPPED_BUTTON_FILTER, PorterDuff.Mode.MULTIPLY );
|
||||
}
|
||||
button.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshAllButtons()
|
||||
{
|
||||
final InputMap map = new InputMap( mProfile.get( "map" ) );
|
||||
for( int i = 0; i < mN64Buttons.length; i++ )
|
||||
{
|
||||
refreshButton( mN64Buttons[i], 0, map.isMapped( i ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package emu.project64.settings;
|
|||
|
||||
import emu.project64.R;
|
||||
import emu.project64.SplashActivity;
|
||||
import emu.project64.profile.ControllerProfileActivity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
@ -61,6 +62,9 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat
|
|||
}
|
||||
else if (preference.getKey().equals("settings_gamepad_screen"))
|
||||
{
|
||||
final AppCompatActivity activity = (AppCompatActivity)getActivity();
|
||||
Intent intent = new Intent( activity, ControllerProfileActivity.class );
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
else if (preference.getKey().equals("settings_video"))
|
||||
{
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
>
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:focusableInTouchMode="false">
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/background_actionbar"
|
||||
android:theme="@style/Theme.Project64.ToolBar" />
|
||||
android:theme="@style/Theme.Project64.ToolBar"
|
||||
app:titleTextAppearance="@style/Theme.Project64.ToolBar.TitleText"
|
||||
/>
|
||||
|
||||
<!--
|
||||
***********************************************************************************
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
>
|
||||
<android.support.v7.widget.Toolbar
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/toolbar"
|
||||
|
|
Loading…
Reference in New Issue