Add support for pre-classifying devices
Bring in blocklist from CrOS as initial config (https://source.chromium.org/chromium/chromium/src/+/main:ui/events/ozone/evdev/event_device_info.cc;drc=1bbf8ac9caa7e57a52a71deec56bf1b6f683c6bd;l=31)
Test: atest --host libinput_rust_test
Bug: 263559234
Flag: com.android.input.flags.enable_keyboard_classifier
Change-Id: I8ffd3d6268cd96de9dfa0addb4653768fed5732c
diff --git a/libs/input/rust/keyboard_classification_config.rs b/libs/input/rust/keyboard_classification_config.rs
new file mode 100644
index 0000000..ab74efb
--- /dev/null
+++ b/libs/input/rust/keyboard_classification_config.rs
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+use crate::input::KeyboardType;
+
+// TODO(b/263559234): Categorize some of these to KeyboardType::None based on ability to produce
+// key events at all. (Requires setup allowing InputDevice to dynamically add/remove
+// KeyboardInputMapper based on blocklist and KeyEvents in case a KeyboardType::None device ends
+// up producing a key event)
+pub static CLASSIFIED_DEVICES: &[(
+ /* vendorId */ u16,
+ /* productId */ u16,
+ KeyboardType,
+ /* is_finalized */ bool,
+)] = &[
+ // HP X4000 Wireless Mouse
+ (0x03f0, 0xa407, KeyboardType::NonAlphabetic, true),
+ // Microsoft Wireless Mobile Mouse 6000
+ (0x045e, 0x0745, KeyboardType::NonAlphabetic, true),
+ // Microsoft Surface Precision Mouse
+ (0x045e, 0x0821, KeyboardType::NonAlphabetic, true),
+ // Microsoft Pro IntelliMouse
+ (0x045e, 0x082a, KeyboardType::NonAlphabetic, true),
+ // Microsoft Bluetooth Mouse
+ (0x045e, 0x082f, KeyboardType::NonAlphabetic, true),
+ // Xbox One Elite Series 2 gamepad
+ (0x045e, 0x0b05, KeyboardType::NonAlphabetic, true),
+ // Logitech T400
+ (0x046d, 0x4026, KeyboardType::NonAlphabetic, true),
+ // Logitech M720 Triathlon (Unifying)
+ (0x046d, 0x405e, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master 2S (Unifying)
+ (0x046d, 0x4069, KeyboardType::NonAlphabetic, true),
+ // Logitech M585 (Unifying)
+ (0x046d, 0x406b, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2 (Unifying)
+ (0x046d, 0x4072, KeyboardType::NonAlphabetic, true),
+ // Logitech Pebble M350
+ (0x046d, 0x4080, KeyboardType::NonAlphabetic, true),
+ // Logitech T630 Ultrathin
+ (0x046d, 0xb00d, KeyboardType::NonAlphabetic, true),
+ // Logitech M558
+ (0x046d, 0xb011, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master (Bluetooth)
+ (0x046d, 0xb012, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2 (Bluetooth)
+ (0x046d, 0xb013, KeyboardType::NonAlphabetic, true),
+ // Logitech M720 Triathlon (Bluetooth)
+ (0x046d, 0xb015, KeyboardType::NonAlphabetic, true),
+ // Logitech M535
+ (0x046d, 0xb016, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master / Anywhere 2 (Bluetooth)
+ (0x046d, 0xb017, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master 2S (Bluetooth)
+ (0x046d, 0xb019, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2S (Bluetooth)
+ (0x046d, 0xb01a, KeyboardType::NonAlphabetic, true),
+ // Logitech M585/M590 (Bluetooth)
+ (0x046d, 0xb01b, KeyboardType::NonAlphabetic, true),
+ // Logitech G603 Lightspeed Gaming Mouse (Bluetooth)
+ (0x046d, 0xb01c, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master (Bluetooth)
+ (0x046d, 0xb01e, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2 (Bluetooth)
+ (0x046d, 0xb01f, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master 3 (Bluetooth)
+ (0x046d, 0xb023, KeyboardType::NonAlphabetic, true),
+ // Logitech G604 Lightspeed Gaming Mouse (Bluetooth)
+ (0x046d, 0xb024, KeyboardType::NonAlphabetic, true),
+ // Logitech Spotlight Presentation Remote (Bluetooth)
+ (0x046d, 0xb503, KeyboardType::NonAlphabetic, true),
+ // Logitech R500 (Bluetooth)
+ (0x046d, 0xb505, KeyboardType::NonAlphabetic, true),
+ // Logitech M500s
+ (0x046d, 0xc093, KeyboardType::NonAlphabetic, true),
+ // Logitech Spotlight Presentation Remote (USB dongle)
+ (0x046d, 0xc53e, KeyboardType::NonAlphabetic, true),
+ // Elecom Enelo IR LED Mouse 350
+ (0x056e, 0x0134, KeyboardType::NonAlphabetic, true),
+ // Elecom EPRIM Blue LED 5 button mouse 228
+ (0x056e, 0x0141, KeyboardType::NonAlphabetic, true),
+ // Elecom Blue LED Mouse 203
+ (0x056e, 0x0159, KeyboardType::NonAlphabetic, true),
+ // Zebra LS2208 barcode scanner
+ (0x05e0, 0x1200, KeyboardType::NonAlphabetic, true),
+ // RDing FootSwitch1F1
+ (0x0c45, 0x7403, KeyboardType::NonAlphabetic, true),
+ // SteelSeries Sensei RAW Frost Blue
+ (0x1038, 0x1369, KeyboardType::NonAlphabetic, true),
+ // SteelSeries Rival 3 Wired
+ (0x1038, 0x1824, KeyboardType::NonAlphabetic, true),
+ // SteelSeries Rival 3 Wireless (USB dongle)
+ (0x1038, 0x1830, KeyboardType::NonAlphabetic, true),
+ // Yubico.com Yubikey
+ (0x1050, 0x0010, KeyboardType::NonAlphabetic, true),
+ // Yubico.com Yubikey 4 OTP+U2F+CCID
+ (0x1050, 0x0407, KeyboardType::NonAlphabetic, true),
+ // Lenovo USB-C Wired Compact Mouse
+ (0x17ef, 0x6123, KeyboardType::NonAlphabetic, true),
+ // Corsair Katar Pro Wireless (USB dongle)
+ (0x1b1c, 0x1b94, KeyboardType::NonAlphabetic, true),
+ // Corsair Katar Pro Wireless (Bluetooth)
+ (0x1bae, 0x1b1c, KeyboardType::NonAlphabetic, true),
+ // Kensington Pro Fit Full-size
+ (0x1bcf, 0x08a0, KeyboardType::NonAlphabetic, true),
+ // Huion HS64
+ (0x256c, 0x006d, KeyboardType::NonAlphabetic, true),
+ // XP-Pen Star G640
+ (0x28bd, 0x0914, KeyboardType::NonAlphabetic, true),
+ // XP-Pen Artist 12 Pro
+ (0x28bd, 0x091f, KeyboardType::NonAlphabetic, true),
+ // XP-Pen Deco mini7W
+ (0x28bd, 0x0928, KeyboardType::NonAlphabetic, true),
+];
diff --git a/libs/input/rust/keyboard_classifier.rs b/libs/input/rust/keyboard_classifier.rs
index 1063fac..8721ef7 100644
--- a/libs/input/rust/keyboard_classifier.rs
+++ b/libs/input/rust/keyboard_classifier.rs
@@ -35,6 +35,7 @@
//! TODO(b/263559234): Data store implementation to store information about past classification
use crate::input::{DeviceId, InputDevice, KeyboardType};
+use crate::keyboard_classification_config::CLASSIFIED_DEVICES;
use crate::{DeviceClass, ModifierState};
use std::collections::HashMap;
@@ -126,6 +127,14 @@
(KeyboardType::NonAlphabetic, true)
};
}
+
+ // Check in known device list for classification
+ for data in CLASSIFIED_DEVICES.iter() {
+ if device.identifier.vendor == data.0 && device.identifier.product == data.1 {
+ return (data.2, data.3);
+ }
+ }
+
// Any composite device with multiple device classes should be categorized as non-alphabetic
// keyboard initially
if device.classes.contains(DeviceClass::Touch)
@@ -169,6 +178,7 @@
#[cfg(test)]
mod tests {
use crate::input::{DeviceId, InputDevice, KeyboardType};
+ use crate::keyboard_classification_config::CLASSIFIED_DEVICES;
use crate::keyboard_classifier::KeyboardClassifier;
use crate::{DeviceClass, ModifierState, RustInputDeviceIdentifier};
@@ -326,6 +336,17 @@
assert!(!classifier.is_finalized(DEVICE_ID));
}
+ #[test]
+ fn classify_known_devices() {
+ let mut classifier = KeyboardClassifier::new();
+ for device in CLASSIFIED_DEVICES.iter() {
+ classifier
+ .notify_keyboard_changed(create_device_with_vendor_product_ids(device.0, device.1));
+ assert_eq!(classifier.get_keyboard_type(DEVICE_ID), device.2);
+ assert_eq!(classifier.is_finalized(DEVICE_ID), device.3);
+ }
+ }
+
fn create_device(classes: DeviceClass) -> InputDevice {
InputDevice {
device_id: DEVICE_ID,
@@ -342,4 +363,21 @@
classes,
}
}
+
+ fn create_device_with_vendor_product_ids(vendor: u16, product: u16) -> InputDevice {
+ InputDevice {
+ device_id: DEVICE_ID,
+ identifier: RustInputDeviceIdentifier {
+ name: "test_device".to_string(),
+ location: "location".to_string(),
+ unique_id: "unique_id".to_string(),
+ bus: 123,
+ vendor,
+ product,
+ version: 567,
+ descriptor: "descriptor".to_string(),
+ },
+ classes: DeviceClass::Keyboard | DeviceClass::AlphabeticKey | DeviceClass::External,
+ }
+ }
}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 5010475..af8f889 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -18,6 +18,7 @@
mod input;
mod input_verifier;
+mod keyboard_classification_config;
mod keyboard_classifier;
pub use input::{