Skip to content

Commit

Permalink
Merge pull request #7443 from zackhow/device-rumble
Browse files Browse the repository at this point in the history
Android: Add controller rumble support
  • Loading branch information
delroth committed Oct 28, 2018
2 parents 7094f22 + 3499a41 commit eb35514
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 98 deletions.
Expand Up @@ -7,15 +7,11 @@
package org.dolphinemu.dolphinemu;

import android.app.AlertDialog;
import android.content.Context;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.view.Surface;

import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.Rumble;

import java.lang.ref.WeakReference;

Expand Down Expand Up @@ -245,22 +241,7 @@ public static void rumble(int padID, double state)
return;
}

if (PreferenceManager.getDefaultSharedPreferences(emulationActivity)
.getBoolean("phoneRumble", true))
{
Vibrator vibrator = (Vibrator) emulationActivity.getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null && vibrator.hasVibrator())
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
vibrator.vibrate(VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
}
else
{
vibrator.vibrate(100);
}
}
}
Rumble.checkRumble(padID, state);
}

public static native String GetUserSetting(String gameID, String Section, String Key);
Expand Down
Expand Up @@ -44,6 +44,7 @@
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
import org.dolphinemu.dolphinemu.utils.Rumble;
import org.dolphinemu.dolphinemu.utils.TvUtil;

import java.lang.annotation.Retention;
Expand Down Expand Up @@ -249,6 +250,7 @@ protected void onCreate(Bundle savedInstanceState)

Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
Java_WiimoteAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
Rumble.initRumble(this);

setContentView(R.layout.activity_emulation);

Expand Down Expand Up @@ -292,6 +294,13 @@ protected void restoreState(Bundle savedInstanceState)
mPlatform = savedInstanceState.getInt(EXTRA_PLATFORM);
}

@Override
protected void onStop()
{
super.onStop();
Rumble.clear();
}

@Override
public void onBackPressed()
{
Expand Down Expand Up @@ -579,6 +588,7 @@ private void toggleRumble(boolean state)
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean("phoneRumble", state);
editor.apply();
Rumble.setPhoneVibrator(state, this);
}


Expand Down Expand Up @@ -836,6 +846,11 @@ private void showSubMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad)
.commit();
}

public boolean deviceHasTouchScreen()
{
return mDeviceHasTouchScreen;
}

public String getSelectedTitle()
{
return mSelectedTitle;
Expand Down
Expand Up @@ -3,14 +3,18 @@
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.Rumble;
import org.dolphinemu.dolphinemu.utils.TvUtil;

import java.util.ArrayList;
Expand Down Expand Up @@ -49,7 +53,8 @@ public boolean onKeyEvent(int keyCode, KeyEvent event)
case KeyEvent.ACTION_UP:
if (!ControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode))
{
saveKeyInput(event);
setting.onKeyInput(event);
dismiss();
}
// Even if we ignore the key, we still consume it. Thus return true regardless.
return true;
Expand All @@ -63,13 +68,11 @@ public boolean onKeyEvent(int keyCode, KeyEvent event)
public boolean onKeyLongPress(int keyCode, KeyEvent event)
{
// Option to clear by long back is only needed on the TV interface
if (TvUtil.isLeanback(getContext()))
if (TvUtil.isLeanback(getContext()) && keyCode == KeyEvent.KEYCODE_BACK)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
clearBinding();
return true;
}
setting.clearValue();
dismiss();
return true;
}
return super.onKeyLongPress(keyCode, event);
}
Expand Down Expand Up @@ -162,69 +165,10 @@ else if (Math.abs(value) < 0.25f && Math.abs(previousValue) > 0.75f)
if (numMovedAxis == 1)
{
mWaitingForEvent = false;
saveMotionInput(input, lastMovedRange, lastMovedDir);
setting.onMotionInput(input, lastMovedRange, lastMovedDir);
dismiss();
}
}

return true;
}

/**
* Saves the provided key input setting both to the INI file (so native code can use it) and as
* an Android preference (so it persists correctly and is human-readable.)
*
* @param keyEvent KeyEvent of this key press.
*/
private void saveKeyInput(KeyEvent keyEvent)
{
InputDevice device = keyEvent.getDevice();
String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
String uiString = device.getName() + ": Button " + keyEvent.getKeyCode();

saveInput(bindStr, uiString);
}

/**
* Saves the provided motion input setting both to the INI file (so native code can use it) and as
* an Android preference (so it persists correctly and is human-readable.)
*
* @param device InputDevice from which the input event originated.
* @param motionRange MotionRange of the movement
* @param axisDir Either '-' or '+'
*/
private void saveMotionInput(InputDevice device, InputDevice.MotionRange motionRange,
char axisDir)
{
String bindStr =
"Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir;
String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir;

saveInput(bindStr, uiString);
}

