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 input;
20 mod input_verifier;
21 mod keyboard_classifier;
22 
23 pub use input::{
24     DeviceClass, DeviceId, InputDevice, ModifierState, MotionAction, MotionFlags, Source,
25 };
26 pub use input_verifier::InputVerifier;
27 pub use keyboard_classifier::KeyboardClassifier;
28 
29 #[cxx::bridge(namespace = "android::input")]
30 #[allow(unsafe_op_in_unsafe_fn)]
31 mod ffi {
32     #[namespace = "android"]
33     unsafe extern "C++" {
34         include!("ffi/FromRustToCpp.h");
shouldLog(tag: &str) -> bool35         fn shouldLog(tag: &str) -> bool;
36     }
37 
38     #[namespace = "android::input::verifier"]
39     extern "Rust" {
40         /// Used to validate the incoming motion stream.
41         /// This class is not thread-safe.
42         /// State is stored in the "InputVerifier" object
43         /// that can be created via the 'create' method.
44         /// Usage:
45         ///
46         /// ```ignore
47         /// Box<InputVerifier> verifier = create("inputChannel name");
48         /// result = process_movement(verifier, ...);
49         /// if (result) {
50         ///    crash(result.error_message());
51         /// }
52         /// ```
53         type InputVerifier;
54         #[cxx_name = create]
create_input_verifier(name: String) -> Box<InputVerifier>55         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, ) -> String56         fn process_movement(
57             verifier: &mut InputVerifier,
58             device_id: i32,
59             source: u32,
60             action: u32,
61             pointer_properties: &[RustPointerProperties],
62             flags: u32,
63         ) -> String;
reset_device(verifier: &mut InputVerifier, device_id: i32)64         fn reset_device(verifier: &mut InputVerifier, device_id: i32);
65     }
66 
67     #[namespace = "android::input::keyboardClassifier"]
68     extern "Rust" {
69         /// Used to classify a keyboard into alphabetic and non-alphabetic
70         type KeyboardClassifier;
71         #[cxx_name = create]
create_keyboard_classifier() -> Box<KeyboardClassifier>72         fn create_keyboard_classifier() -> Box<KeyboardClassifier>;
73         #[cxx_name = notifyKeyboardChanged]
notify_keyboard_changed( classifier: &mut KeyboardClassifier, device_id: i32, identifier: RustInputDeviceIdentifier, device_classes: u32, )74         fn notify_keyboard_changed(
75             classifier: &mut KeyboardClassifier,
76             device_id: i32,
77             identifier: RustInputDeviceIdentifier,
78             device_classes: u32,
79         );
80         #[cxx_name = getKeyboardType]
get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u3281         fn get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32;
82         #[cxx_name = isFinalized]
is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool83         fn is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool;
84         #[cxx_name = processKey]
process_key( classifier: &mut KeyboardClassifier, device_id: i32, evdev_code: i32, modifier_state: u32, )85         fn process_key(
86             classifier: &mut KeyboardClassifier,
87             device_id: i32,
88             evdev_code: i32,
89             modifier_state: u32,
90         );
91     }
92 
93     #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
94     pub struct RustPointerProperties {
95         pub id: i32,
96     }
97 
98     #[derive(Debug)]
99     pub struct RustInputDeviceIdentifier {
100         pub name: String,
101         pub location: String,
102         pub unique_id: String,
103         pub bus: u16,
104         pub vendor: u16,
105         pub product: u16,
106         pub version: u16,
107         pub descriptor: String,
108     }
109 }
110 
111 use crate::ffi::{RustInputDeviceIdentifier, RustPointerProperties};
112 
create_input_verifier(name: String) -> Box<InputVerifier>113 fn create_input_verifier(name: String) -> Box<InputVerifier> {
114     Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents")))
115 }
116 
process_movement( verifier: &mut InputVerifier, device_id: i32, source: u32, action: u32, pointer_properties: &[RustPointerProperties], flags: u32, ) -> String117 fn process_movement(
118     verifier: &mut InputVerifier,
119     device_id: i32,
120     source: u32,
121     action: u32,
122     pointer_properties: &[RustPointerProperties],
123     flags: u32,
124 ) -> String {
125     let motion_flags = MotionFlags::from_bits(flags);
126     if motion_flags.is_none() {
127         panic!(
128             "The conversion of flags 0x{:08x} failed, please check if some flags have not been \
129             added to MotionFlags.",
130             flags
131         );
132     }
133     let result = verifier.process_movement(
134         DeviceId(device_id),
135         Source::from_bits(source).unwrap(),
136         action,
137         pointer_properties,
138         motion_flags.unwrap(),
139     );
140     match result {
141         Ok(()) => "".to_string(),
142         Err(e) => e,
143     }
144 }
145 
reset_device(verifier: &mut InputVerifier, device_id: i32)146 fn reset_device(verifier: &mut InputVerifier, device_id: i32) {
147     verifier.reset_device(DeviceId(device_id));
148 }
149 
create_keyboard_classifier() -> Box<KeyboardClassifier>150 fn create_keyboard_classifier() -> Box<KeyboardClassifier> {
151     Box::new(KeyboardClassifier::new())
152 }
153 
notify_keyboard_changed( classifier: &mut KeyboardClassifier, device_id: i32, identifier: RustInputDeviceIdentifier, device_classes: u32, )154 fn notify_keyboard_changed(
155     classifier: &mut KeyboardClassifier,
156     device_id: i32,
157     identifier: RustInputDeviceIdentifier,
158     device_classes: u32,
159 ) {
160     let classes = DeviceClass::from_bits(device_classes);
161     if classes.is_none() {
162         panic!(
163             "The conversion of device class 0x{:08x} failed, please check if some device classes
164              have not been added to DeviceClass.",
165             device_classes
166         );
167     }
168     classifier.notify_keyboard_changed(InputDevice {
169         device_id: DeviceId(device_id),
170         identifier,
171         classes: classes.unwrap(),
172     });
173 }
174 
get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32175 fn get_keyboard_type(classifier: &mut KeyboardClassifier, device_id: i32) -> u32 {
176     classifier.get_keyboard_type(DeviceId(device_id)) as u32
177 }
178 
is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool179 fn is_finalized(classifier: &mut KeyboardClassifier, device_id: i32) -> bool {
180     classifier.is_finalized(DeviceId(device_id))
181 }
182 
process_key( classifier: &mut KeyboardClassifier, device_id: i32, evdev_code: i32, meta_state: u32, )183 fn process_key(
184     classifier: &mut KeyboardClassifier,
185     device_id: i32,
186     evdev_code: i32,
187     meta_state: u32,
188 ) {
189     let modifier_state = ModifierState::from_bits(meta_state);
190     if modifier_state.is_none() {
191         panic!(
192             "The conversion of meta state 0x{:08x} failed, please check if some meta state
193              have not been added to ModifierState.",
194             meta_state
195         );
196     }
197     classifier.process_key(DeviceId(device_id), evdev_code, modifier_state.unwrap());
198 }
199