Compare commits

..

2 commits

Author SHA1 Message Date
lizzie 417ed904f0
[dynarmic] fix MWAIT push/pop not being handled properly on xbyak (#3875)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
push %edx is not what i wanted, nor what anybody wants, xbyak silently accepting this before was not intended
now that xbyak is updated this is an issue

the issue was simply:
a) ptr being overwritten (if it happened to be EDX/EBX/EAX) due to changed WAITPKG logic (oops)
b) xbyak not reporting wrong r32 pop/push on older versions thus missing it and now it throws an exception

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3875
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-04-23 05:06:33 +02:00
wildcard 838cc926f6
keyboard fixes (#3865)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3865
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-04-23 03:43:54 +02:00
4 changed files with 100 additions and 11 deletions

View file

@ -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.

View file

@ -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

View file

@ -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()));

View file

@ -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) {