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