#1,#3,#4+#5 keyboards: Binocular Compose, cursor watchdog 3s, SetText + VmNoopIme + sendText
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
package pw.binom.rayneovm.glasses
|
||||
|
||||
import android.inputmethodservice.InputMethodService
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
|
||||
/**
|
||||
* Пустой IME — глушилка системного IME гостя на нашем VirtualDisplay.
|
||||
*
|
||||
* Когда это дефолтный IME очков — гость (Zona, ...) не показывает свою клавиатуру поверх
|
||||
* нашего приложения: InputMethodService.showInputRequestedAndUpdated → false (нет UI).
|
||||
*
|
||||
* Активируется через Shizuku/binder: `settings put secure default_input_method
|
||||
* pw.binom.rayneovm.glasses/.VmNoopImeService`. Возврат к штатному IME не предусмотрен.
|
||||
*/
|
||||
class VmNoopImeService : InputMethodService() {
|
||||
|
||||
override fun onCreateInputView(): View? {
|
||||
Log.i(TAG, "onCreateInputView: возвращаю null UI")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartInputView(info: EditorInfo?, restarting: Boolean) {
|
||||
Log.i(TAG, "onStartInputView: info=$info restarting=$restarting")
|
||||
// UI не показываем (onCreateInputView == null). Фокус отдаём гостю, как обычно —
|
||||
// его кастомные EditText-ы получают inputType как обычно.
|
||||
}
|
||||
|
||||
override fun onFinishInputView(finishedInput: Boolean) {}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "VmNoopIme"
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import pw.binom.rayneovm.shared.LaunchAppCommand
|
||||
import pw.binom.rayneovm.shared.Ping
|
||||
import pw.binom.rayneovm.shared.Pong
|
||||
import pw.binom.rayneovm.shared.SetAudioMode
|
||||
import pw.binom.rayneovm.shared.SetText
|
||||
import pw.binom.rayneovm.shared.Shutdown
|
||||
import pw.binom.rayneovm.shared.TouchEvent
|
||||
import pw.binom.rayneovm.shared.VmMessage
|
||||
@@ -220,6 +221,11 @@ class VmService : LifecycleService() {
|
||||
Log.i(TAG, "ScreenControl: sleep=${msg.sleep}")
|
||||
controller.setScreen(msg.sleep)
|
||||
}
|
||||
is SetText -> {
|
||||
Log.i(TAG, "SetText: displayId=${msg.displayId} len=${msg.text.length}")
|
||||
val ok = controller.injectText(msg.displayId, msg.text)
|
||||
Log.i(TAG, "SetText -> $ok")
|
||||
}
|
||||
is Shutdown -> {
|
||||
Log.i(TAG, "Shutdown")
|
||||
controller.stopGuest()
|
||||
|
||||
+24
@@ -295,6 +295,30 @@ class VmGlassesController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Инжектит [text] в активное текстовое поле гостя на [displayId] (через InputConnection.commitText).
|
||||
*
|
||||
* Если фокуса в текстовом поле нет — возвращает false (тогда на телефоне остаётся
|
||||
* keyCodeForChar-фолбэк). Биндер берётся у «стража» (он поднят пока живёт VmService), иначе —
|
||||
* у активного гостевого дисплея.
|
||||
*/
|
||||
fun injectText(displayId: Int, text: String): Boolean {
|
||||
val binder = guardBinder ?: activeSource?.shizukuBinder
|
||||
if (binder == null) {
|
||||
Log.w(TAG, "injectText: нет Shizuku-биндера")
|
||||
return false
|
||||
}
|
||||
if (text.isEmpty()) return true
|
||||
return try {
|
||||
val ok = ShizukuVdBinder.injectText(binder, displayId, text)
|
||||
if (!ok) Log.w(TAG, "injectText: binder вернул false")
|
||||
ok
|
||||
} catch (t: Throwable) {
|
||||
Log.w(TAG, "injectText: binder transact упал", t)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/** Клавиатурное/медиа-событие гостю на его VirtualDisplay (Back, Play, Pause, ...). */
|
||||
fun sendKey(keyCode: Int, action: Int) {
|
||||
val src = activeSource ?: return
|
||||
|
||||
Reference in New Issue
Block a user