Populate controller list on android (#920)
* list controllers in UI for android * more * more
This commit is contained in:
parent
11a49fd687
commit
5850c514f2
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2266,6 +2266,7 @@ dependencies = [
|
||||
"encoding_rs",
|
||||
"fatfs",
|
||||
"futures",
|
||||
"jni 0.22.4",
|
||||
"mimalloc",
|
||||
"postcard",
|
||||
"rand 0.10.1",
|
||||
|
||||
@ -46,6 +46,7 @@ dirs = "6.0"
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
slint = { version = "1.16", default-features = false, features = ["compat-1-2", "std", "backend-android-activity-06", "accessibility"], optional = true }
|
||||
jni = "0.22"
|
||||
|
||||
[build-dependencies]
|
||||
winresource = "0.1"
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod android_input;
|
||||
pub mod audio;
|
||||
#[cfg(feature = "gui")]
|
||||
pub mod cheats;
|
||||
|
||||
106
src/ui/android_input.rs
Normal file
106
src/ui/android_input.rs
Normal file
@ -0,0 +1,106 @@
|
||||
use jni::{Env, JavaVM, bind_java_type};
|
||||
|
||||
bind_java_type! {
|
||||
pub AndroidInputDevice => "android.view.InputDevice",
|
||||
fields {
|
||||
#[allow(non_snake_case)]
|
||||
static SOURCE_JOYSTICK: jint,
|
||||
#[allow(non_snake_case)]
|
||||
static SOURCE_GAMEPAD: jint,
|
||||
},
|
||||
methods {
|
||||
static fn get_device_ids() -> jint[],
|
||||
static fn get_device(device_id: jint) -> AndroidInputDevice,
|
||||
fn supports_source(source: jint) -> jboolean,
|
||||
fn is_virtual() -> jboolean,
|
||||
fn is_external() -> jboolean,
|
||||
fn get_vendor_id() -> jint,
|
||||
fn get_product_id() -> jint,
|
||||
fn get_name() -> JString,
|
||||
fn get_descriptor() -> JString,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ControllerInfo {
|
||||
pub name: String,
|
||||
/// Stable ID from [`InputDevice.getDescriptor`](https://developer.android.com/reference/android/view/InputDevice#getDescriptor()).
|
||||
pub descriptor: String,
|
||||
}
|
||||
|
||||
/// Lists connected gamepads and joysticks using the Android framework.
|
||||
pub fn list_controllers() -> Vec<ControllerInfo> {
|
||||
let Some(app) = crate::ui::ANDROID_APP.get() else {
|
||||
eprintln!("Android app not initialized; cannot list controllers");
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
let vm = unsafe { JavaVM::from_raw(app.vm_as_ptr().cast()) };
|
||||
|
||||
match vm.attach_current_thread(list_controllers_on_jvm) {
|
||||
Ok(controllers) => controllers,
|
||||
Err(err) => {
|
||||
eprintln!("JNI error while listing controllers: {err:?}");
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn list_controllers_on_jvm(env: &mut Env<'_>) -> jni::errors::Result<Vec<ControllerInfo>> {
|
||||
let source_gamepad = AndroidInputDevice::SOURCE_GAMEPAD(env)?;
|
||||
let source_joystick = AndroidInputDevice::SOURCE_JOYSTICK(env)?;
|
||||
|
||||
let device_ids = AndroidInputDevice::get_device_ids(env)?;
|
||||
let count = device_ids.len(env)?;
|
||||
let mut ids = vec![0i32; count];
|
||||
if count > 0 {
|
||||
device_ids.get_region(env, 0, &mut ids)?;
|
||||
}
|
||||
|
||||
let mut controllers = Vec::new();
|
||||
for device_id in ids {
|
||||
let device = AndroidInputDevice::get_device(env, device_id)?;
|
||||
if device.is_null() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if device.is_virtual(env)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !device.is_external(env)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !device.supports_source(env, source_gamepad & source_joystick)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
if device.get_vendor_id(env)? == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if device.get_product_id(env)? == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = if let Ok(name) = device.get_name(env)
|
||||
&& let Ok(name) = name.try_to_string(env)
|
||||
{
|
||||
name
|
||||
} else {
|
||||
"Unknown controller".to_string()
|
||||
};
|
||||
let descriptor = if let Ok(descriptor) = device.get_descriptor(env)
|
||||
&& let Ok(descriptor) = descriptor.try_to_string(env)
|
||||
{
|
||||
descriptor
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
controllers.push(ControllerInfo { name, descriptor });
|
||||
}
|
||||
|
||||
Ok(controllers)
|
||||
}
|
||||
@ -362,7 +362,12 @@ pub fn get_controller_names() -> Vec<String> {
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn get_controller_names() -> Vec<String> {
|
||||
vec!["None".into()]
|
||||
let mut controllers: Vec<String> = ui::android_input::list_controllers()
|
||||
.into_iter()
|
||||
.map(|c| c.name)
|
||||
.collect();
|
||||
controllers.insert(0, "None".into());
|
||||
controllers
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
@ -386,7 +391,12 @@ pub fn get_controller_paths() -> Vec<String> {
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg(feature = "gui")]
|
||||
pub fn get_controller_paths() -> Vec<String> {
|
||||
vec![String::new()]
|
||||
let mut controller_paths: Vec<String> = ui::android_input::list_controllers()
|
||||
.into_iter()
|
||||
.map(|c| c.descriptor)
|
||||
.collect();
|
||||
controller_paths.insert(0, String::new());
|
||||
controller_paths
|
||||
}
|
||||
|
||||
fn handle_joystick_events(ui: &mut ui::Ui) {
|
||||
|
||||
Reference in New Issue
Block a user