xref: /aosp_15_r20/frameworks/native/libs/input/rust/lib.rs (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2023 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker //! The rust component of libinput.
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker mod data_store;
20*38e8c45fSAndroid Build Coastguard Worker mod input;
21*38e8c45fSAndroid Build Coastguard Worker mod input_verifier;
22*38e8c45fSAndroid Build Coastguard Worker mod keyboard_classification_config;
23*38e8c45fSAndroid Build Coastguard Worker mod keyboard_classifier;
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker pub use data_store::{DataStore, DefaultFileReaderWriter};
26*38e8c45fSAndroid Build Coastguard Worker pub use input::{
27*38e8c45fSAndroid Build Coastguard Worker     DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionFlags,
28*38e8c45fSAndroid Build Coastguard Worker     Source,
29*38e8c45fSAndroid Build Coastguard Worker };
30*38e8c45fSAndroid Build Coastguard Worker pub use input_verifier::InputVerifier;
31*38e8c45fSAndroid Build Coastguard Worker pub use keyboard_classifier::KeyboardClassifier;
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker #[cxx::bridge(namespace = "android::input")]
34*38e8c45fSAndroid Build Coastguard Worker #[allow(clippy::needless_maybe_sized)]
35*38e8c45fSAndroid Build Coastguard Worker #[allow(unsafe_op_in_unsafe_fn)]
36*38e8c45fSAndroid Build Coastguard Worker mod ffi {
37*38e8c45fSAndroid Build Coastguard Worker     #[namespace = "android"]
38*38e8c45fSAndroid Build Coastguard Worker     unsafe extern "C++" {
39*38e8c45fSAndroid Build Coastguard Worker         include!("ffi/FromRustToCpp.h");
shouldLog(tag: &str) -> bool40*38e8c45fSAndroid Build Coastguard Worker         fn shouldLog(tag: &str) -> bool;
41*38e8c45fSAndroid Build Coastguard Worker     }
42*38e8c45fSAndroid Build Coastguard Worker 
43*38e8c45fSAndroid Build Coastguard Worker     #[namespace = "android::input::verifier"]
44*38e8c45fSAndroid Build Coastguard Worker     extern "Rust" {
45*38e8c45fSAndroid Build Coastguard Worker         /// Used to validate the incoming motion stream.
46*38e8c45fSAndroid Build Coastguard Worker         /// This class is not thread-safe.
47*38e8c45fSAndroid Build Coastguard Worker         /// State is stored in the "InputVerifier" object
48*38e8c45fSAndroid Build Coastguard Worker         /// that can be created via the 'create' method.
49*38e8c45fSAndroid Build Coastguard Worker         /// Usage:
50*38e8c45fSAndroid Build Coastguard Worker         ///
51*38e8c45fSAndroid Build Coastguard Worker         /// ```ignore
52*38e8c45fSAndroid Build Coastguard Worker         /// Box<InputVerifier> verifier = create("inputChannel name");
53*38e8c45fSAndroid Build Coastguard Worker         /// result = process_movement(verifier, ...);
54*38e8c45fSAndroid Build Coastguard Worker         /// if (result) {
55*38e8c45fSAndroid Build Coastguard Worker         ///    crash(result.error_message());
56*38e8c45fSAndroid Build Coastguard Worker         /// }
57*38e8c45fSAndroid Build Coastguard Worker         /// ```
58*38e8c45fSAndroid Build Coastguard Worker         type InputVerifier;
59*38e8c45fSAndroid Build Coastguard Worker         #[cxx_name = create]
create_input_verifier(name: String) -> Box<InputVerifier>60*38e8c45fSAndroid Build Coastguard Worker         fn create_input_verifier(name: String) -> Box<InputVerifier>;
process_movement( verifier: &mut InputVerifier, device_id: i32, source: u32, action: u32, pointer_properties: &[RustPointerProperties], flags: u32, ) -> String61*38e8c45fSAndroid Build Coastguard Worker         fn process_movement(
62*38e8c45fSAndroid Build Coastguard Worker             verifier: &mut InputVerifier,
63*38e8c45fSAndroid Build Coastguard Worker             device_id: i32,
64*38e8c45fSAndroid Build Coastguard Worker             source: u32,
65*38e8c45fSAndroid Build Coastguard Worker             action: u32,
66*38e8c45fSAndroid Build Coastguard Worker             pointer_properties: &[RustPointerProperties],
67*38e8c45fSAndroid Build Coastguard Worker             flags: u32,
68*38e8c45fSAndroid Build Coastguard Worker         ) -> String;
reset_device(verifier: &mut InputVerifier, device_id: i32)69*38e8c45fSAndroid Build Coastguard Worker         fn reset_device(verifier: &mut InputVerifier, device_id: i32);
70*38e8c45fSAndroid Build Coastguard Worker     }
71*38e8c45fSAndroid Build Coastguard Worker 
72*38e8c45fSAndroid Build Coastguard Worker     #[namespace = "android::input::keyboardClassifier"]
73*38e8c45fSAndroid Build Coastguard Worker     extern "Rust" {
74*38e8c45fSAndroid Build Coastguard Worker         /// Used to classify a keyboard into alphabetic and non-alphabetic
75*38e8c45fSAndroid Build Coastguard Worker         type KeyboardClassifier;
76*38e8c45fSAndroid Build Coastguard Worker         #[cxx_name = create]
create_keyboard_classifier() -> Box<KeyboardClassifier>77*38e8c45fSAndroid Build Coastguard Worker         fn create_keyboard_classifier() -> Box<KeyboardClassifier>;
78*38e8c45fSAndroid Build Coastguard Worker         #[cxx_name = notifyKeyboardChanged]
notify_keyboard_changed( classifier: &mut KeyboardClassifier, device_id: i32, identifier: RustInputDeviceIdentifier, device_classes: u32, )79*38e8c45fSAndroid Build Coastguard Worker         fn notify_keyboard_changed(
80*38e8c45fSAndroid Build Coastguard Worker             classifier: &mut KeyboardClassifier,
81*38e8c45fSAndroid Build Coastguard Worker             device_id: i32,
82*38e8c45fSAndroid Build Coastguard Worker             identifier: RustInputDeviceIdentifier,
83*38e8c45fSAndroid Build Coastguard Worker             device_classes: u32,
84*38e8c45fSAndroid Build Coastguard Worker         );
85*38e8c45fSAndroid Build Coastguard Worker         #[cxx_name = getKeyboardType]
get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u3286*38e8c45fSAndroid Build Coastguard Worker         fn get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32;
87*38e8c45fSAndroid Build Coastguard Worker         #[cxx_name = isFinalized]
is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool88*38e8c45fSAndroid Build Coastguard Worker         fn is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool;
89*38e8c45fSAndroid Build Coastguard Worker         #[cxx_name = processKey]
process_key( classifier: &mut KeyboardClassifier, device_id: i32, evdev_code: i32, modifier_state: u32, )90*38e8c45fSAndroid Build Coastguard Worker         fn process_key(
91*38e8c45fSAndroid Build Coastguard Worker             classifier: &mut KeyboardClassifier,
92*38e8c45fSAndroid Build Coastguard Worker             device_id: i32,
93*38e8c45fSAndroid Build Coastguard Worker             evdev_code: i32,
94*38e8c45fSAndroid Build Coastguard Worker             modifier_state: u32,
95*38e8c45fSAndroid Build Coastguard Worker         );
96*38e8c45fSAndroid Build Coastguard Worker     }
97*38e8c45fSAndroid Build Coastguard Worker 
98*38e8c45fSAndroid Build Coastguard Worker     #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
99*38e8c45fSAndroid Build Coastguard Worker     pub struct RustPointerProperties {
100*38e8c45fSAndroid Build Coastguard Worker         pub id: i32,
101*38e8c45fSAndroid Build Coastguard Worker     }
102*38e8c45fSAndroid Build Coastguard Worker 
103*38e8c45fSAndroid Build Coastguard Worker     #[derive(Debug)]
104*38e8c45fSAndroid Build Coastguard Worker     pub struct RustInputDeviceIdentifier {
105*38e8c45fSAndroid Build Coastguard Worker         pub name: String,
106*38e8c45fSAndroid Build Coastguard Worker         pub location: String,
107*38e8c45fSAndroid Build Coastguard Worker         pub unique_id: String,
108*38e8c45fSAndroid Build Coastguard Worker         pub bus: u16,
109*38e8c45fSAndroid Build Coastguard Worker         pub vendor: u16,
110*38e8c45fSAndroid Build Coastguard Worker         pub product: u16,
111*38e8c45fSAndroid Build Coastguard Worker         pub version: u16,
112*38e8c45fSAndroid Build Coastguard Worker         pub descriptor: String,
113*38e8c45fSAndroid Build Coastguard Worker     }
114*38e8c45fSAndroid Build Coastguard Worker }
115*38e8c45fSAndroid Build Coastguard Worker 
116*38e8c45fSAndroid Build Coastguard Worker use crate::ffi::{RustInputDeviceIdentifier, RustPointerProperties};
117*38e8c45fSAndroid Build Coastguard Worker 
create_input_verifier(name: String) -> Box<InputVerifier>118*38e8c45fSAndroid Build Coastguard Worker fn create_input_verifier(name: String) -> Box<InputVerifier> {
119*38e8c45fSAndroid Build Coastguard Worker     Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents")))
120*38e8c45fSAndroid Build Coastguard Worker }
121*38e8c45fSAndroid Build Coastguard Worker 
process_movement( verifier: &mut InputVerifier, device_id: i32, source: u32, action: u32, pointer_properties: &[RustPointerProperties], flags: u32, ) -> String122*38e8c45fSAndroid Build Coastguard Worker fn process_movement(
123*38e8c45fSAndroid Build Coastguard Worker     verifier: &mut InputVerifier,
124*38e8c45fSAndroid Build Coastguard Worker     device_id: i32,
125*38e8c45fSAndroid Build Coastguard Worker     source: u32,
126*38e8c45fSAndroid Build Coastguard Worker     action: u32,
127*38e8c45fSAndroid Build Coastguard Worker     pointer_properties: &[RustPointerProperties],
128*38e8c45fSAndroid Build Coastguard Worker     flags: u32,
129*38e8c45fSAndroid Build Coastguard Worker ) -> String {
130*38e8c45fSAndroid Build Coastguard Worker     let motion_flags = MotionFlags::from_bits(flags);
131*38e8c45fSAndroid Build Coastguard Worker     if motion_flags.is_none() {
132*38e8c45fSAndroid Build Coastguard Worker         panic!(
133*38e8c45fSAndroid Build Coastguard Worker             "The conversion of flags 0x{:08x} failed, please check if some flags have not been \
134*38e8c45fSAndroid Build Coastguard Worker             added to MotionFlags.",
135*38e8c45fSAndroid Build Coastguard Worker             flags
136*38e8c45fSAndroid Build Coastguard Worker         );
137*38e8c45fSAndroid Build Coastguard Worker     }
138*38e8c45fSAndroid Build Coastguard Worker     let result = verifier.process_movement(
139*38e8c45fSAndroid Build Coastguard Worker         DeviceId(device_id),
140*38e8c45fSAndroid Build Coastguard Worker         Source::from_bits(source).unwrap(),
141*38e8c45fSAndroid Build Coastguard Worker         action,
142*38e8c45fSAndroid Build Coastguard Worker         pointer_properties,
143*38e8c45fSAndroid Build Coastguard Worker         motion_flags.unwrap(),
144*38e8c45fSAndroid Build Coastguard Worker     );
145*38e8c45fSAndroid Build Coastguard Worker     match result {
146*38e8c45fSAndroid Build Coastguard Worker         Ok(()) => "".to_string(),
147*38e8c45fSAndroid Build Coastguard Worker         Err(e) => e,
148*38e8c45fSAndroid Build Coastguard Worker     }
149*38e8c45fSAndroid Build Coastguard Worker }
150*38e8c45fSAndroid Build Coastguard Worker 
reset_device(verifier: &mut InputVerifier, device_id: i32)151*38e8c45fSAndroid Build Coastguard Worker fn reset_device(verifier: &mut InputVerifier, device_id: i32) {
152*38e8c45fSAndroid Build Coastguard Worker     verifier.reset_device(DeviceId(device_id));
153*38e8c45fSAndroid Build Coastguard Worker }
154*38e8c45fSAndroid Build Coastguard Worker 
create_keyboard_classifier() -> Box<KeyboardClassifier>155*38e8c45fSAndroid Build Coastguard Worker fn create_keyboard_classifier() -> Box<KeyboardClassifier> {
156*38e8c45fSAndroid Build Coastguard Worker     // Future design: Make this data store singleton by passing it to C++ side and making it global
157*38e8c45fSAndroid Build Coastguard Worker     // and pass by reference to components that need to store persistent data.
158*38e8c45fSAndroid Build Coastguard Worker     //
159*38e8c45fSAndroid Build Coastguard Worker     // Currently only used by rust keyboard classifier so keeping it here.
160*38e8c45fSAndroid Build Coastguard Worker     let data_store = DataStore::new(Box::new(DefaultFileReaderWriter::new(
161*38e8c45fSAndroid Build Coastguard Worker         "/data/system/inputflinger-data.json".to_string(),
162*38e8c45fSAndroid Build Coastguard Worker     )));
163*38e8c45fSAndroid Build Coastguard Worker     Box::new(KeyboardClassifier::new(data_store))
164*38e8c45fSAndroid Build Coastguard Worker }
165*38e8c45fSAndroid Build Coastguard Worker 
notify_keyboard_changed( classifier: &mut KeyboardClassifier, device_id: i32, identifier: RustInputDeviceIdentifier, device_classes: u32, )166*38e8c45fSAndroid Build Coastguard Worker fn notify_keyboard_changed(
167*38e8c45fSAndroid Build Coastguard Worker     classifier: &mut KeyboardClassifier,
168*38e8c45fSAndroid Build Coastguard Worker     device_id: i32,
169*38e8c45fSAndroid Build Coastguard Worker     identifier: RustInputDeviceIdentifier,
170*38e8c45fSAndroid Build Coastguard Worker     device_classes: u32,
171*38e8c45fSAndroid Build Coastguard Worker ) {
172*38e8c45fSAndroid Build Coastguard Worker     let classes = DeviceClass::from_bits(device_classes);
173*38e8c45fSAndroid Build Coastguard Worker     if classes.is_none() {
174*38e8c45fSAndroid Build Coastguard Worker         panic!(
175*38e8c45fSAndroid Build Coastguard Worker             "The conversion of device class 0x{:08x} failed, please check if some device classes
176*38e8c45fSAndroid Build Coastguard Worker              have not been added to DeviceClass.",
177*38e8c45fSAndroid Build Coastguard Worker             device_classes
178*38e8c45fSAndroid Build Coastguard Worker         );
179*38e8c45fSAndroid Build Coastguard Worker     }
180*38e8c45fSAndroid Build Coastguard Worker     classifier.notify_keyboard_changed(InputDevice {
181*38e8c45fSAndroid Build Coastguard Worker         device_id: DeviceId(device_id),
182*38e8c45fSAndroid Build Coastguard Worker         identifier,
183*38e8c45fSAndroid Build Coastguard Worker         classes: classes.unwrap(),
184*38e8c45fSAndroid Build Coastguard Worker     });
185*38e8c45fSAndroid Build Coastguard Worker }
186*38e8c45fSAndroid Build Coastguard Worker 
get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32187*38e8c45fSAndroid Build Coastguard Worker fn get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32 {
188*38e8c45fSAndroid Build Coastguard Worker     classifier.get_keyboard_type(DeviceId(device_id)) as u32
189*38e8c45fSAndroid Build Coastguard Worker }
190*38e8c45fSAndroid Build Coastguard Worker 
is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool191*38e8c45fSAndroid Build Coastguard Worker fn is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool {
192*38e8c45fSAndroid Build Coastguard Worker     classifier.is_finalized(DeviceId(device_id))
193*38e8c45fSAndroid Build Coastguard Worker }
194*38e8c45fSAndroid Build Coastguard Worker 
process_key( classifier: &mut KeyboardClassifier, device_id: i32, evdev_code: i32, meta_state: u32, )195*38e8c45fSAndroid Build Coastguard Worker fn process_key(
196*38e8c45fSAndroid Build Coastguard Worker     classifier: &mut KeyboardClassifier,
197*38e8c45fSAndroid Build Coastguard Worker     device_id: i32,
198*38e8c45fSAndroid Build Coastguard Worker     evdev_code: i32,
199*38e8c45fSAndroid Build Coastguard Worker     meta_state: u32,
200*38e8c45fSAndroid Build Coastguard Worker ) {
201*38e8c45fSAndroid Build Coastguard Worker     let modifier_state = ModifierState::from_bits(meta_state);
202*38e8c45fSAndroid Build Coastguard Worker     if modifier_state.is_none() {
203*38e8c45fSAndroid Build Coastguard Worker         panic!(
204*38e8c45fSAndroid Build Coastguard Worker             "The conversion of meta state 0x{:08x} failed, please check if some meta state
205*38e8c45fSAndroid Build Coastguard Worker              have not been added to ModifierState.",
206*38e8c45fSAndroid Build Coastguard Worker             meta_state
207*38e8c45fSAndroid Build Coastguard Worker         );
208*38e8c45fSAndroid Build Coastguard Worker     }
209*38e8c45fSAndroid Build Coastguard Worker     classifier.process_key(DeviceId(device_id), evdev_code, modifier_state.unwrap());
210*38e8c45fSAndroid Build Coastguard Worker }
211