mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-23 07:44:18 +00:00
Compare commits
2 commits
860acb4faf
...
417ed904f0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
417ed904f0 | ||
|
|
838cc926f6 |
|
|
@ -1,3 +1,7 @@
|
|||
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -33,8 +37,10 @@ object SoftwareKeyboard {
|
|||
val emulationActivity = NativeLibrary.sEmulationActivity.get()
|
||||
|
||||
val overlayView = emulationActivity!!.findViewById<View>(R.id.surface_input_overlay)
|
||||
overlayView.requestFocus()
|
||||
val im =
|
||||
overlayView.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
im.restartInput(overlayView)
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -17,16 +17,23 @@ import android.graphics.drawable.VectorDrawable
|
|||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.text.InputType
|
||||
import android.util.AttributeSet
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.View.OnTouchListener
|
||||
import android.view.WindowInsets
|
||||
import android.view.inputmethod.BaseInputConnection
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputConnection
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.window.layout.WindowMetricsCalculator
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
|
||||
|
|
@ -49,6 +56,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
private val overlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet()
|
||||
private val overlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet()
|
||||
private val overlayJoysticks: MutableSet<InputOverlayDrawableJoystick> = HashSet()
|
||||
private val imeEditable = Editable.Factory.getInstance().newEditable("")
|
||||
|
||||
private var inEditMode = false
|
||||
private var gamelessMode = false
|
||||
|
|
@ -75,6 +83,63 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
// External listener for EmulationFragment joypad overlay auto-hide
|
||||
var touchEventListener: ((MotionEvent) -> Unit)? = null
|
||||
|
||||
override fun onCheckIsTextEditor(): Boolean = true
|
||||
|
||||
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
|
||||
imeEditable.clear()
|
||||
outAttrs.inputType =
|
||||
InputType.TYPE_CLASS_TEXT or
|
||||
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or
|
||||
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI or EditorInfo.IME_ACTION_DONE
|
||||
outAttrs.initialSelStart = 0
|
||||
outAttrs.initialSelEnd = 0
|
||||
|
||||
return object : BaseInputConnection(this, true) {
|
||||
override fun getEditable(): Editable = imeEditable
|
||||
|
||||
override fun commitText(text: CharSequence?, newCursorPosition: Int): Boolean {
|
||||
if (!text.isNullOrEmpty()) {
|
||||
forwardCommittedText(text)
|
||||
}
|
||||
return super.commitText(text, newCursorPosition)
|
||||
}
|
||||
|
||||
override fun deleteSurroundingText(beforeLength: Int, afterLength: Int): Boolean {
|
||||
repeat(beforeLength.coerceAtLeast(0)) {
|
||||
NativeLibrary.submitInlineKeyboardInput(KeyEvent.KEYCODE_DEL)
|
||||
}
|
||||
return super.deleteSurroundingText(beforeLength, afterLength)
|
||||
}
|
||||
|
||||
override fun sendKeyEvent(event: KeyEvent): Boolean {
|
||||
if (event.action != KeyEvent.ACTION_DOWN) {
|
||||
return true
|
||||
}
|
||||
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_BACK,
|
||||
KeyEvent.KEYCODE_DEL,
|
||||
KeyEvent.KEYCODE_ENTER -> {
|
||||
NativeLibrary.submitInlineKeyboardInput(event.keyCode)
|
||||
}
|
||||
else -> {
|
||||
val textChar = event.unicodeChar
|
||||
if (textChar != 0) {
|
||||
NativeLibrary.submitInlineKeyboardText(textChar.toChar().toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun performEditorAction(actionCode: Int): Boolean {
|
||||
NativeLibrary.submitInlineKeyboardInput(KeyEvent.KEYCODE_ENTER)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.onLayout(changed, left, top, right, bottom)
|
||||
|
||||
|
|
@ -119,6 +184,25 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
}
|
||||
}
|
||||
|
||||
private fun forwardCommittedText(text: CharSequence) {
|
||||
val builder = StringBuilder()
|
||||
text.forEach { character ->
|
||||
when (character) {
|
||||
'\n' -> {
|
||||
if (builder.isNotEmpty()) {
|
||||
NativeLibrary.submitInlineKeyboardText(builder.toString())
|
||||
builder.clear()
|
||||
}
|
||||
NativeLibrary.submitInlineKeyboardInput(KeyEvent.KEYCODE_ENTER)
|
||||
}
|
||||
else -> builder.append(character)
|
||||
}
|
||||
}
|
||||
if (builder.isNotEmpty()) {
|
||||
NativeLibrary.submitInlineKeyboardText(builder.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawGrid(canvas: Canvas) {
|
||||
val gridSize = IntSetting.OVERLAY_GRID_SIZE.getInt()
|
||||
val width = canvas.width
|
||||
|
|
|
|||
|
|
@ -243,6 +243,9 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
|
|||
static_cast<s32>(m_current_text.size()));
|
||||
break;
|
||||
case KEYCODE_DEL:
|
||||
if (m_current_text.empty()) {
|
||||
return;
|
||||
}
|
||||
m_current_text.pop_back();
|
||||
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
|
||||
static_cast<int>(m_current_text.size()));
|
||||
|
|
|
|||
|
|
@ -23,16 +23,14 @@ static const auto default_cg_mode = nullptr; //Allow RWE
|
|||
namespace Dynarmic {
|
||||
|
||||
void EmitSpinLockLock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp, bool waitpkg) {
|
||||
// TODO: this is because we lack regalloc - so better to be safe :(
|
||||
if (waitpkg) {
|
||||
code.push(Xbyak::util::eax);
|
||||
code.push(Xbyak::util::ebx);
|
||||
code.push(Xbyak::util::edx);
|
||||
}
|
||||
Xbyak::Label start, loop;
|
||||
code.jmp(start, code.T_NEAR);
|
||||
code.L(loop);
|
||||
if (waitpkg) {
|
||||
// TODO: this is because we lack regalloc - so better to be safe :(
|
||||
code.push(Xbyak::util::rax);
|
||||
code.push(Xbyak::util::rbx);
|
||||
code.push(Xbyak::util::rdx);
|
||||
// TODO: This clobbers EAX and EDX did we tell the regalloc?
|
||||
// ARM ptr for address-monitoring
|
||||
code.umonitor(ptr);
|
||||
|
|
@ -49,6 +47,9 @@ void EmitSpinLockLock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32
|
|||
code.umwait(Xbyak::util::ebx);
|
||||
// CF == 1 if we hit the OS-timeout in IA32_UMWAIT_CONTROL without a write
|
||||
// CF == 0 if we exited the wait for any other reason
|
||||
code.pop(Xbyak::util::rdx);
|
||||
code.pop(Xbyak::util::rbx);
|
||||
code.pop(Xbyak::util::rax);
|
||||
} else {
|
||||
code.pause();
|
||||
}
|
||||
|
|
@ -57,11 +58,6 @@ void EmitSpinLockLock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32
|
|||
/*code.lock();*/ code.xchg(code.dword[ptr], tmp);
|
||||
code.test(tmp, tmp);
|
||||
code.jnz(loop, code.T_NEAR);
|
||||
if (waitpkg) {
|
||||
code.pop(Xbyak::util::edx);
|
||||
code.pop(Xbyak::util::ebx);
|
||||
code.pop(Xbyak::util::eax);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue