Implement KeyboardClassifier interface in rust
DD: go/project-imposter-android
This CL includes:
- Rust interface setup
Next CL to include:
- Basic categorization into alphabetic and non-alphabetic
- Updating categorization based on key presses
Test: atest --host libinput_rust_test
Test: atest inputflinger_tests
Bug: 263559234
Flag: com.android.input.flags.enable_keyboard_classifier_rust_impl
Change-Id: I52773be992ddd8efaa9546e0af8b0a78515d931c
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 8f44b3a..4123ffc 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -117,6 +117,27 @@
"--allowlist-var=AINPUT_SOURCE_HDMI",
"--allowlist-var=AINPUT_SOURCE_SENSOR",
"--allowlist-var=AINPUT_SOURCE_ROTARY_ENCODER",
+ "--allowlist-var=AINPUT_KEYBOARD_TYPE_NONE",
+ "--allowlist-var=AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC",
+ "--allowlist-var=AINPUT_KEYBOARD_TYPE_ALPHABETIC",
+ "--allowlist-var=AMETA_NONE",
+ "--allowlist-var=AMETA_ALT_ON",
+ "--allowlist-var=AMETA_ALT_LEFT_ON",
+ "--allowlist-var=AMETA_ALT_RIGHT_ON",
+ "--allowlist-var=AMETA_SHIFT_ON",
+ "--allowlist-var=AMETA_SHIFT_LEFT_ON",
+ "--allowlist-var=AMETA_SHIFT_RIGHT_ON",
+ "--allowlist-var=AMETA_SYM_ON",
+ "--allowlist-var=AMETA_FUNCTION_ON",
+ "--allowlist-var=AMETA_CTRL_ON",
+ "--allowlist-var=AMETA_CTRL_LEFT_ON",
+ "--allowlist-var=AMETA_CTRL_RIGHT_ON",
+ "--allowlist-var=AMETA_META_ON",
+ "--allowlist-var=AMETA_META_LEFT_ON",
+ "--allowlist-var=AMETA_META_RIGHT_ON",
+ "--allowlist-var=AMETA_CAPS_LOCK_ON",
+ "--allowlist-var=AMETA_NUM_LOCK_ON",
+ "--allowlist-var=AMETA_SCROLL_LOCK_ON",
],
static_libs: [
@@ -208,6 +229,7 @@
"InputVerifier.cpp",
"Keyboard.cpp",
"KeyCharacterMap.cpp",
+ "KeyboardClassifier.cpp",
"KeyLayoutMap.cpp",
"MotionPredictor.cpp",
"MotionPredictorMetricsManager.cpp",
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index bc67810..9333ab8 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -273,10 +273,7 @@
}
void InputDeviceInfo::setKeyboardType(int32_t keyboardType) {
- static_assert(AINPUT_KEYBOARD_TYPE_NONE < AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
- static_assert(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC < AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- // There can be multiple subdevices with different keyboard types, set it to the highest type
- mKeyboardType = std::max(mKeyboardType, keyboardType);
+ mKeyboardType = keyboardType;
}
void InputDeviceInfo::setKeyboardLayoutInfo(KeyboardLayoutInfo layoutInfo) {
diff --git a/libs/input/KeyboardClassifier.cpp b/libs/input/KeyboardClassifier.cpp
new file mode 100644
index 0000000..0c2c7be
--- /dev/null
+++ b/libs/input/KeyboardClassifier.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "KeyboardClassifier"
+
+#include <android-base/logging.h>
+#include <com_android_input_flags.h>
+#include <ftl/flags.h>
+#include <input/KeyboardClassifier.h>
+
+#include "input_cxx_bridge.rs.h"
+
+namespace input_flags = com::android::input::flags;
+
+using android::input::RustInputDeviceIdentifier;
+
+namespace android {
+
+KeyboardClassifier::KeyboardClassifier() {
+ if (input_flags::enable_keyboard_classifier()) {
+ mRustClassifier = android::input::keyboardClassifier::create();
+ }
+}
+
+KeyboardType KeyboardClassifier::getKeyboardType(DeviceId deviceId) {
+ if (mRustClassifier) {
+ return static_cast<KeyboardType>(
+ android::input::keyboardClassifier::getKeyboardType(**mRustClassifier, deviceId));
+ } else {
+ auto it = mKeyboardTypeMap.find(deviceId);
+ if (it == mKeyboardTypeMap.end()) {
+ return KeyboardType::NONE;
+ }
+ return it->second;
+ }
+}
+
+// Copied from EventHub.h
+const uint32_t DEVICE_CLASS_KEYBOARD = android::os::IInputConstants::DEVICE_CLASS_KEYBOARD;
+const uint32_t DEVICE_CLASS_ALPHAKEY = android::os::IInputConstants::DEVICE_CLASS_ALPHAKEY;
+
+void KeyboardClassifier::notifyKeyboardChanged(DeviceId deviceId,
+ const InputDeviceIdentifier& identifier,
+ uint32_t deviceClasses) {
+ if (mRustClassifier) {
+ RustInputDeviceIdentifier rustIdentifier;
+ rustIdentifier.name = identifier.name;
+ rustIdentifier.location = identifier.location;
+ rustIdentifier.unique_id = identifier.uniqueId;
+ rustIdentifier.bus = identifier.bus;
+ rustIdentifier.vendor = identifier.vendor;
+ rustIdentifier.product = identifier.product;
+ rustIdentifier.version = identifier.version;
+ rustIdentifier.descriptor = identifier.descriptor;
+ android::input::keyboardClassifier::notifyKeyboardChanged(**mRustClassifier, deviceId,
+ rustIdentifier, deviceClasses);
+ } else {
+ bool isKeyboard = (deviceClasses & DEVICE_CLASS_KEYBOARD) != 0;
+ bool hasAlphabeticKey = (deviceClasses & DEVICE_CLASS_ALPHAKEY) != 0;
+ mKeyboardTypeMap.insert_or_assign(deviceId,
+ isKeyboard ? (hasAlphabeticKey
+ ? KeyboardType::ALPHABETIC
+ : KeyboardType::NON_ALPHABETIC)
+ : KeyboardType::NONE);
+ }
+}
+
+void KeyboardClassifier::processKey(DeviceId deviceId, int32_t evdevCode, uint32_t metaState) {
+ if (mRustClassifier &&
+ !android::input::keyboardClassifier::isFinalized(**mRustClassifier, deviceId)) {
+ android::input::keyboardClassifier::processKey(**mRustClassifier, deviceId, evdevCode,
+ metaState);
+ }
+}
+
+} // namespace android
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 90ed2b7..e8746d0 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -234,4 +234,157 @@
* time to adjust to changes in direction.
*/
const int VELOCITY_TRACKER_STRATEGY_LEGACY = 9;
+
+
+ /*
+ * Input device class: Keyboard
+ * The input device is a keyboard or has buttons.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_KEYBOARD = 0x00000001;
+
+ /*
+ * Input device class: Alphakey
+ * The input device is an alpha-numeric keyboard (not just a dial pad).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_ALPHAKEY = 0x00000002;
+
+ /*
+ * Input device class: Touch
+ * The input device is a touchscreen or a touchpad (either single-touch or multi-touch).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_TOUCH = 0x00000004;
+
+ /*
+ * Input device class: Cursor
+ * The input device is a cursor device such as a trackball or mouse.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_CURSOR = 0x00000008;
+
+ /*
+ * Input device class: Multi-touch
+ * The input device is a multi-touch touchscreen or touchpad.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_TOUCH_MT = 0x00000010;
+
+ /*
+ * Input device class: Dpad
+ * The input device is a directional pad (implies keyboard, has DPAD keys).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_DPAD = 0x00000020;
+
+ /*
+ * Input device class: Gamepad
+ * The input device is a gamepad (implies keyboard, has BUTTON keys).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_GAMEPAD = 0x00000040;
+
+ /*
+ * Input device class: Switch
+ * The input device has switches.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_SWITCH = 0x00000080;
+
+ /*
+ * Input device class: Joystick
+ * The input device is a joystick (implies gamepad, has joystick absolute axes).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_JOYSTICK = 0x00000100;
+
+ /*
+ * Input device class: Vibrator
+ * The input device has a vibrator (supports FF_RUMBLE).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_VIBRATOR = 0x00000200;
+
+ /*
+ * Input device class: Mic
+ * The input device has a microphone.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_MIC = 0x00000400;
+
+ /*
+ * Input device class: External Stylus
+ * The input device is an external stylus (has data we want to fuse with touch data).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800;
+
+ /*
+ * Input device class: Rotary Encoder
+ * The input device has a rotary encoder.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_ROTARY_ENCODER = 0x00001000;
+
+ /*
+ * Input device class: Sensor
+ * The input device has a sensor like accelerometer, gyro, etc.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_SENSOR = 0x00002000;
+
+ /*
+ * Input device class: Battery
+ * The input device has a battery.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_BATTERY = 0x00004000;
+
+ /*
+ * Input device class: Light
+ * The input device has sysfs controllable lights.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_LIGHT = 0x00008000;
+
+ /*
+ * Input device class: Touchpad
+ * The input device is a touchpad, requiring an on-screen cursor.
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_TOUCHPAD = 0x00010000;
+
+ /*
+ * Input device class: Virtual
+ * The input device is virtual (not a real device, not part of UI configuration).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_VIRTUAL = 0x20000000;
+
+ /*
+ * Input device class: External
+ * The input device is external (not built-in).
+ *
+ * @hide
+ */
+ const int DEVICE_CLASS_EXTERNAL = 0x40000000;
}
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 560166c..a2192cb 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -150,3 +150,10 @@
description: "Hide touch and pointer indicators if a secure window is present on display"
bug: "325252005"
}
+
+flag {
+ name: "enable_keyboard_classifier"
+ namespace: "input"
+ description: "Keyboard classifier that classifies all keyboards into alphabetic or non-alphabetic"
+ bug: "263559234"
+}
diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs
index d0dbd6f..72b421c 100644
--- a/libs/input/rust/input.rs
+++ b/libs/input/rust/input.rs
@@ -16,22 +16,26 @@
//! Common definitions of the Android Input Framework in rust.
+use crate::ffi::RustInputDeviceIdentifier;
use bitflags::bitflags;
-use inputconstants::aidl::android::os::IInputConstants::INPUT_EVENT_FLAG_CANCELED;
-use inputconstants::aidl::android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
-use inputconstants::aidl::android::os::IInputConstants::INPUT_EVENT_FLAG_TAINTED;
-use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_HOVER_EXIT_PENDING;
-use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
-use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
-use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS;
-use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
-use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+use inputconstants::aidl::android::os::IInputConstants;
use std::fmt;
/// The InputDevice ID.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DeviceId(pub i32);
+/// The InputDevice equivalent for Rust inputflinger
+#[derive(Debug)]
+pub struct InputDevice {
+ /// InputDevice ID
+ pub device_id: DeviceId,
+ /// InputDevice unique identifier
+ pub identifier: RustInputDeviceIdentifier,
+ /// InputDevice classes (equivalent to EventHub InputDeviceClass)
+ pub classes: DeviceClass,
+}
+
#[repr(u32)]
pub enum SourceClass {
None = input_bindgen::AINPUT_SOURCE_CLASS_NONE,
@@ -192,23 +196,23 @@
#[derive(Debug)]
pub struct MotionFlags: u32 {
/// FLAG_WINDOW_IS_OBSCURED
- const WINDOW_IS_OBSCURED = MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED as u32;
+ const WINDOW_IS_OBSCURED = IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED as u32;
/// FLAG_WINDOW_IS_PARTIALLY_OBSCURED
- const WINDOW_IS_PARTIALLY_OBSCURED = MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED as u32;
+ const WINDOW_IS_PARTIALLY_OBSCURED = IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED as u32;
/// FLAG_HOVER_EXIT_PENDING
- const HOVER_EXIT_PENDING = MOTION_EVENT_FLAG_HOVER_EXIT_PENDING as u32;
+ const HOVER_EXIT_PENDING = IInputConstants::MOTION_EVENT_FLAG_HOVER_EXIT_PENDING as u32;
/// FLAG_IS_GENERATED_GESTURE
- const IS_GENERATED_GESTURE = MOTION_EVENT_FLAG_IS_GENERATED_GESTURE as u32;
+ const IS_GENERATED_GESTURE = IInputConstants::MOTION_EVENT_FLAG_IS_GENERATED_GESTURE as u32;
/// FLAG_CANCELED
- const CANCELED = INPUT_EVENT_FLAG_CANCELED as u32;
+ const CANCELED = IInputConstants::INPUT_EVENT_FLAG_CANCELED as u32;
/// FLAG_NO_FOCUS_CHANGE
- const NO_FOCUS_CHANGE = MOTION_EVENT_FLAG_NO_FOCUS_CHANGE as u32;
+ const NO_FOCUS_CHANGE = IInputConstants::MOTION_EVENT_FLAG_NO_FOCUS_CHANGE as u32;
/// FLAG_IS_ACCESSIBILITY_EVENT
- const IS_ACCESSIBILITY_EVENT = INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT as u32;
+ const IS_ACCESSIBILITY_EVENT = IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT as u32;
/// FLAG_TAINTED
- const TAINTED = INPUT_EVENT_FLAG_TAINTED as u32;
+ const TAINTED = IInputConstants::INPUT_EVENT_FLAG_TAINTED as u32;
/// FLAG_TARGET_ACCESSIBILITY_FOCUS
- const TARGET_ACCESSIBILITY_FOCUS = MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS as u32;
+ const TARGET_ACCESSIBILITY_FOCUS = IInputConstants::MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS as u32;
}
}
@@ -220,6 +224,107 @@
}
}
+bitflags! {
+ /// Device class of the input device. These are duplicated from Eventhub.h
+ /// We need to make sure the two version remain in sync when adding new classes.
+ #[derive(Debug, PartialEq)]
+ pub struct DeviceClass: u32 {
+ /// The input device is a keyboard or has buttons
+ const Keyboard = IInputConstants::DEVICE_CLASS_KEYBOARD as u32;
+ /// The input device is an alpha-numeric keyboard (not just a dial pad)
+ const AlphabeticKey = IInputConstants::DEVICE_CLASS_ALPHAKEY as u32;
+ /// The input device is a touchscreen or a touchpad (either single-touch or multi-touch)
+ const Touch = IInputConstants::DEVICE_CLASS_TOUCH as u32;
+ /// The input device is a cursor device such as a trackball or mouse.
+ const Cursor = IInputConstants::DEVICE_CLASS_CURSOR as u32;
+ /// The input device is a multi-touch touchscreen or touchpad.
+ const MultiTouch = IInputConstants::DEVICE_CLASS_TOUCH_MT as u32;
+ /// The input device is a directional pad (implies keyboard, has DPAD keys).
+ const Dpad = IInputConstants::DEVICE_CLASS_DPAD as u32;
+ /// The input device is a gamepad (implies keyboard, has BUTTON keys).
+ const Gamepad = IInputConstants::DEVICE_CLASS_GAMEPAD as u32;
+ /// The input device has switches.
+ const Switch = IInputConstants::DEVICE_CLASS_SWITCH as u32;
+ /// The input device is a joystick (implies gamepad, has joystick absolute axes).
+ const Joystick = IInputConstants::DEVICE_CLASS_JOYSTICK as u32;
+ /// The input device has a vibrator (supports FF_RUMBLE).
+ const Vibrator = IInputConstants::DEVICE_CLASS_VIBRATOR as u32;
+ /// The input device has a microphone.
+ const Mic = IInputConstants::DEVICE_CLASS_MIC as u32;
+ /// The input device is an external stylus (has data we want to fuse with touch data).
+ const ExternalStylus = IInputConstants::DEVICE_CLASS_EXTERNAL_STYLUS as u32;
+ /// The input device has a rotary encoder
+ const RotaryEncoder = IInputConstants::DEVICE_CLASS_ROTARY_ENCODER as u32;
+ /// The input device has a sensor like accelerometer, gyro, etc
+ const Sensor = IInputConstants::DEVICE_CLASS_SENSOR as u32;
+ /// The input device has a battery
+ const Battery = IInputConstants::DEVICE_CLASS_BATTERY as u32;
+ /// The input device has sysfs controllable lights
+ const Light = IInputConstants::DEVICE_CLASS_LIGHT as u32;
+ /// The input device is a touchpad, requiring an on-screen cursor.
+ const Touchpad = IInputConstants::DEVICE_CLASS_TOUCHPAD as u32;
+ /// The input device is virtual (not a real device, not part of UI configuration).
+ const Virtual = IInputConstants::DEVICE_CLASS_VIRTUAL as u32;
+ /// The input device is external (not built-in).
+ const External = IInputConstants::DEVICE_CLASS_EXTERNAL as u32;
+ }
+}
+
+bitflags! {
+ /// Modifier state flags
+ #[derive(Debug, PartialEq)]
+ pub struct ModifierState: u32 {
+ /// No meta keys are pressed
+ const None = input_bindgen::AMETA_NONE;
+ /// This mask is used to check whether one of the ALT meta keys is pressed
+ const AltOn = input_bindgen::AMETA_ALT_ON;
+ /// This mask is used to check whether the left ALT meta key is pressed
+ const AltLeftOn = input_bindgen::AMETA_ALT_LEFT_ON;
+ /// This mask is used to check whether the right ALT meta key is pressed
+ const AltRightOn = input_bindgen::AMETA_ALT_RIGHT_ON;
+ /// This mask is used to check whether one of the SHIFT meta keys is pressed
+ const ShiftOn = input_bindgen::AMETA_SHIFT_ON;
+ /// This mask is used to check whether the left SHIFT meta key is pressed
+ const ShiftLeftOn = input_bindgen::AMETA_SHIFT_LEFT_ON;
+ /// This mask is used to check whether the right SHIFT meta key is pressed
+ const ShiftRightOn = input_bindgen::AMETA_SHIFT_RIGHT_ON;
+ /// This mask is used to check whether the SYM meta key is pressed
+ const SymOn = input_bindgen::AMETA_SYM_ON;
+ /// This mask is used to check whether the FUNCTION meta key is pressed
+ const FunctionOn = input_bindgen::AMETA_FUNCTION_ON;
+ /// This mask is used to check whether one of the CTRL meta keys is pressed
+ const CtrlOn = input_bindgen::AMETA_CTRL_ON;
+ /// This mask is used to check whether the left CTRL meta key is pressed
+ const CtrlLeftOn = input_bindgen::AMETA_CTRL_LEFT_ON;
+ /// This mask is used to check whether the right CTRL meta key is pressed
+ const CtrlRightOn = input_bindgen::AMETA_CTRL_RIGHT_ON;
+ /// This mask is used to check whether one of the META meta keys is pressed
+ const MetaOn = input_bindgen::AMETA_META_ON;
+ /// This mask is used to check whether the left META meta key is pressed
+ const MetaLeftOn = input_bindgen::AMETA_META_LEFT_ON;
+ /// This mask is used to check whether the right META meta key is pressed
+ const MetaRightOn = input_bindgen::AMETA_META_RIGHT_ON;
+ /// This mask is used to check whether the CAPS LOCK meta key is on
+ const CapsLockOn = input_bindgen::AMETA_CAPS_LOCK_ON;
+ /// This mask is used to check whether the NUM LOCK meta key is on
+ const NumLockOn = input_bindgen::AMETA_NUM_LOCK_ON;
+ /// This mask is used to check whether the SCROLL LOCK meta key is on
+ const ScrollLockOn = input_bindgen::AMETA_SCROLL_LOCK_ON;
+ }
+}
+
+/// A rust enum representation of a Keyboard type.
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum KeyboardType {
+ /// KEYBOARD_TYPE_NONE
+ None = input_bindgen::AINPUT_KEYBOARD_TYPE_NONE,
+ /// KEYBOARD_TYPE_NON_ALPHABETIC
+ NonAlphabetic = input_bindgen::AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC,
+ /// KEYBOARD_TYPE_ALPHABETIC
+ Alphabetic = input_bindgen::AINPUT_KEYBOARD_TYPE_ALPHABETIC,
+}
+
#[cfg(test)]
mod tests {
use crate::input::SourceClass;
diff --git a/libs/input/rust/keyboard_classifier.rs b/libs/input/rust/keyboard_classifier.rs
new file mode 100644
index 0000000..bd3a51c
--- /dev/null
+++ b/libs/input/rust/keyboard_classifier.rs
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Contains the KeyboardClassifier, that tries to identify whether an Input device is an
+//! alphabetic or non-alphabetic keyboard. It also tracks the KeyEvents produced by the device
+//! in order to verify/change the inferred keyboard type.
+
+use crate::input::{DeviceId, InputDevice, KeyboardType};
+use crate::ModifierState;
+
+/// The KeyboardClassifier is used to classify a keyboard device into non-keyboard, alphabetic
+/// keyboard or non-alphabetic keyboard
+#[derive(Default)]
+pub struct KeyboardClassifier {}
+
+impl KeyboardClassifier {
+ /// Create a new KeyboardClassifier
+ pub fn new() -> Self {
+ Default::default()
+ }
+
+ /// Adds keyboard to KeyboardClassifier
+ pub fn notify_keyboard_changed(&mut self, _device: InputDevice) {
+ // TODO(b/263559234): Implement method
+ }
+
+ /// Get keyboard type for a tracked keyboard in KeyboardClassifier
+ pub fn get_keyboard_type(&self, _device_id: DeviceId) -> KeyboardType {
+ // TODO(b/263559234): Implement method
+ KeyboardType::None
+ }
+
+ /// Tells if keyboard type classification is finalized. Once finalized the classification can't
+ /// change until device is reconnected again.
+ pub fn is_finalized(&self, _device_id: DeviceId) -> bool {
+ // TODO(b/263559234): Implement method
+ false
+ }
+
+ /// Process a key event and change keyboard type if required.
+ pub fn process_key(
+ &mut self,
+ _device_id: DeviceId,
+ _evdev_code: i32,
+ _modifier_state: ModifierState,
+ ) {
+ // TODO(b/263559234): Implement method
+ }
+}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index fb3f520..5010475 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -18,9 +18,13 @@
mod input;
mod input_verifier;
+mod keyboard_classifier;
-pub use input::{DeviceId, MotionAction, MotionFlags, Source};
+pub use input::{
+ DeviceClass, DeviceId, InputDevice, ModifierState, MotionAction, MotionFlags, Source,
+};
pub use input_verifier::InputVerifier;
+pub use keyboard_classifier::KeyboardClassifier;
#[cxx::bridge(namespace = "android::input")]
#[allow(unsafe_op_in_unsafe_fn)]
@@ -47,7 +51,8 @@
/// }
/// ```
type InputVerifier;
- fn create(name: String) -> Box<InputVerifier>;
+ #[cxx_name = create]
+ fn create_input_verifier(name: String) -> Box<InputVerifier>;
fn process_movement(
verifier: &mut InputVerifier,
device_id: i32,
@@ -59,15 +64,53 @@
fn reset_device(verifier: &mut InputVerifier, device_id: i32);
}
+ #[namespace = "android::input::keyboardClassifier"]
+ extern "Rust" {
+ /// Used to classify a keyboard into alphabetic and non-alphabetic
+ type KeyboardClassifier;
+ #[cxx_name = create]
+ fn create_keyboard_classifier() -> Box<KeyboardClassifier>;
+ #[cxx_name = notifyKeyboardChanged]
+ fn notify_keyboard_changed(
+ classifier: &mut KeyboardClassifier,
+ device_id: i32,
+ identifier: RustInputDeviceIdentifier,
+ device_classes: u32,
+ );
+ #[cxx_name = getKeyboardType]
+ fn get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32;
+ #[cxx_name = isFinalized]
+ fn is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool;
+ #[cxx_name = processKey]
+ fn process_key(
+ classifier: &mut KeyboardClassifier,
+ device_id: i32,
+ evdev_code: i32,
+ modifier_state: u32,
+ );
+ }
+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct RustPointerProperties {
pub id: i32,
}
+
+ #[derive(Debug)]
+ pub struct RustInputDeviceIdentifier {
+ pub name: String,
+ pub location: String,
+ pub unique_id: String,
+ pub bus: u16,
+ pub vendor: u16,
+ pub product: u16,
+ pub version: u16,
+ pub descriptor: String,
+ }
}
-use crate::ffi::RustPointerProperties;
+use crate::ffi::{RustInputDeviceIdentifier, RustPointerProperties};
-fn create(name: String) -> Box<InputVerifier> {
+fn create_input_verifier(name: String) -> Box<InputVerifier> {
Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents")))
}
@@ -103,3 +146,53 @@
fn reset_device(verifier: &mut InputVerifier, device_id: i32) {
verifier.reset_device(DeviceId(device_id));
}
+
+fn create_keyboard_classifier() -> Box<KeyboardClassifier> {
+ Box::new(KeyboardClassifier::new())
+}
+
+fn notify_keyboard_changed(
+ classifier: &mut KeyboardClassifier,
+ device_id: i32,
+ identifier: RustInputDeviceIdentifier,
+ device_classes: u32,
+) {
+ let classes = DeviceClass::from_bits(device_classes);
+ if classes.is_none() {
+ panic!(
+ "The conversion of device class 0x{:08x} failed, please check if some device classes
+ have not been added to DeviceClass.",
+ device_classes
+ );
+ }
+ classifier.notify_keyboard_changed(InputDevice {
+ device_id: DeviceId(device_id),
+ identifier,
+ classes: classes.unwrap(),
+ });
+}
+
+fn get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32 {
+ classifier.get_keyboard_type(DeviceId(device_id)) as u32
+}
+
+fn is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool {
+ classifier.is_finalized(DeviceId(device_id))
+}
+
+fn process_key(
+ classifier: &mut KeyboardClassifier,
+ device_id: i32,
+ evdev_code: i32,
+ meta_state: u32,
+) {
+ let modifier_state = ModifierState::from_bits(meta_state);
+ if modifier_state.is_none() {
+ panic!(
+ "The conversion of meta state 0x{:08x} failed, please check if some meta state
+ have not been added to ModifierState.",
+ meta_state
+ );
+ }
+ classifier.process_key(DeviceId(device_id), evdev_code, modifier_state.unwrap());
+}