/**
* Save the input string to settings and SharedPreferences, then dismiss this Dialog.
*/
private void saveInput(String bind, String ui)
{
setting.setValue(bind);

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = preferences.edit();

editor.putString(setting.getKey(), ui);
editor.apply();

dismiss();
}

private void clearBinding()
{
setting.setValue("");
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = preferences.edit();
editor.remove(setting.getKey());
editor.apply();
dismiss();
}
}
@@ -1,9 +1,15 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;

import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.view.InputDevice;
import android.view.KeyEvent;

import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.features.settings.model.Setting;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;

public final class InputBindingSetting extends SettingsItem
public class InputBindingSetting extends SettingsItem
{
public InputBindingSetting(String key, String section, int titleId, Setting setting)
{
Expand All @@ -21,15 +27,53 @@ public String getValue()
return setting.getValue();
}

/**
* Saves the provided key input setting both to the INI file (so native code can use it) and as
* an Android preference (so it persists correctly and is human-readable.)
*
* @param keyEvent KeyEvent of this key press.
*/
public void onKeyInput(KeyEvent keyEvent)
{
InputDevice device = keyEvent.getDevice();
String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
String uiString = device.getName() + ": Button " + keyEvent.getKeyCode();
setValue(bindStr, uiString);
}

/**
* Saves the provided motion input setting both to the INI file (so native code can use it) and as
* an Android preference (so it persists correctly and is human-readable.)
*
* @param device InputDevice from which the input event originated.
* @param motionRange MotionRange of the movement
* @param axisDir Either '-' or '+'
*/
public void onMotionInput(InputDevice device, InputDevice.MotionRange motionRange,
char axisDir)
{
String bindStr =
"Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir;
String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir;
setValue(bindStr, uiString);
}

/**
* Write a value to the backing string. If that string was previously null,
* initializes a new one and returns it, so it can be added to the Hashmap.
*
* @param bind The input that will be bound
* @return null if overwritten successfully; otherwise, a newly created StringSetting.
*/
public StringSetting setValue(String bind)
public StringSetting setValue(String bind, String ui)
{
SharedPreferences
preferences =
PreferenceManager.getDefaultSharedPreferences(DolphinApplication.getAppContext());
SharedPreferences.Editor editor = preferences.edit();
editor.putString(getKey(), ui);
editor.apply();

if (getSetting() == null)
{
StringSetting setting = new StringSetting(getKey(), getSection(), bind);
Expand All @@ -44,6 +88,11 @@ public StringSetting setValue(String bind)
}
}

public void clearValue()
{
setValue("", "");
}

@Override
public int getType()
{
Expand Down
@@ -0,0 +1,75 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;

import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Vibrator;
import android.view.InputDevice;
import android.view.KeyEvent;

import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.Setting;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.utils.Rumble;

public class RumbleBindingSetting extends InputBindingSetting
{

public RumbleBindingSetting(String key, String section, int titleId, Setting setting)
{
super(key, section, titleId, setting);
}

@Override
public String getValue()
{
if (getSetting() == null)
{
return "";
}

StringSetting setting = (StringSetting) getSetting();
return setting.getValue();
}

/**
* Just need the device when saving rumble.
*/
@Override
public void onKeyInput(KeyEvent keyEvent)
{
saveRumble(keyEvent.getDevice());
}

/**
* Just need the device when saving rumble.
*/
@Override
public void onMotionInput(InputDevice device,
InputDevice.MotionRange motionRange,
char axisDir)
{
saveRumble(device);
}

private void saveRumble(InputDevice device)
{
Vibrator vibrator = device.getVibrator();
if (vibrator != null && vibrator.hasVibrator())
{
setValue(device.getDescriptor(), device.getName());
Rumble.doRumble(vibrator);
}
else
{
setValue("",
DolphinApplication.getAppContext().getString(R.string.rumble_not_found));
}
}

@Override
public int getType()
{
return TYPE_RUMBLE_BINDING;
}
}
Expand Up @@ -19,6 +19,7 @@ public abstract class SettingsItem
public static final int TYPE_SUBMENU = 4;
public static final int TYPE_INPUT_BINDING = 5;
public static final int TYPE_STRING_SINGLE_CHOICE = 6;
public static final int TYPE_RUMBLE_BINDING = 7;

private String mKey;
private String mSection;
Expand Down

0 comments on commit eb35514

Please sign in to comment.