mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-30 02:32:46 +01:00
android: Convert keyboard applet to kotlin and refactor
This commit is contained in:
parent
d5ebfc8e21
commit
d30103b69f
6 changed files with 255 additions and 279 deletions
|
@ -83,22 +83,22 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||||
if (event.action == android.view.KeyEvent.ACTION_DOWN) {
|
if (event.action == KeyEvent.ACTION_DOWN) {
|
||||||
if (keyCode == android.view.KeyEvent.KEYCODE_ENTER) {
|
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||||
// Special case, we do not support multiline input, dismiss the keyboard.
|
// Special case, we do not support multiline input, dismiss the keyboard.
|
||||||
val overlayView: View =
|
val overlayView: View =
|
||||||
this.findViewById<View>(R.id.surface_input_overlay)
|
this.findViewById(R.id.surface_input_overlay)
|
||||||
val im =
|
val im =
|
||||||
overlayView.context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
overlayView.context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
im.hideSoftInputFromWindow(overlayView.windowToken, 0);
|
im.hideSoftInputFromWindow(overlayView.windowToken, 0)
|
||||||
} else {
|
} else {
|
||||||
val textChar = event.getUnicodeChar();
|
val textChar = event.unicodeChar
|
||||||
if (textChar == 0) {
|
if (textChar == 0) {
|
||||||
// No text, button input.
|
// No text, button input.
|
||||||
NativeLibrary.SubmitInlineKeyboardInput(keyCode);
|
NativeLibrary.SubmitInlineKeyboardInput(keyCode)
|
||||||
} else {
|
} else {
|
||||||
// Text submitted.
|
// Text submitted.
|
||||||
NativeLibrary.SubmitInlineKeyboardText(textChar.toChar().toString());
|
NativeLibrary.SubmitInlineKeyboardText(textChar.toChar().toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,264 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.applets;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.ResultReceiver;
|
|
||||||
import android.text.InputFilter;
|
|
||||||
import android.text.InputType;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewTreeObserver;
|
|
||||||
import android.view.WindowInsets;
|
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.core.view.ViewCompat;
|
|
||||||
import androidx.fragment.app.DialogFragment;
|
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication;
|
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary;
|
|
||||||
import org.yuzu.yuzu_emu.R;
|
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public final class SoftwareKeyboard {
|
|
||||||
/// Corresponds to Service::AM::Applets::SwkbdType
|
|
||||||
private interface SwkbdType {
|
|
||||||
int Normal = 0;
|
|
||||||
int NumberPad = 1;
|
|
||||||
int Qwerty = 2;
|
|
||||||
int Unknown3 = 3;
|
|
||||||
int Latin = 4;
|
|
||||||
int SimplifiedChinese = 5;
|
|
||||||
int TraditionalChinese = 6;
|
|
||||||
int Korean = 7;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Corresponds to Service::AM::Applets::SwkbdPasswordMode
|
|
||||||
private interface SwkbdPasswordMode {
|
|
||||||
int Disabled = 0;
|
|
||||||
int Enabled = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Corresponds to Service::AM::Applets::SwkbdResult
|
|
||||||
private interface SwkbdResult {
|
|
||||||
int Ok = 0;
|
|
||||||
int Cancel = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
public static class KeyboardConfig implements java.io.Serializable {
|
|
||||||
public String ok_text;
|
|
||||||
public String header_text;
|
|
||||||
public String sub_text;
|
|
||||||
public String guide_text;
|
|
||||||
public String initial_text;
|
|
||||||
public short left_optional_symbol_key;
|
|
||||||
public short right_optional_symbol_key;
|
|
||||||
public int max_text_length;
|
|
||||||
public int min_text_length;
|
|
||||||
public int initial_cursor_position;
|
|
||||||
public int type;
|
|
||||||
public int password_mode;
|
|
||||||
public int text_draw_type;
|
|
||||||
public int key_disable_flags;
|
|
||||||
public boolean use_blur_background;
|
|
||||||
public boolean enable_backspace_button;
|
|
||||||
public boolean enable_return_button;
|
|
||||||
public boolean disable_cancel_button;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Corresponds to Frontend::KeyboardData
|
|
||||||
public static class KeyboardData {
|
|
||||||
public int result;
|
|
||||||
public String text;
|
|
||||||
|
|
||||||
private KeyboardData(int result, String text) {
|
|
||||||
this.result = result;
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class KeyboardDialogFragment extends DialogFragment {
|
|
||||||
static KeyboardDialogFragment newInstance(KeyboardConfig config) {
|
|
||||||
KeyboardDialogFragment frag = new KeyboardDialogFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putSerializable("config", config);
|
|
||||||
frag.setArguments(args);
|
|
||||||
return frag;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
final Activity emulationActivity = getActivity();
|
|
||||||
assert emulationActivity != null;
|
|
||||||
|
|
||||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
params.leftMargin = params.rightMargin =
|
|
||||||
YuzuApplication.getAppContext().getResources().getDimensionPixelSize(
|
|
||||||
R.dimen.dialog_margin);
|
|
||||||
|
|
||||||
KeyboardConfig config = Objects.requireNonNull(
|
|
||||||
(KeyboardConfig) requireArguments().getSerializable("config"));
|
|
||||||
|
|
||||||
// Set up the input
|
|
||||||
EditText editText = new EditText(YuzuApplication.getAppContext());
|
|
||||||
editText.setHint(config.initial_text);
|
|
||||||
editText.setSingleLine(!config.enable_return_button);
|
|
||||||
editText.setLayoutParams(params);
|
|
||||||
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(config.max_text_length)});
|
|
||||||
|
|
||||||
// Handle input type
|
|
||||||
int input_type = 0;
|
|
||||||
switch (config.type)
|
|
||||||
{
|
|
||||||
case SwkbdType.Normal:
|
|
||||||
case SwkbdType.Qwerty:
|
|
||||||
case SwkbdType.Unknown3:
|
|
||||||
case SwkbdType.Latin:
|
|
||||||
case SwkbdType.SimplifiedChinese:
|
|
||||||
case SwkbdType.TraditionalChinese:
|
|
||||||
case SwkbdType.Korean:
|
|
||||||
default:
|
|
||||||
input_type = InputType.TYPE_CLASS_TEXT;
|
|
||||||
if (config.password_mode == SwkbdPasswordMode.Enabled)
|
|
||||||
{
|
|
||||||
input_type |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SwkbdType.NumberPad:
|
|
||||||
input_type = InputType.TYPE_CLASS_NUMBER;
|
|
||||||
if (config.password_mode == SwkbdPasswordMode.Enabled)
|
|
||||||
{
|
|
||||||
input_type |= InputType.TYPE_NUMBER_VARIATION_PASSWORD;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply input type
|
|
||||||
editText.setInputType(input_type);
|
|
||||||
|
|
||||||
FrameLayout container = new FrameLayout(emulationActivity);
|
|
||||||
container.addView(editText);
|
|
||||||
|
|
||||||
String headerText = config.header_text.isEmpty() ? emulationActivity.getString(R.string.software_keyboard) : config.header_text;
|
|
||||||
String okText = config.header_text.isEmpty() ? emulationActivity.getString(android.R.string.ok) : config.ok_text;
|
|
||||||
|
|
||||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
|
|
||||||
.setTitle(headerText)
|
|
||||||
.setView(container);
|
|
||||||
setCancelable(false);
|
|
||||||
|
|
||||||
builder.setPositiveButton(okText, null);
|
|
||||||
builder.setNegativeButton(emulationActivity.getString(android.R.string.cancel), null);
|
|
||||||
|
|
||||||
final AlertDialog dialog = builder.create();
|
|
||||||
dialog.create();
|
|
||||||
if (dialog.getButton(DialogInterface.BUTTON_POSITIVE) != null) {
|
|
||||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener((view) -> {
|
|
||||||
data.result = SwkbdResult.Ok;
|
|
||||||
data.text = editText.getText().toString();
|
|
||||||
dialog.dismiss();
|
|
||||||
|
|
||||||
synchronized (finishLock) {
|
|
||||||
finishLock.notifyAll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (dialog.getButton(DialogInterface.BUTTON_NEUTRAL) != null) {
|
|
||||||
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener((view) -> {
|
|
||||||
data.result = SwkbdResult.Ok;
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (finishLock) {
|
|
||||||
finishLock.notifyAll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (dialog.getButton(DialogInterface.BUTTON_NEGATIVE) != null) {
|
|
||||||
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener((view) -> {
|
|
||||||
data.result = SwkbdResult.Cancel;
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (finishLock) {
|
|
||||||
finishLock.notifyAll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static KeyboardData data;
|
|
||||||
private static final Object finishLock = new Object();
|
|
||||||
|
|
||||||
private static void ExecuteNormalImpl(KeyboardConfig config) {
|
|
||||||
final EmulationActivity emulationActivity = NativeLibrary.sEmulationActivity.get();
|
|
||||||
|
|
||||||
data = new KeyboardData(SwkbdResult.Cancel, "");
|
|
||||||
|
|
||||||
KeyboardDialogFragment fragment = KeyboardDialogFragment.newInstance(config);
|
|
||||||
fragment.show(emulationActivity.getSupportFragmentManager(), "keyboard");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ExecuteInlineImpl(KeyboardConfig config) {
|
|
||||||
final EmulationActivity emulationActivity = NativeLibrary.sEmulationActivity.get();
|
|
||||||
|
|
||||||
var overlayView = emulationActivity.findViewById(R.id.surface_input_overlay);
|
|
||||||
InputMethodManager im = (InputMethodManager)overlayView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
||||||
im.showSoftInput(overlayView, InputMethodManager.SHOW_FORCED);
|
|
||||||
|
|
||||||
// There isn't a good way to know that the IMM is dismissed, so poll every 500ms to submit inline keyboard result.
|
|
||||||
final Handler handler = new Handler();
|
|
||||||
final int delayMs = 500;
|
|
||||||
handler.postDelayed(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
var insets = ViewCompat.getRootWindowInsets(overlayView);
|
|
||||||
var isKeyboardVisible = insets.isVisible(WindowInsets.Type.ime());
|
|
||||||
if (isKeyboardVisible) {
|
|
||||||
handler.postDelayed(this, delayMs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No longer visible, submit the result.
|
|
||||||
NativeLibrary.SubmitInlineKeyboardInput(android.view.KeyEvent.KEYCODE_ENTER);
|
|
||||||
}
|
|
||||||
}, delayMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyboardData ExecuteNormal(KeyboardConfig config) {
|
|
||||||
NativeLibrary.sEmulationActivity.get().runOnUiThread(() -> ExecuteNormalImpl(config));
|
|
||||||
|
|
||||||
synchronized (finishLock) {
|
|
||||||
try {
|
|
||||||
finishLock.wait();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ExecuteInline(KeyboardConfig config) {
|
|
||||||
NativeLibrary.sEmulationActivity.get().runOnUiThread(() -> ExecuteInlineImpl(config));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ShowError(String error) {
|
|
||||||
NativeLibrary.displayAlertMsg(
|
|
||||||
YuzuApplication.getAppContext().getResources().getString(R.string.software_keyboard),
|
|
||||||
error, false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.applets.keyboard
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.applets.keyboard.ui.KeyboardDialogFragment
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
object SoftwareKeyboard {
|
||||||
|
lateinit var data: KeyboardData
|
||||||
|
val dataLock = Object()
|
||||||
|
|
||||||
|
private fun executeNormalImpl(config: KeyboardConfig) {
|
||||||
|
val emulationActivity = NativeLibrary.sEmulationActivity.get()
|
||||||
|
data = KeyboardData(SwkbdResult.Cancel.ordinal, "")
|
||||||
|
val fragment = KeyboardDialogFragment.newInstance(config)
|
||||||
|
fragment.show(emulationActivity!!.supportFragmentManager, KeyboardDialogFragment.TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeInlineImpl(config: KeyboardConfig) {
|
||||||
|
val emulationActivity = NativeLibrary.sEmulationActivity.get()
|
||||||
|
|
||||||
|
val overlayView = emulationActivity!!.findViewById<View>(R.id.surface_input_overlay)
|
||||||
|
val im =
|
||||||
|
overlayView.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
im.showSoftInput(overlayView, InputMethodManager.SHOW_FORCED)
|
||||||
|
|
||||||
|
// There isn't a good way to know that the IMM is dismissed, so poll every 500ms to submit inline keyboard result.
|
||||||
|
val handler = Handler(Looper.myLooper()!!)
|
||||||
|
val delayMs = 500
|
||||||
|
handler.postDelayed(object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
val insets = ViewCompat.getRootWindowInsets(overlayView)
|
||||||
|
val isKeyboardVisible = insets!!.isVisible(WindowInsets.Type.ime())
|
||||||
|
if (isKeyboardVisible) {
|
||||||
|
handler.postDelayed(this, delayMs.toLong())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// No longer visible, submit the result.
|
||||||
|
NativeLibrary.SubmitInlineKeyboardInput(KeyEvent.KEYCODE_ENTER)
|
||||||
|
}
|
||||||
|
}, delayMs.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun executeNormal(config: KeyboardConfig): KeyboardData {
|
||||||
|
NativeLibrary.sEmulationActivity.get()!!.runOnUiThread { executeNormalImpl(config) }
|
||||||
|
synchronized(dataLock) {
|
||||||
|
dataLock.wait()
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun executeInline(config: KeyboardConfig) {
|
||||||
|
NativeLibrary.sEmulationActivity.get()!!.runOnUiThread { executeInlineImpl(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corresponds to Service::AM::Applets::SwkbdType
|
||||||
|
enum class SwkbdType {
|
||||||
|
Normal,
|
||||||
|
NumberPad,
|
||||||
|
Qwerty,
|
||||||
|
Unknown3,
|
||||||
|
Latin,
|
||||||
|
SimplifiedChinese,
|
||||||
|
TraditionalChinese,
|
||||||
|
Korean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corresponds to Service::AM::Applets::SwkbdPasswordMode
|
||||||
|
enum class SwkbdPasswordMode {
|
||||||
|
Disabled,
|
||||||
|
Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corresponds to Service::AM::Applets::SwkbdResult
|
||||||
|
enum class SwkbdResult {
|
||||||
|
Ok,
|
||||||
|
Cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
data class KeyboardConfig(
|
||||||
|
var ok_text: String? = null,
|
||||||
|
var header_text: String? = null,
|
||||||
|
var sub_text: String? = null,
|
||||||
|
var guide_text: String? = null,
|
||||||
|
var initial_text: String? = null,
|
||||||
|
var left_optional_symbol_key: Short = 0,
|
||||||
|
var right_optional_symbol_key: Short = 0,
|
||||||
|
var max_text_length: Int = 0,
|
||||||
|
var min_text_length: Int = 0,
|
||||||
|
var initial_cursor_position: Int = 0,
|
||||||
|
var type: Int = 0,
|
||||||
|
var password_mode: Int = 0,
|
||||||
|
var text_draw_type: Int = 0,
|
||||||
|
var key_disable_flags: Int = 0,
|
||||||
|
var use_blur_background: Boolean = false,
|
||||||
|
var enable_backspace_button: Boolean = false,
|
||||||
|
var enable_return_button: Boolean = false,
|
||||||
|
var disable_cancel_button: Boolean = false
|
||||||
|
) : Serializable
|
||||||
|
|
||||||
|
// Corresponds to Frontend::KeyboardData
|
||||||
|
data class KeyboardData(var result: Int, var text: String)
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.applets.keyboard.ui
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.InputFilter
|
||||||
|
import android.text.InputType
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.applets.keyboard.SoftwareKeyboard
|
||||||
|
import org.yuzu.yuzu_emu.applets.keyboard.SoftwareKeyboard.KeyboardConfig
|
||||||
|
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
|
||||||
|
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
|
||||||
|
|
||||||
|
class KeyboardDialogFragment : DialogFragment() {
|
||||||
|
private lateinit var binding: DialogEditTextBinding
|
||||||
|
private lateinit var config: KeyboardConfig
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
binding = DialogEditTextBinding.inflate(layoutInflater)
|
||||||
|
config = requireArguments().serializable(CONFIG)!!
|
||||||
|
|
||||||
|
// Set up the input
|
||||||
|
binding.editText.hint = config.initial_text
|
||||||
|
binding.editText.isSingleLine = !config.enable_return_button
|
||||||
|
binding.editText.filters =
|
||||||
|
arrayOf<InputFilter>(InputFilter.LengthFilter(config.max_text_length))
|
||||||
|
|
||||||
|
// Handle input type
|
||||||
|
var inputType: Int
|
||||||
|
when (config.type) {
|
||||||
|
SoftwareKeyboard.SwkbdType.Normal.ordinal,
|
||||||
|
SoftwareKeyboard.SwkbdType.Qwerty.ordinal,
|
||||||
|
SoftwareKeyboard.SwkbdType.Unknown3.ordinal,
|
||||||
|
SoftwareKeyboard.SwkbdType.Latin.ordinal,
|
||||||
|
SoftwareKeyboard.SwkbdType.SimplifiedChinese.ordinal,
|
||||||
|
SoftwareKeyboard.SwkbdType.TraditionalChinese.ordinal,
|
||||||
|
SoftwareKeyboard.SwkbdType.Korean.ordinal -> {
|
||||||
|
inputType = InputType.TYPE_CLASS_TEXT
|
||||||
|
if (config.password_mode == SoftwareKeyboard.SwkbdPasswordMode.Enabled.ordinal) {
|
||||||
|
inputType = inputType or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SoftwareKeyboard.SwkbdType.NumberPad.ordinal -> {
|
||||||
|
inputType = InputType.TYPE_CLASS_NUMBER
|
||||||
|
if (config.password_mode == SoftwareKeyboard.SwkbdPasswordMode.Enabled.ordinal) {
|
||||||
|
inputType = inputType or InputType.TYPE_NUMBER_VARIATION_PASSWORD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
inputType = InputType.TYPE_CLASS_TEXT
|
||||||
|
if (config.password_mode == SoftwareKeyboard.SwkbdPasswordMode.Enabled.ordinal) {
|
||||||
|
inputType = inputType or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.editText.inputType = inputType
|
||||||
|
|
||||||
|
val headerText =
|
||||||
|
config.header_text!!.ifEmpty { resources.getString(R.string.software_keyboard) }
|
||||||
|
val okText =
|
||||||
|
if (config.header_text!!.isEmpty()) resources.getString(android.R.string.ok) else config.ok_text!!
|
||||||
|
|
||||||
|
return MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setTitle(headerText)
|
||||||
|
.setView(binding.root)
|
||||||
|
.setPositiveButton(okText) { _, _ ->
|
||||||
|
SoftwareKeyboard.data.result = SoftwareKeyboard.SwkbdResult.Ok.ordinal
|
||||||
|
SoftwareKeyboard.data.text = binding.editText.text.toString()
|
||||||
|
}
|
||||||
|
.setNegativeButton(resources.getString(android.R.string.cancel)) { _, _ ->
|
||||||
|
SoftwareKeyboard.data.result = SoftwareKeyboard.SwkbdResult.Cancel.ordinal
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
synchronized(SoftwareKeyboard.dataLock) {
|
||||||
|
SoftwareKeyboard.dataLock.notifyAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "KeyboardDialogFragment"
|
||||||
|
const val CONFIG = "keyboard_config"
|
||||||
|
|
||||||
|
fun newInstance(config: KeyboardConfig?): KeyboardDialogFragment {
|
||||||
|
val frag = KeyboardDialogFragment()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putSerializable(CONFIG, config)
|
||||||
|
frag.arguments = args
|
||||||
|
return frag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -253,19 +253,19 @@ void AndroidKeyboard::SubmitNormalText(const ResultData& data) const {
|
||||||
|
|
||||||
void InitJNI(JNIEnv* env) {
|
void InitJNI(JNIEnv* env) {
|
||||||
s_software_keyboard_class = reinterpret_cast<jclass>(
|
s_software_keyboard_class = reinterpret_cast<jclass>(
|
||||||
env->NewGlobalRef(env->FindClass("org/yuzu/yuzu_emu/applets/SoftwareKeyboard")));
|
env->NewGlobalRef(env->FindClass("org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard")));
|
||||||
s_keyboard_config_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
s_keyboard_config_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
||||||
env->FindClass("org/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardConfig")));
|
env->FindClass("org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard$KeyboardConfig")));
|
||||||
s_keyboard_data_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
s_keyboard_data_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
||||||
env->FindClass("org/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardData")));
|
env->FindClass("org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard$KeyboardData")));
|
||||||
|
|
||||||
s_swkbd_execute_normal = env->GetStaticMethodID(
|
s_swkbd_execute_normal = env->GetStaticMethodID(
|
||||||
s_software_keyboard_class, "ExecuteNormal",
|
s_software_keyboard_class, "executeNormal",
|
||||||
"(Lorg/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardConfig;)Lorg/yuzu/yuzu_emu/"
|
"(Lorg/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard$KeyboardConfig;)Lorg/yuzu/yuzu_emu/"
|
||||||
"applets/SoftwareKeyboard$KeyboardData;");
|
"applets/keyboard/SoftwareKeyboard$KeyboardData;");
|
||||||
s_swkbd_execute_inline =
|
s_swkbd_execute_inline =
|
||||||
env->GetStaticMethodID(s_software_keyboard_class, "ExecuteInline",
|
env->GetStaticMethodID(s_software_keyboard_class, "executeInline",
|
||||||
"(Lorg/yuzu/yuzu_emu/applets/SoftwareKeyboard$KeyboardConfig;)V");
|
"(Lorg/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard$KeyboardConfig;)V");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CleanupJNI(JNIEnv* env) {
|
void CleanupJNI(JNIEnv* env) {
|
||||||
|
|
23
src/android/app/src/main/res/layout/dialog_edit_text.xml
Normal file
23
src/android/app/src/main/res/layout/dialog_edit_text.xml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/edit_text_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="24dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/edit_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="none" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in a new issue