mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 22:05:38 +00:00
Android: Add hotkey binding support
This commit is contained in:
parent
2672e2b505
commit
22bb64e7b0
|
@ -1170,6 +1170,43 @@ DEFINE_JNI_ARGS_METHOD(jarray, AndroidHostInterface_getGameListEntries, jobject
|
|||
return entry_array;
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jobjectArray , AndroidHostInterface_getHotkeyInfoList, jobject obj)
|
||||
{
|
||||
jclass entry_class = env->FindClass("com/github/stenzek/duckstation/HotkeyInfo");
|
||||
Assert(entry_class != nullptr);
|
||||
|
||||
jmethodID entry_constructor =
|
||||
env->GetMethodID(entry_class, "<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
Assert(entry_constructor != nullptr);
|
||||
|
||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||
const CommonHostInterface::HotkeyInfoList& hotkeys = hi->GetHotkeyInfoList();
|
||||
if (hotkeys.empty())
|
||||
return nullptr;
|
||||
|
||||
jobjectArray entry_array = env->NewObjectArray(static_cast<jsize>(hotkeys.size()), entry_class, nullptr);
|
||||
Assert(entry_array != nullptr);
|
||||
|
||||
u32 counter = 0;
|
||||
for (const CommonHostInterface::HotkeyInfo& hk : hotkeys)
|
||||
{
|
||||
jstring category = env->NewStringUTF(hk.category.GetCharArray());
|
||||
jstring name = env->NewStringUTF(hk.name.GetCharArray());
|
||||
jstring display_name = env->NewStringUTF(hk.display_name.GetCharArray());
|
||||
|
||||
jobject entry_jobject = env->NewObject(entry_class, entry_constructor, category, name, display_name);
|
||||
|
||||
env->SetObjectArrayElement(entry_array, counter++, entry_jobject);
|
||||
env->DeleteLocalRef(entry_jobject);
|
||||
env->DeleteLocalRef(display_name);
|
||||
env->DeleteLocalRef(name);
|
||||
env->DeleteLocalRef(category);
|
||||
}
|
||||
|
||||
return entry_array;
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_applySettings, jobject obj)
|
||||
{
|
||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||
|
|
|
@ -81,6 +81,8 @@ public class AndroidHostInterface {
|
|||
public native boolean loadInputProfile(String name);
|
||||
public native boolean saveInputProfile(String name);
|
||||
|
||||
public native HotkeyInfo[] getHotkeyInfoList();
|
||||
|
||||
public native void refreshGameList(boolean invalidateCache, boolean invalidateDatabase, AndroidProgressCallback progressCallback);
|
||||
|
||||
public native GameListEntry[] getGameListEntries();
|
||||
|
|
|
@ -14,10 +14,16 @@ import androidx.preference.PreferenceViewHolder;
|
|||
import java.util.Set;
|
||||
|
||||
public class ControllerBindingPreference extends Preference {
|
||||
private boolean mIsAxis;
|
||||
private enum Type {
|
||||
BUTTON,
|
||||
AXIS,
|
||||
HOTKEY
|
||||
}
|
||||
|
||||
private String mBindingName;
|
||||
private String mValue;
|
||||
private TextView mValueView;
|
||||
private Type mType = Type.BUTTON;
|
||||
|
||||
private static int getIconForButton(String buttonName) {
|
||||
if (buttonName.equals("Up")) {
|
||||
|
@ -57,6 +63,10 @@ public class ControllerBindingPreference extends Preference {
|
|||
return R.drawable.ic_baseline_radio_button_checked_24;
|
||||
}
|
||||
|
||||
private static int getIconForHotkey(String hotkeyDisplayName) {
|
||||
return R.drawable.ic_baseline_category_24;
|
||||
}
|
||||
|
||||
public ControllerBindingPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
setWidgetLayoutResource(R.layout.layout_controller_binding_preference);
|
||||
|
@ -83,32 +93,47 @@ public class ControllerBindingPreference extends Preference {
|
|||
TextView nameView = ((TextView)holder.findViewById(R.id.controller_binding_name));
|
||||
mValueView = ((TextView)holder.findViewById(R.id.controller_binding_value));
|
||||
|
||||
iconView.setImageDrawable(ContextCompat.getDrawable(getContext(), getIconForButton(mBindingName)));
|
||||
int drawableId = R.drawable.ic_baseline_radio_button_checked_24;
|
||||
switch (mType)
|
||||
{
|
||||
case BUTTON: drawableId = getIconForButton(mBindingName); break;
|
||||
case AXIS: drawableId = getIconForAxis(mBindingName); break;
|
||||
case HOTKEY: drawableId = getIconForHotkey(mBindingName); break;
|
||||
}
|
||||
|
||||
iconView.setImageDrawable(ContextCompat.getDrawable(getContext(), drawableId));
|
||||
nameView.setText(mBindingName);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
ControllerBindingDialog dialog = new ControllerBindingDialog(getContext(), mBindingName, getKey(), mValue, mIsAxis);
|
||||
ControllerBindingDialog dialog = new ControllerBindingDialog(getContext(), mBindingName, getKey(), mValue, (mType == Type.AXIS));
|
||||
dialog.setOnDismissListener((dismissedDialog) -> updateValue());
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public void initButton(int controllerIndex, String buttonName) {
|
||||
mBindingName = buttonName;
|
||||
mIsAxis = false;
|
||||
mType = Type.BUTTON;
|
||||
setKey(String.format("Controller%d/Button%s", controllerIndex, buttonName));
|
||||
updateValue();
|
||||
}
|
||||
|
||||
public void initAxis(int controllerIndex, String axisName) {
|
||||
mBindingName = axisName;
|
||||
mIsAxis = true;
|
||||
mType = Type.AXIS;
|
||||
setKey(String.format("Controller%d/Axis%s", controllerIndex, axisName));
|
||||
updateValue();
|
||||
}
|
||||
|
||||
public void initHotkey(HotkeyInfo hotkeyInfo) {
|
||||
mBindingName = hotkeyInfo.getDisplayName();
|
||||
mType = Type.HOTKEY;
|
||||
setKey(hotkeyInfo.getBindingConfigKey());
|
||||
updateValue();
|
||||
}
|
||||
|
||||
private void updateValue(String value) {
|
||||
mValue = value;
|
||||
if (mValueView != null) {
|
||||
|
|
|
@ -151,11 +151,11 @@ public class ControllerMappingActivity extends AppCompatActivity {
|
|||
pref.updateValue();
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
public static class ControllerPortFragment extends PreferenceFragmentCompat {
|
||||
private ControllerMappingActivity activity;
|
||||
private int controllerIndex;
|
||||
|
||||
public SettingsFragment(ControllerMappingActivity activity, int controllerIndex) {
|
||||
public ControllerPortFragment(ControllerMappingActivity activity, int controllerIndex) {
|
||||
this.activity = activity;
|
||||
this.controllerIndex = controllerIndex;
|
||||
}
|
||||
|
@ -189,6 +189,31 @@ public class ControllerMappingActivity extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
|
||||
public static class HotkeyFragment extends PreferenceFragmentCompat {
|
||||
private ControllerMappingActivity activity;
|
||||
private HotkeyInfo[] mHotkeyInfo;
|
||||
|
||||
public HotkeyFragment(ControllerMappingActivity activity) {
|
||||
this.activity = activity;
|
||||
this.mHotkeyInfo = AndroidHostInterface.getInstance().getHotkeyInfoList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
|
||||
if (mHotkeyInfo != null) {
|
||||
for (HotkeyInfo hotkeyInfo : mHotkeyInfo) {
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initHotkey(hotkeyInfo);
|
||||
ps.addPreference(cbp);
|
||||
activity.mPreferences.add(cbp);
|
||||
}
|
||||
}
|
||||
|
||||
setPreferenceScreen(ps);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsCollectionFragment extends Fragment {
|
||||
private ControllerMappingActivity activity;
|
||||
private SettingsCollectionAdapter adapter;
|
||||
|
@ -211,9 +236,12 @@ public class ControllerMappingActivity extends AppCompatActivity {
|
|||
viewPager.setAdapter(adapter);
|
||||
|
||||
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
|
||||
new TabLayoutMediator(tabLayout, viewPager,
|
||||
(tab, position) -> tab.setText(String.format("Port %d", position + 1))
|
||||
).attach();
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
if (position == NUM_CONTROLLER_PORTS)
|
||||
tab.setText("Hotkeys");
|
||||
else
|
||||
tab.setText(String.format("Port %d", position + 1));
|
||||
}).attach();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,12 +256,15 @@ public class ControllerMappingActivity extends AppCompatActivity {
|
|||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
return new SettingsFragment(activity, position + 1);
|
||||
if (position != NUM_CONTROLLER_PORTS)
|
||||
return new ControllerPortFragment(activity, position + 1);
|
||||
else
|
||||
return new HotkeyFragment(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return NUM_CONTROLLER_PORTS;
|
||||
return NUM_CONTROLLER_PORTS + 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
public class HotkeyInfo {
|
||||
private String mCategory;
|
||||
private String mName;
|
||||
private String mDisplayName;
|
||||
|
||||
public HotkeyInfo(String category, String name, String displayName) {
|
||||
mCategory = category;
|
||||
mName = name;
|
||||
mDisplayName = displayName;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return mCategory;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return mDisplayName;
|
||||
}
|
||||
|
||||
public String getBindingConfigKey() {
|
||||
return String.format("Hotkeys/%s", mName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2l-5.5,9h11z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17.5,17.5m-4.5,0a4.5,4.5 0,1 1,9 0a4.5,4.5 0,1 1,-9 0"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,13.5h8v8H3z"/>
|
||||
</vector>
|
Loading…
Reference in a new issue