feat: support android keyboard input

This commit is contained in:
mcfans 2023-10-17 22:12:52 +08:00
parent cf97d090f3
commit bbc241748b
6 changed files with 57 additions and 5 deletions

View File

@ -10,8 +10,10 @@ import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.GestureDescription import android.accessibilityservice.GestureDescription
import android.graphics.Path import android.graphics.Path
import android.os.Build import android.os.Build
import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import java.util.* import java.util.*
import kotlin.math.abs import kotlin.math.abs
@ -252,6 +254,18 @@ class InputService : AccessibilityService() {
} }
} }
@RequiresApi(Build.VERSION_CODES.N)
fun onTextInput(str: String) {
findFocus(AccessibilityNodeInfo.FOCUS_INPUT)?.let {
val arguments = Bundle()
arguments.putCharSequence(
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
str
)
it.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)
}
}
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
ctx = this ctx = this

View File

@ -94,6 +94,12 @@ class MainService : Service() {
} }
} }
@Keep
@RequiresApi(Build.VERSION_CODES.N)
fun rustInputString(input: String) {
InputService.ctx?.onTextInput(input)
}
@Keep @Keep
fun rustGetByName(name: String): String { fun rustGetByName(name: String): String {
return when (name) { return when (name) {

View File

@ -364,6 +364,10 @@ class _RemotePageState extends State<RemotePage> {
? [] ? []
: gFFI.ffiModel.isPeerAndroid : gFFI.ffiModel.isPeerAndroid
? [ ? [
IconButton(
color: Colors.white,
icon: Icon(Icons.keyboard),
onPressed: openKeyboard),
IconButton( IconButton(
color: Colors.white, color: Colors.white,
icon: const Icon(Icons.build), icon: const Icon(Icons.build),

View File

@ -173,6 +173,25 @@ pub fn call_main_service_pointer_input(kind: &str, mask: i32, x: i32, y: i32) ->
} }
} }
pub fn call_main_service_input_string(str: &str) -> JniResult<()> {
if let (Some(jvm), Some(ctx)) = (
JVM.read().unwrap().as_ref(),
MAIN_SERVICE_CTX.read().unwrap().as_ref(),
) {
let mut env = jvm.attach_current_thread_as_daemon()?;
let input_string = env.new_string(str)?;
env.call_method(
ctx,
"rustInputString",
"(Ljava/lang/String;)V",
&[JValue::Object(&JObject::from(input_string))],
)?;
return Ok(());
} else {
return Err(JniError::ThrowFailed(-1));
}
}
pub fn call_main_service_get_by_name(name: &str) -> JniResult<String> { pub fn call_main_service_get_by_name(name: &str) -> JniResult<String> {
if let (Some(jvm), Some(ctx)) = ( if let (Some(jvm), Some(ctx)) = (
JVM.read().unwrap().as_ref(), JVM.read().unwrap().as_ref(),

View File

@ -41,7 +41,7 @@ use hbb_common::{
tokio_util::codec::{BytesCodec, Framed}, tokio_util::codec::{BytesCodec, Framed},
}; };
#[cfg(any(target_os = "android", target_os = "ios"))] #[cfg(any(target_os = "android", target_os = "ios"))]
use scrap::android::call_main_service_pointer_input; use scrap::android::{call_main_service_pointer_input, call_main_service_input_string};
use serde_json::{json, value::Value}; use serde_json::{json, value::Value};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
@ -1722,8 +1722,17 @@ impl Connection {
} }
self.update_auto_disconnect_timer(); self.update_auto_disconnect_timer();
} }
#[cfg(any(target_os = "android", target_os = "ios"))] #[cfg(any(target_os = "ios"))]
Some(message::Union::KeyEvent(..)) => {} Some(message::Union::KeyEvent(..)) => {}
#[cfg(any(target_os = "android"))]
Some(message::Union::KeyEvent(me)) => {
// We can only use seq of key event, android device doesn't support abritrary key stroke.
let seq = me.seq();
let result = call_main_service_input_string(seq);
if let Err(e) = result {
log::debug!("call_main_service_input_string fail:{}", e);
}
}
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
Some(message::Union::KeyEvent(me)) => { Some(message::Union::KeyEvent(me)) => {
if self.peer_keyboard_enabled() { if self.peer_keyboard_enabled() {