Merge pull request #7443 from zackhow/device-rumble
Android: Add controller rumble support
This commit is contained in:
commit
eb35514f3b
|
@ -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;
|
||||
|
||||
|
@ -245,22 +241,7 @@ public final class NativeLibrary
|
|||
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);
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper;
|
|||
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;
|
||||
|
@ -249,6 +250,7 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
|
||||
Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
||||
Java_WiimoteAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
||||
Rumble.initRumble(this);
|
||||
|
||||
setContentView(R.layout.activity_emulation);
|
||||
|
||||
|
@ -292,6 +294,13 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
mPlatform = savedInstanceState.getInt(EXTRA_PLATFORM);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop()
|
||||
{
|
||||
super.onStop();
|
||||
Rumble.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
|
@ -579,6 +588,7 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean("phoneRumble", state);
|
||||
editor.apply();
|
||||
Rumble.setPhoneVibrator(state, this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -836,6 +846,11 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
.commit();
|
||||
}
|
||||
|
||||
public boolean deviceHasTouchScreen()
|
||||
{
|
||||
return mDeviceHasTouchScreen;
|
||||
}
|
||||
|
||||
public String getSelectedTitle()
|
||||
{
|
||||
return mSelectedTitle;
|
||||
|
|
|
@ -3,14 +3,18 @@ package org.dolphinemu.dolphinemu.dialogs;
|
|||
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;
|
||||
|
@ -49,7 +53,8 @@ public final class MotionAlertDialog extends AlertDialog
|
|||
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;
|
||||
|
@ -63,13 +68,11 @@ public final class MotionAlertDialog extends AlertDialog
|
|||
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);
|
||||
}
|
||||
|
@ -162,69 +165,10 @@ public final class MotionAlertDialog extends AlertDialog
|
|||
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)
|
||||
{
|
||||
|
@ -21,6 +27,37 @@ public final class InputBindingSetting extends SettingsItem
|
|||
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.
|
||||
|
@ -28,8 +65,15 @@ public final class InputBindingSetting extends SettingsItem
|
|||
* @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);
|
||||
|
@ -44,6 +88,11 @@ public final class InputBindingSetting extends SettingsItem
|
|||
}
|
||||
}
|
||||
|
||||
public void clearValue()
|
||||
{
|
||||
setValue("", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.Settings;
|
|||
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SliderSetting;
|
||||
|
@ -29,6 +30,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting;
|
|||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.CheckBoxSettingViewHolder;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderViewHolder;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.InputBindingSettingViewHolder;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.RumbleBindingViewHolder;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SettingViewHolder;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SingleChoiceViewHolder;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SliderViewHolder;
|
||||
|
@ -90,6 +92,10 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
|
|||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new InputBindingSettingViewHolder(view, this, mContext);
|
||||
|
||||
case SettingsItem.TYPE_RUMBLE_BINDING:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new RumbleBindingViewHolder(view, this, mContext);
|
||||
|
||||
default:
|
||||
Log.error("[SettingsAdapter] Invalid view type: " + viewType);
|
||||
return null;
|
||||
|
@ -216,19 +222,17 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
|
|||
{
|
||||
final MotionAlertDialog dialog = new MotionAlertDialog(mContext, item);
|
||||
dialog.setTitle(R.string.input_binding);
|
||||
dialog.setMessage(String.format(mContext.getString(R.string.input_binding_description),
|
||||
dialog.setMessage(String.format(mContext.getString(
|
||||
item instanceof RumbleBindingSetting ?
|
||||
R.string.input_rumble_description : R.string.input_binding_description),
|
||||
mContext.getString(item.getNameId())));
|
||||
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), this);
|
||||
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, mContext.getString(R.string.clear),
|
||||
(dialogInterface, i) ->
|
||||
{
|
||||
item.setValue("");
|
||||
|
||||
SharedPreferences sharedPreferences =
|
||||
SharedPreferences preferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(item.getKey());
|
||||
editor.apply();
|
||||
item.clearValue();
|
||||
});
|
||||
dialog.setOnDismissListener(dialog1 ->
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
|
|||
import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.HeaderSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SliderSetting;
|
||||
|
@ -632,6 +633,8 @@ public final class SettingsFragmentPresenter
|
|||
bindingsSection.getSetting(SettingsFile.KEY_GCBIND_DPAD_LEFT + gcPadNumber);
|
||||
Setting bindDPadRight =
|
||||
bindingsSection.getSetting(SettingsFile.KEY_GCBIND_DPAD_RIGHT + gcPadNumber);
|
||||
Setting gcEmuRumble =
|
||||
bindingsSection.getSetting(SettingsFile.KEY_EMU_RUMBLE + gcPadNumber);
|
||||
|
||||
sl.add(new HeaderSetting(null, null, R.string.generic_buttons, 0));
|
||||
sl.add(new InputBindingSetting(SettingsFile.KEY_GCBIND_A + gcPadNumber,
|
||||
|
@ -682,6 +685,11 @@ public final class SettingsFragmentPresenter
|
|||
Settings.SECTION_BINDINGS, R.string.generic_left, bindDPadLeft));
|
||||
sl.add(new InputBindingSetting(SettingsFile.KEY_GCBIND_DPAD_RIGHT + gcPadNumber,
|
||||
Settings.SECTION_BINDINGS, R.string.generic_right, bindDPadRight));
|
||||
|
||||
|
||||
sl.add(new HeaderSetting(null, null, R.string.emulation_control_rumble, 0));
|
||||
sl.add(new RumbleBindingSetting(SettingsFile.KEY_EMU_RUMBLE + gcPadNumber,
|
||||
Settings.SECTION_BINDINGS, R.string.emulation_control_rumble, gcEmuRumble));
|
||||
}
|
||||
else // Adapter
|
||||
{
|
||||
|
@ -761,6 +769,8 @@ public final class SettingsFragmentPresenter
|
|||
bindingsSection.getSetting(SettingsFile.KEY_WIIBIND_DPAD_LEFT + wiimoteNumber);
|
||||
Setting bindDPadRight =
|
||||
bindingsSection.getSetting(SettingsFile.KEY_WIIBIND_DPAD_RIGHT + wiimoteNumber);
|
||||
Setting wiiEmuRumble =
|
||||
bindingsSection.getSetting(SettingsFile.KEY_EMU_RUMBLE + wiimoteNumber);
|
||||
|
||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_WIIMOTE_EXTENSION,
|
||||
Settings.SECTION_WIIMOTE + (wiimoteNumber - 3), R.string.wiimote_extensions,
|
||||
|
@ -843,6 +853,11 @@ public final class SettingsFragmentPresenter
|
|||
Settings.SECTION_BINDINGS, R.string.generic_left, bindDPadLeft));
|
||||
sl.add(new InputBindingSetting(SettingsFile.KEY_WIIBIND_DPAD_RIGHT + wiimoteNumber,
|
||||
Settings.SECTION_BINDINGS, R.string.generic_right, bindDPadRight));
|
||||
|
||||
|
||||
sl.add(new HeaderSetting(null, null, R.string.emulation_control_rumble, 0));
|
||||
sl.add(new RumbleBindingSetting(SettingsFile.KEY_EMU_RUMBLE + wiimoteNumber,
|
||||
Settings.SECTION_BINDINGS, R.string.emulation_control_rumble, wiiEmuRumble));
|
||||
}
|
||||
|
||||
private void addExtensionTypeSettings(ArrayList<SettingsItem> sl, int wiimoteNumber,
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||
|
||||
public class RumbleBindingViewHolder extends SettingViewHolder
|
||||
{
|
||||
private RumbleBindingSetting mItem;
|
||||
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public RumbleBindingViewHolder(View itemView, SettingsAdapter adapter, Context context)
|
||||
{
|
||||
super(itemView, adapter);
|
||||
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
|
||||
mItem = (RumbleBindingSetting) item;
|
||||
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
mTextSettingDescription.setText(sharedPreferences.getString(mItem.getKey(), ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
|
||||
}
|
||||
}
|
|
@ -115,6 +115,8 @@ public final class SettingsFile
|
|||
public static final String KEY_GCADAPTER_RUMBLE = "AdapterRumble";
|
||||
public static final String KEY_GCADAPTER_BONGOS = "SimulateKonga";
|
||||
|
||||
public static final String KEY_EMU_RUMBLE = "EmuRumble";
|
||||
|
||||
public static final String KEY_WIIMOTE_TYPE = "Source";
|
||||
public static final String KEY_WIIMOTE_EXTENSION = "Extension";
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.SparseArray;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Rumble
|
||||
{
|
||||
private static Vibrator phoneVibrator;
|
||||
private static SparseArray<Vibrator> emuVibrators;
|
||||
|
||||
public static void initRumble(EmulationActivity activity)
|
||||
{
|
||||
if (activity.deviceHasTouchScreen() &&
|
||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
.getBoolean("phoneRumble", true))
|
||||
{
|
||||
setPhoneVibrator(true, activity);
|
||||
}
|
||||
|
||||
emuVibrators = new SparseArray<>();
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
StringSetting deviceName =
|
||||
(StringSetting) activity.getSettings().getSection(Settings.SECTION_BINDINGS)
|
||||
.getSetting(SettingsFile.KEY_EMU_RUMBLE + i);
|
||||
if (deviceName != null && !deviceName.getValue().isEmpty())
|
||||
{
|
||||
for (int id : InputDevice.getDeviceIds())
|
||||
{
|
||||
InputDevice device = InputDevice.getDevice(id);
|
||||
if (deviceName.getValue().equals(device.getDescriptor()))
|
||||
{
|
||||
Vibrator vib = device.getVibrator();
|
||||
if (vib != null && vib.hasVibrator())
|
||||
emuVibrators.put(i, vib);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setPhoneVibrator(boolean set, EmulationActivity activity)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
Vibrator vib = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (vib != null && vib.hasVibrator())
|
||||
phoneVibrator = vib;
|
||||
}
|
||||
else
|
||||
{
|
||||
phoneVibrator = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void clear()
|
||||
{
|
||||
phoneVibrator = null;
|
||||
emuVibrators.clear();
|
||||
}
|
||||
|
||||
public static void checkRumble(int padId, double state)
|
||||
{
|
||||
if (phoneVibrator != null)
|
||||
doRumble(phoneVibrator);
|
||||
|
||||
if (emuVibrators.get(padId) != null)
|
||||
doRumble(emuVibrators.get(padId));
|
||||
}
|
||||
|
||||
public static void doRumble(Vibrator vib)
|
||||
{
|
||||
// Check again that it exists and can vibrate
|
||||
if (vib != null && vib.hasVibrator())
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
{
|
||||
vib.vibrate(VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
}
|
||||
else
|
||||
{
|
||||
vib.vibrate(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
<string name="input_binding">Input Binding</string>
|
||||
<string name="input_binding_description">Press or move an input to bind it to %1$s.</string>
|
||||
<string name="input_rumble_description">Press or move any input to set rumble.</string>
|
||||
|
||||
<!-- Generic buttons (Shared with lots of stuff) -->
|
||||
<string name="generic_buttons">Buttons</string>
|
||||
|
@ -291,6 +292,9 @@
|
|||
<string name="header_wiimote_general">General</string>
|
||||
<string name="header_controllers">Controllers</string>
|
||||
|
||||
<!-- Rumble -->
|
||||
<string name="rumble_not_found">Device rumble not found</string>
|
||||
|
||||
<string name="write_permission_needed">You need to allow write access to external storage for the emulator to work</string>
|
||||
<string name="load_settings">Loading Settings...</string>
|
||||
<string name="emulation_change_disc">Change Disc</string>
|
||||
|
|
Loading…
Reference in New Issue