From 03d3398f1e9945c39a30590829c5050eaa9d9b22 Mon Sep 17 00:00:00 2001 From: liye Date: Wed, 6 Aug 2025 10:57:00 +0800 Subject: [PATCH 1/5] add wire control --- Cargo.toml | 1 + devices/Cargo.toml | 1 + devices/src/usb/config.rs | 1 + devices/src/usb/consumer.rs | 248 +++++++++++++++++++++++++++++ devices/src/usb/hid.rs | 78 ++++++++- devices/src/usb/mod.rs | 2 + docs/config_guidebook.md | 14 ++ machine/Cargo.toml | 1 + machine/src/lib.rs | 13 +- machine/src/standard_common/mod.rs | 2 +- machine_manager/src/cmdline.rs | 1 + machine_manager/src/machine.rs | 1 + trace/trace_info/usb.toml | 12 ++ ui/src/input.rs | 57 +++++++ ui/src/keycode.rs | 122 ++++++++------ ui/src/ohui_srv/msg_handle.rs | 15 +- 16 files changed, 510 insertions(+), 59 deletions(-) create mode 100644 devices/src/usb/consumer.rs diff --git a/Cargo.toml b/Cargo.toml index 4c78415f..2c1bdae9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ trace_to_hitrace = ["trace/trace_to_hitrace", "machine/trace_to_hitrace"] hisysevent = ["hisysevent/hisysevent"] vfio = ["machine/vfio_device"] usb_uas = ["machine/usb_uas"] +usb_consumer = ["machine/usb_consumer"] virtio_rng = ["machine/virtio_rng"] virtio_scsi = ["machine/virtio_scsi"] vhost_vsock = ["machine/vhost_vsock"] diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 3dca2b41..da05e394 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -57,3 +57,4 @@ usb_uas = [] trace_to_logger = [] trace_to_ftrace = [] trace_to_hitrace = [] +usb_consumer = [] diff --git a/devices/src/usb/config.rs b/devices/src/usb/config.rs index aef89932..3fd8e7a6 100644 --- a/devices/src/usb/config.rs +++ b/devices/src/usb/config.rs @@ -267,3 +267,4 @@ pub const USB_PRODUCT_ID_KEYBOARD: u16 = 0x0002; pub const USB_PRODUCT_ID_STORAGE: u16 = 0x0003; pub const USB_PRODUCT_ID_TABLET: u16 = 0x0004; pub const USB_PRODUCT_ID_UAS: u16 = 0x0005; +pub const USB_PRODUCT_ID_CONSUMER: u16 = 0x0006; diff --git a/devices/src/usb/consumer.rs b/devices/src/usb/consumer.rs new file mode 100644 index 00000000..e17f306c --- /dev/null +++ b/devices/src/usb/consumer.rs @@ -0,0 +1,248 @@ +// Copyright (c) 2025 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::sync::{Arc, Mutex, Weak}; + +use anyhow::Result; +use clap::Parser; +use log::{debug, info, warn}; +use once_cell::sync::Lazy; + +use super::descriptor::{ + UsbConfigDescriptor, UsbDescConfig, UsbDescDevice, UsbDescEndpoint, UsbDescIface, UsbDescOther, + UsbDescriptorOps, UsbDeviceDescriptor, UsbEndpointDescriptor, UsbInterfaceDescriptor, +}; +use super::hid::{Hid, HidType, CONSUMER_REPORT_DESCRIPTOR, QUEUE_LENGTH, QUEUE_MASK}; +use super::xhci::xhci_controller::{endpoint_number_to_id, XhciDevice}; +use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; +use super::{ + notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, + UsbPacketStatus, +}; +use machine_manager::config::valid_id; +use ui::input::{register_consumer, unregister_consumer, ConsumerOpts, CONSUMER_UP}; +use util::gen_base_func; + +/// Consumer device descriptor +static DESC_DEVICE_CONSUMER: Lazy> = Lazy::new(|| { + Arc::new(UsbDescDevice { + device_desc: UsbDeviceDescriptor { + bLength: USB_DT_DEVICE_SIZE, + bDescriptorType: USB_DT_DEVICE, + idVendor: 0x0627, + idProduct: USB_PRODUCT_ID_CONSUMER, + bcdDevice: 0, + iManufacturer: STR_MANUFACTURER_INDEX, + iProduct: STR_PRODUCT_CONSUMER_INDEX, + iSerialNumber: STR_SERIAL_CONSUMER_INDEX, + bcdUSB: 0x0100, + bDeviceClass: 0, + bDeviceSubClass: 0, + bDeviceProtocol: 0, + bMaxPacketSize0: 8, + bNumConfigurations: 1, + }, + configs: vec![Arc::new(UsbDescConfig { + config_desc: UsbConfigDescriptor { + bLength: USB_DT_CONFIG_SIZE, + bDescriptorType: USB_DT_CONFIGURATION, + wTotalLength: 0, + bNumInterfaces: 1, + bConfigurationValue: 1, + iConfiguration: STR_CONFIG_CONSUMER_INDEX, + bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_REMOTE_WAKEUP, + bMaxPower: 50, + }, + iad_desc: vec![], + interfaces: vec![DESC_IFACE_CONSUMER.clone()], + })], + }) +}); +/// CONSUMER interface descriptor +static DESC_IFACE_CONSUMER: Lazy> = Lazy::new(|| { + Arc::new(UsbDescIface { + interface_desc: UsbInterfaceDescriptor { + bLength: USB_DT_INTERFACE_SIZE, + bDescriptorType: USB_DT_INTERFACE, + bInterfaceNumber: 0, + bAlternateSetting: 0, + bNumEndpoints: 1, + bInterfaceClass: USB_CLASS_HID, + bInterfaceSubClass: 0, + bInterfaceProtocol: 0, + iInterface: 0, + }, + other_desc: vec![Arc::new(UsbDescOther { + // HID descriptor + data: vec![0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, CONSUMER_REPORT_DESCRIPTOR.len() as u8, 0], + })], + endpoints: vec![Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | 0x1, + bmAttributes: USB_ENDPOINT_ATTR_INT, + wMaxPacketSize: 8, + bInterval: 0xa, + }, + extra: Vec::new(), + })], + }) +}); + +/// String descriptor index +const STR_MANUFACTURER_INDEX: u8 = 1; +const STR_PRODUCT_CONSUMER_INDEX: u8 = 2; +const STR_CONFIG_CONSUMER_INDEX: u8 = 3; +const STR_SERIAL_CONSUMER_INDEX: u8 = 4; + +/// String descriptor +const DESC_STRINGS: [&str; 5] = [ + "", + "StratoVirt", + "StratoVirt USB Consumer", + "HID Consumer", + "6", +]; + +#[derive(Parser, Clone, Debug, Default)] +#[command(no_binary_name(true))] +pub struct UsbConsumerConfig { + #[arg(long)] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + id: String, + #[arg(long)] + bus: Option, + #[arg(long)] + port: Option, +} + +/// USB Consumer device. +pub struct UsbConsumer { + base: UsbDeviceBase, + hid: Hid, + /// USB controller used to notify controller to transfer data. + cntlr: Option>>, +} + +pub struct UsbConsumerAdapter { + usb_consumer: Arc>, +} + +impl ConsumerOpts for UsbConsumerAdapter { + fn do_consumer_event(&mut self, keycode: u16, down: bool) -> Result<()> { + trace::usb_consumer_event(&keycode, &down); + + let mut scan_code = keycode; + if !down { + scan_code = scan_code | CONSUMER_UP; + } + + let mut locked_consumer = self.usb_consumer.lock().unwrap(); + if locked_consumer.hid.num >= QUEUE_LENGTH { + trace::usb_consumer_queue_full(); + return Ok(()); + } + + let index = ((locked_consumer.hid.head + locked_consumer.hid.num) & QUEUE_MASK) as usize; + locked_consumer.hid.num += 1; + locked_consumer.hid.consumer.keycodes[index] = scan_code; + drop(locked_consumer); + let clone_consumer = self.usb_consumer.clone(); + let ep_id = endpoint_number_to_id(true, 1); + notify_controller(&(clone_consumer as Arc>), ep_id) + } +} + +impl UsbConsumer { + pub fn new(config: UsbConsumerConfig) -> Self { + Self { + base: UsbDeviceBase::new(config.id, USB_DEVICE_BUFFER_DEFAULT_LEN), + hid: Hid::new(HidType::Consumer), + cntlr: None, + } + } +} + +impl UsbDevice for UsbConsumer { + gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); + + fn realize(mut self) -> Result>> { + self.base.reset_usb_endpoint(); + self.base.speed = USB_SPEED_FULL; + let mut s: Vec = DESC_STRINGS.iter().map(|&s| s.to_string()).collect(); + let prefix = &s[STR_SERIAL_CONSUMER_INDEX as usize]; + s[STR_SERIAL_CONSUMER_INDEX as usize] = self.base.generate_serial_number(prefix); + self.base.init_descriptor(DESC_DEVICE_CONSUMER.clone(), s)?; + let id = self.device_id().to_string(); + let consumer = Arc::new(Mutex::new(self)); + let consumer_adapter = Arc::new(Mutex::new(UsbConsumerAdapter { + usb_consumer: consumer.clone(), + })); + register_consumer(&id, consumer_adapter); + + Ok(consumer_adapter) + } + + fn unrealize(&mut self) -> Result<()> { + unregister_consumer(self.device_id()); + Ok(()) + } + + fn cancel_packet(&mut self, _packet: &Arc>) {} + + fn reset(&mut self) { + info!("Consumer device reset"); + self.base.remote_wakeup = 0; + self.base.addr = 0; + self.hid.reset(); + } + + fn handle_control(&mut self, packet: &Arc>, device_req: &UsbDeviceRequest) { + let mut locked_packet = packet.lock().unwrap(); + match self + .base + .handle_control_for_descriptor(&mut locked_packet, device_req) + { + Ok(handled) => { + if handled { + debug!("Consumer control handled by descriptor, return directly."); + return; + } + } + Err(e) => { + warn!( + "Received incorrect USB Consumer descriptor message: {:?}", + e + ); + locked_packet.status = UsbPacketStatus::Stall; + return; + } + } + self.hid + .handle_control_packet(&mut locked_packet, device_req, &mut self.base.data_buf); + } + + fn handle_data(&mut self, p: &Arc>) { + let mut locked_p = p.lock().unwrap(); + self.hid.handle_data_packet(&mut locked_p); + } + + fn set_controller(&mut self, cntlr: Weak>) { + self.cntlr = Some(cntlr); + } + + fn get_controller(&self) -> Option>> { + self.cntlr.clone() + } +} diff --git a/devices/src/usb/hid.rs b/devices/src/usb/hid.rs index 513005ef..14d6b8a8 100644 --- a/devices/src/usb/hid.rs +++ b/devices/src/usb/hid.rs @@ -16,7 +16,8 @@ use log::error; use super::config::*; use super::{UsbDeviceRequest, UsbPacket, UsbPacketStatus}; -use ui::input::set_kbd_led_state; +use ui::input::{set_kbd_led_state, MEDIA_FAST_FORWARD, MEDIA_NEXT, MEDIA_PLAY_PAUSE, MEDIA_PREVIOUS, + MEDIA_REWIND, MEDIA_STOP}; /// HID keycode const HID_KEYBOARD_LEFT_CONTROL: u8 = 0xe0; @@ -152,12 +153,35 @@ const KEYBOARD_REPORT_DESCRIPTOR: [u8; 63] = [ 0xc0, // End Collection ]; +/// consumer report descriptor +const CONSUMER_REPORT_DESCRIPTOR: &[u8] = &[ + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xa1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x06, // Report Count (6) + 0x09, 0xCD, // Usage (Play/Pause) + 0x09, 0xB7, // Usage (Stop) + 0x09, 0xB5, // Usage (Scan Previous Track) + 0x09, 0xB6, // Usage (Scan Next Track) + 0x09, 0xB4, // Usage (Rewind) + 0x09, 0xB3, // Usage (Fast Forward) + 0x81, 0x02, // Input (Data,Var,Abs) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x03, // Input (Const,Var,Abs) + 0xc0, // End Collection +]; + /// HID type #[derive(Debug)] pub enum HidType { Mouse, Tablet, Keyboard, + Consumer, UnKnown, } @@ -222,6 +246,22 @@ impl HidPointer { } } +pub struct HidConsumer { + pub keycodes: [u16; QUEUE_LENGTH as usize], +} + +impl HidConsumer { + fn new() -> Self { + HidConsumer { + keycodes: [0; QUEUE_LENGTH as usize], + } + } + + fn reset(&mut self) { + self.keycodes.iter_mut().for_each(|x| *x = 0); + } +} + /// Human Interface Device. pub struct Hid { pub(crate) head: u32, @@ -231,6 +271,7 @@ pub struct Hid { idle: u8, pub(crate) keyboard: HidKeyboard, pub(crate) pointer: HidPointer, + pub(crate) consumer: HidConsumer, } impl Hid { @@ -243,6 +284,7 @@ impl Hid { idle: 0, keyboard: HidKeyboard::new(), pointer: HidPointer::new(), + consumer: HidConsumer::new(), } } @@ -253,6 +295,7 @@ impl Hid { self.idle = 0; self.keyboard.reset(); self.pointer.reset(); + self.consumer.reset(); } fn convert_to_hid_code(&mut self) { @@ -334,6 +377,26 @@ impl Hid { data } + fn consumer_poll(&mut self) -> Vec { + let mut data = vec![1]; + if self.num != 0 { + let slot = self.head & QUEUE_MASK; + self.increase_head(); + self.num -= 1; + let keycode = self.consumer.keycodes[slot as usize]; + data[0] = match keycode { + MEDIA_PLAY_PAUSE => 1, + MEDIA_STOP => 2, + MEDIA_PREVIOUS => 4, + MEDIA_NEXT => 8, + MEDIA_REWIND => 16, + MEDIA_FAST_FORWARD => 32, + _ => 0, + }; + } + data + } + fn pointer_poll(&mut self) -> Vec { let index = self.head; if self.num != 0 { @@ -403,6 +466,11 @@ impl Hid { .clone_from_slice(&KEYBOARD_REPORT_DESCRIPTOR[..]); packet.actual_length = KEYBOARD_REPORT_DESCRIPTOR.len() as u32; } + HidType::Consumer => { + data[..CONSUMER_REPORT_DESCRIPTOR.len()] + .clone_from_slice(&CONSUMER_REPORT_DESCRIPTOR[..]); + packet.actual_length = CONSUMER_REPORT_DESCRIPTOR.len() as u32; + } _ => { error!("Unknown HID type"); packet.status = UsbPacketStatus::Stall; @@ -438,6 +506,11 @@ impl Hid { data[0..buf.len()].copy_from_slice(buf.as_slice()); packet.actual_length = buf.len() as u32; } + HidType::Consumer => { + let buf = self.consumer_poll(); + data[0..buf.len()].copy_from_slice(buf.as_slice()); + packet.actual_length = buf.len() as u32; + } _ => { error!("Unsupported HID type for report"); packet.status = UsbPacketStatus::Stall; @@ -516,6 +589,9 @@ impl Hid { HidType::Tablet => { buf = self.pointer_poll(); } + HidType::Consumer => { + buf = self.consumer_poll(); + } _ => { error!("Unsupported HID device"); p.status = UsbPacketStatus::Stall; diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index 110152b8..21f9d7bb 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -20,6 +20,8 @@ pub mod hid; pub mod keyboard; pub mod storage; pub mod tablet; +#[cfg(feature = "usb_consumer")] +pub mod consumer; #[cfg(feature = "usb_uas")] pub mod uas; #[cfg(feature = "usb_host")] diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index 483cf9c4..44a3c46c 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -955,6 +955,20 @@ Three properties can be set for USB Uas. Note: "aio=off,direct=false" must be configured and other aio/direct values are not supported. +#### 2.13.8 USB Consumer +The USB consumer is a consumer that uses the USB protocol. It should be attached to USB controller. + +One property can be set for USB Consumer. + +* id: unique device id. + +```shell +-device usb-consumer,id= +``` + +Note: Only one consumer can be configured. + + ### 2.14 Virtio Scsi Controller Virtio Scsi controller is a pci device which can be attached scsi device. diff --git a/machine/Cargo.toml b/machine/Cargo.toml index ecead47e..4863aa15 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -52,6 +52,7 @@ ramfb = ["devices/ramfb", "machine_manager/ramfb"] virtio_gpu = ["virtio/virtio_gpu", "machine_manager/virtio_gpu"] vfio_device = ["vfio", "hypervisor/vfio_device"] usb_uas = ["devices/usb_uas"] +usb_consumer = ["devices/usb_consumer"] virtio_rng = ["virtio/virtio_rng"] virtio_scsi = ["virtio/virtio_scsi"] vhost_vsock = ["virtio/vhost_vsock"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 7b37ac7c..b6b38833 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -76,6 +76,8 @@ use devices::usb::camera::{UsbCamera, UsbCameraConfig}; use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; use devices::usb::storage::{UsbStorage, UsbStorageConfig}; use devices::usb::tablet::{UsbTablet, UsbTabletConfig}; +#[cfg(feature = "usb_consumer")] +use devices::usb::consumer::{UsbConsumer, UsbConsumerConfig}; #[cfg(feature = "usb_uas")] use devices::usb::uas::{UsbUas, UsbUasConfig}; #[cfg(feature = "usb_host")] @@ -1866,6 +1868,15 @@ pub trait MachineOps: MachineLifecycle { .realize() .with_context(|| "Failed to realize usb tablet device")? } + #[cfg(feature = "usb_consumer")] + "usb-consumer" => { + let config = + UsbConsumerConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let consumer = UsbConsumer::new(config); + consumer + .realize() + .with_context(|| "Failed to realize usb consumer device")? + } #[cfg(feature = "usb_camera")] "usb-camera" => { let token_id = match self.get_token_id() { @@ -2011,7 +2022,7 @@ pub trait MachineOps: MachineLifecycle { ("virtconsole" | "virtserialport", add_virtio_serial_port, vm_config, cfg_args), ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), ("nec-usb-xhci", add_usb_xhci, cfg_args), - ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); + ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-consumer" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); #[cfg(feature = "vhostuser_block")] ("vhost-user-blk-device",add_vhost_user_blk_device, vm_config, cfg_args), #[cfg(feature = "vhostuser_block")] diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index a9409012..ed5fe003 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1278,7 +1278,7 @@ impl DeviceInterface for StdMachine { ); } } - "usb-kbd" | "usb-tablet" | "usb-camera" | "usb-host" | "usb-storage" | "usb-uas" => { + "usb-kbd" | "usb-tablet" | "usb-consumer" |"usb-camera" | "usb-host" | "usb-storage" | "usb-uas" => { let cfg_args = locked_vmconfig.add_device_config(args.as_ref()); if let Err(e) = self.add_usb_device(&mut vm_config_clone, &cfg_args) { error!("{:?}", e); diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index b056b571..10922132 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -256,6 +256,7 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { \n\t\tadd usb controller: -device nec-usb-xhci,id=,bus=,addr=<0xa>; \ \n\t\tadd usb keyboard: -device usb-kbd,id=; \ \n\t\tadd usb tablet: -device usb-tablet,id=; \ + \n\t\tadd usb consumer: -device usb-consumer,id=; \ \n\t\tadd usb storage: -device usb-storage,id=,drive=; \ \n\t\tadd scsi controller: -device virtio-scsi-pci,id=,bus=,addr=<0x3>[,multifunction=on|off][,iothread=][,num-queues=]; \ \n\t\tadd scsi hard disk: -device scsi-hd,scsi-id=<0>,bus=,lun=<0>,drive=,id=; \ diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs index f23acb51..3b684513 100644 --- a/machine_manager/src/machine.rs +++ b/machine_manager/src/machine.rs @@ -363,6 +363,7 @@ pub trait DeviceInterface { ("nec-usb-xhci", "base-xhci"), ("usb-tablet", "usb-hid"), ("usb-kbd", "usb-hid"), + ("usb-consumer", "usb-hid"), ("usb-storage", "usb-storage-dev"), ("virtio-gpu-pci", "virtio-gpu"), ]; diff --git a/trace/trace_info/usb.toml b/trace/trace_info/usb.toml index 9defe6d2..2c678ad5 100644 --- a/trace/trace_info/usb.toml +++ b/trace/trace_info/usb.toml @@ -358,6 +358,18 @@ args = "hid_code: &dyn fmt::Debug, index: &dyn fmt::Debug, key: &dyn fmt::Debug" message = "hid_code {:?} index {:?} key {:?}" enabled = true +[[events]] +name = "usb_consumer_event" +args = "keycode: &dyn fmt::Debug, down: &dyn fmt::Debug" +message = "do consumer event keycode={:?} down={:?}" +enabled = true + +[[events]] +name = "usb_consumer_queue_full" +args = "" +message = "consumer queue is full" +enabled = true + [[events]] name = "usb_no_data_in_usb_device" args = "" diff --git a/ui/src/input.rs b/ui/src/input.rs index 6f1e10c7..ae7f5f9d 100644 --- a/ui/src/input.rs +++ b/ui/src/input.rs @@ -68,6 +68,16 @@ pub const NUM_LOCK_LED: u8 = 0x1; pub const CAPS_LOCK_LED: u8 = 0x2; pub const SCROLL_LOCK_LED: u8 = 0x4; +// consumer +pub const CONSUMER_PREFIX: u16 = 0xe000; +pub const CONSUMER_UP: u16 = 0x0100; +pub const MEDIA_PLAY_PAUSE: u16 = 0xe022; +pub const MEDIA_STOP: u16 = 0xe024; +pub const MEDIA_PREVIOUS: u16 = 0xe010; +pub const MEDIA_NEXT: u16 = 0xe019; +pub const MEDIA_REWIND: u16 = 0xe011; // None-Microsoft Official, customer +pub const MEDIA_FAST_FORWARD: u16 = 0xe012; // None-Microsoft Official, customer + static INPUTS: Lazy>> = Lazy::new(|| Arc::new(Mutex::new(Inputs::default()))); static LED_STATE: Lazy>> = @@ -258,6 +268,8 @@ struct Inputs { kbd_lists: HashMap>>, tablet_ids: Vec, tablet_lists: HashMap>>, + consumer_ids: Vec, + consumer_lists: HashMap>>, keyboard_state: KeyBoardState, btn_state: u32, } @@ -295,6 +307,22 @@ impl Inputs { } } + fn register_consumer(&mut self, device: &str, consumer: Arc>) { + self.consumer_ids.insert(0, device.to_string()); + self.consumer_lists.insert(device.to_string(), consumer); + } + + fn unregister_consumer(&mut self, device: &str) { + self.consumer_lists.remove(device); + let len = self.consumer_ids.len(); + for i in 0..len { + if self.consumer_ids[i] == device { + self.consumer_ids.remove(i); + break; + } + } + } + fn get_active_kbd(&mut self) -> Option>> { if !self.kbd_ids.is_empty() { let kbd = self.kbd_lists.get(&self.kbd_ids[0])?.clone(); @@ -304,6 +332,15 @@ impl Inputs { } } + fn get_active_consumer(&mut self) -> Option>> { + if !self.consumer_ids.is_empty() { + let consumer = self.consumer_lists.get(&self.consumer_ids[0])?.clone(); + Some(consumer) + } else { + None + } + } + fn get_active_mouse(&mut self) -> Option>> { if !self.tablet_ids.is_empty() { let mouse = self.tablet_lists.get(&self.tablet_ids[0])?.clone(); @@ -351,6 +388,14 @@ pub fn unregister_pointer(device: &str) { INPUTS.lock().unwrap().unregister_mouse(device); } +pub fn register_consumer(device: &str, consumer: Arc>) { + INPUTS.lock().unwrap().register_consumer(device, consumer); +} + +pub fn unregister_consumer(device: &str) { + INPUTS.lock().unwrap().unregister_consumer(device); +} + pub fn input_move_abs(axis: Axis, data: u32) -> Result<()> { let mut input_event = InputEvent::new(InputType::MoveEvent); let move_event = MoveEvent { axis, data }; @@ -408,6 +453,14 @@ pub fn key_event(keycode: u16, down: bool) -> Result<()> { Ok(()) } +pub fn consumer_event(keycode: u16, down: bool) -> Result<()> { + let consumer = INPUTS.lock().unwrap().get_active_consumer(); + if let Some(c) = consumer { + c.lock().unwrap().do_consumer_event(keycode, down)?; + } + Ok(()) +} + pub fn trigger_key(keycode: u16) -> Result<()> { key_event(keycode, true)?; key_event(keycode, false) @@ -517,6 +570,10 @@ pub trait PointerOpts: Send { fn sync(&mut self) -> Result<()>; } +pub trait ConsumerOpts: Send { + fn do_consumer_event(&mut self, keycode: u16, down: bool) -> Result<()>; +} + #[cfg(test)] mod tests { use anyhow::bail; diff --git a/ui/src/keycode.rs b/ui/src/keycode.rs index 16db2dbd..30aeac93 100644 --- a/ui/src/keycode.rs +++ b/ui/src/keycode.rs @@ -10,6 +10,8 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use crate::input::{MEDIA_FAST_FORWARD, MEDIA_NEXT, MEDIA_PLAY_PAUSE, MEDIA_PREVIOUS, + MEDIA_REWIND, MEDIA_STOP}; use std::collections::HashMap; pub enum DpyMod { @@ -198,6 +200,12 @@ pub enum KeyCode { MetaL, MetaR, Brokenbar, + MediaPlayPause, + MediaStop, + MediaPrevious, + MediaNext, + MediaRewind, + MediaFastForward, } impl KeyCode { @@ -326,56 +334,62 @@ impl KeyCode { KeyCode::SuperL => 0x00DB, KeyCode::SuperR => 0x00DC, KeyCode::Menu => 0x00DD, - KeyCode::Exclam => 0x0102, // Shift 1 - KeyCode::At => 0x0103, // Shift 2 - KeyCode::Numbersign => 0x0104, // Shift 3 - KeyCode::Dollar => 0x0105, // Shift 4 - KeyCode::Percent => 0x0106, // Shift 5 - KeyCode::Asciicircum => 0x0107, // Shift 6 - KeyCode::Ampersand => 0x0108, // Shift 7 - KeyCode::Asterisk => 0x0109, // Shift 8 - KeyCode::Parenleft => 0x010A, // Shift 9 - KeyCode::Parenright => 0x010B, // Shift 0 - KeyCode::Underscore => 0x010C, // Shift Minus - KeyCode::Plus => 0x010D, // Shift Equal - KeyCode::KeyQ => 0x0110, // Shift q - KeyCode::KeyW => 0x0111, // Shift w - KeyCode::KeyE => 0x0112, // Shift e - KeyCode::KeyR => 0x0113, // Shift r - KeyCode::KeyT => 0x0114, // Shift t - KeyCode::KeyY => 0x0115, // Shift y - KeyCode::KeyU => 0x0116, // Shift u - KeyCode::KeyI => 0x0117, // Shift i - KeyCode::KeyO => 0x0118, // Shift o - KeyCode::KeyP => 0x0119, // Shift p - KeyCode::Braceleft => 0x011A, // Shift Bracketleft - KeyCode::Braceright => 0x011B, // Shift Bracketright - KeyCode::KeyA => 0x011E, // Shift a - KeyCode::KeyS => 0x011F, // Shift s - KeyCode::KeyD => 0x0120, // Shift d - KeyCode::KeyF => 0x0121, // Shift f - KeyCode::KeyG => 0x0122, // Shift g - KeyCode::KeyH => 0x0123, // Shift h - KeyCode::KeyJ => 0x0124, // Shift j - KeyCode::KeyK => 0x0125, // Shift k - KeyCode::KeyL => 0x0126, // Shift l - KeyCode::Colon => 0x0127, // Shift Semicolon - KeyCode::Quotedbl => 0x0128, // Shift Apostrophe - KeyCode::Asciitilde => 0x0129, // Shift Grave - KeyCode::Bar => 0x012B, // Shift Backslash - KeyCode::KeyZ => 0x012C, // Shift z - KeyCode::KeyX => 0x012D, // Shift x - KeyCode::KeyC => 0x012E, // Shift c - KeyCode::KeyV => 0x012F, // Shift v - KeyCode::KeyB => 0x0130, // Shift b - KeyCode::KeyN => 0x0131, // Shift n - KeyCode::KeyM => 0x0132, // Shift m - KeyCode::Less => 0x0133, // Shift Comma - KeyCode::Greater => 0x0134, // Shift Period - KeyCode::Question => 0x0135, // Shift Slash - KeyCode::MetaL => 0x0138, // Shift AltL - KeyCode::MetaR => 0x01B8, // Shift AltR - KeyCode::Brokenbar => 0x0956, // Shift Altgr Less + KeyCode::Exclam => 0x0102, // Shift 1 + KeyCode::At => 0x0103, // Shift 2 + KeyCode::Numbersign => 0x0104, // Shift 3 + KeyCode::Dollar => 0x0105, // Shift 4 + KeyCode::Percent => 0x0106, // Shift 5 + KeyCode::Asciicircum => 0x0107, // Shift 6 + KeyCode::Ampersand => 0x0108, // Shift 7 + KeyCode::Asterisk => 0x0109, // Shift 8 + KeyCode::Parenleft => 0x010A, // Shift 9 + KeyCode::Parenright => 0x010B, // Shift 0 + KeyCode::Underscore => 0x010C, // Shift Minus + KeyCode::Plus => 0x010D, // Shift Equal + KeyCode::KeyQ => 0x0110, // Shift q + KeyCode::KeyW => 0x0111, // Shift w + KeyCode::KeyE => 0x0112, // Shift e + KeyCode::KeyR => 0x0113, // Shift r + KeyCode::KeyT => 0x0114, // Shift t + KeyCode::KeyY => 0x0115, // Shift y + KeyCode::KeyU => 0x0116, // Shift u + KeyCode::KeyI => 0x0117, // Shift i + KeyCode::KeyO => 0x0118, // Shift o + KeyCode::KeyP => 0x0119, // Shift p + KeyCode::Braceleft => 0x011A, // Shift Bracketleft + KeyCode::Braceright => 0x011B, // Shift Bracketright + KeyCode::KeyA => 0x011E, // Shift a + KeyCode::KeyS => 0x011F, // Shift s + KeyCode::KeyD => 0x0120, // Shift d + KeyCode::KeyF => 0x0121, // Shift f + KeyCode::KeyG => 0x0122, // Shift g + KeyCode::KeyH => 0x0123, // Shift h + KeyCode::KeyJ => 0x0124, // Shift j + KeyCode::KeyK => 0x0125, // Shift k + KeyCode::KeyL => 0x0126, // Shift l + KeyCode::Colon => 0x0127, // Shift Semicolon + KeyCode::Quotedbl => 0x0128, // Shift Apostrophe + KeyCode::Asciitilde => 0x0129, // Shift Grave + KeyCode::Bar => 0x012B, // Shift Backslash + KeyCode::KeyZ => 0x012C, // Shift z + KeyCode::KeyX => 0x012D, // Shift x + KeyCode::KeyC => 0x012E, // Shift c + KeyCode::KeyV => 0x012F, // Shift v + KeyCode::KeyB => 0x0130, // Shift b + KeyCode::KeyN => 0x0131, // Shift n + KeyCode::KeyM => 0x0132, // Shift m + KeyCode::Less => 0x0133, // Shift Comma + KeyCode::Greater => 0x0134, // Shift Period + KeyCode::Question => 0x0135, // Shift Slash + KeyCode::MetaL => 0x0138, // Shift AltL + KeyCode::MetaR => 0x01B8, // Shift AltR + KeyCode::Brokenbar => 0x0956, // Shift Altgr Less + Keycode::MediaPlayPause => MEDIA_PLAY_PAUSE, // Play/Pause + Keycode::MediaStop => MEDIA_STOP, // Stop + Keycode::MediaPrevious => MEDIA_PREVIOUS, // Scan Previous Track + Keycode::MediaNext => MEDIA_NEXT, // Scan Next Track + Keycode::MediaRewind => MEDIA_REWIND, // Rewind + Keycode::MediaFastFoward => MEDIA_FAST_FORWARD, // Fast Forward } } @@ -397,7 +411,13 @@ impl KeyCode { } #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] -const KEY_CODE_OH: [(KeyCode, u16); 105] = [ +const KEY_CODE_OH: [(KeyCode, u16); 111] = [ + (KeyCode::MediaPlayPause, 0x000A), + (KeyCode::MediaStop, 0x000B), + (KeyCode::MediaPrevious, 0x000C), + (KeyCode::MediaNext, 0x000D), + (KeyCode::MediaRewind, 0x000E), + (KeyCode::MediaFastForward, 0x000F), (KeyCode::Key0, 0x07D0), (KeyCode::Key1, 0x07D1), (KeyCode::Key2, 0x07D2), diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 18ec699c..9c9d3ebc 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -31,7 +31,7 @@ use crate::{ INPUT_BUTTON_WHEEL_DOWN, INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, INPUT_POINT_FORWARD, INPUT_POINT_LEFT, INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, - KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, + KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, CONSUMER_PREFIX, }, keycode::{DpyMod, KeyCode}, }; @@ -88,15 +88,20 @@ impl WindowState { fn do_key_action(&self, keycode: u16, action: u16) -> Result<()> { let press = action != 0; - keyboard_update(press, keycode)?; - input::key_event(keycode, press).map_err(|e| { - anyhow!( + if keycode & CONSUMER_PREFIX == CONSUMER_PREFIX { + input::consumer_event(keycode, press).map_err(|e| anyhow!( + "do consumer event failed: code: {}, action: {}, {:?}", keycode, press, e)); + } else { + keyboard_update(press, keycode)?; + input::key_event(keycode, press).map_err(|e| { + anyhow!( "do key event failed: code: {}, action: {}, {:?}", keycode, press, e ) - }) + }) + } } fn move_pointer(&mut self, x: f64, y: f64) -> Result<()> { -- Gitee From eb1dbe582f3fce2c9813ebb8c0b4d503561d56f8 Mon Sep 17 00:00:00 2001 From: liye Date: Wed, 6 Aug 2025 10:57:00 +0800 Subject: [PATCH 2/5] add wire control --- devices/src/usb/consumer.rs | 4 +- devices/src/usb/hid.rs | 2 +- ui/src/keycode.rs | 117 ++++++++++++++++++------------------ 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/devices/src/usb/consumer.rs b/devices/src/usb/consumer.rs index e17f306c..9b3e976d 100644 --- a/devices/src/usb/consumer.rs +++ b/devices/src/usb/consumer.rs @@ -25,7 +25,7 @@ use super::hid::{Hid, HidType, CONSUMER_REPORT_DESCRIPTOR, QUEUE_LENGTH, QUEUE_M use super::xhci::xhci_controller::{endpoint_number_to_id, XhciDevice}; use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; use super::{ - notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, + notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus, }; use machine_manager::config::valid_id; @@ -191,7 +191,7 @@ impl UsbDevice for UsbConsumer { })); register_consumer(&id, consumer_adapter); - Ok(consumer_adapter) + Ok(consumer) } fn unrealize(&mut self) -> Result<()> { diff --git a/devices/src/usb/hid.rs b/devices/src/usb/hid.rs index 14d6b8a8..78260fb0 100644 --- a/devices/src/usb/hid.rs +++ b/devices/src/usb/hid.rs @@ -154,7 +154,7 @@ const KEYBOARD_REPORT_DESCRIPTOR: [u8; 63] = [ ]; /// consumer report descriptor -const CONSUMER_REPORT_DESCRIPTOR: &[u8] = &[ +pub const CONSUMER_REPORT_DESCRIPTOR: &[u8] = &[ 0x05, 0x0C, // Usage Page (Consumer) 0x09, 0x01, // Usage (Consumer Control) 0xa1, 0x01, // Collection (Application) diff --git a/ui/src/keycode.rs b/ui/src/keycode.rs index 30aeac93..d3ac4677 100644 --- a/ui/src/keycode.rs +++ b/ui/src/keycode.rs @@ -10,8 +10,9 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use crate::input::{MEDIA_FAST_FORWARD, MEDIA_NEXT, MEDIA_PLAY_PAUSE, MEDIA_PREVIOUS, - MEDIA_REWIND, MEDIA_STOP}; +use crate::input::{ + MEDIA_FAST_FORWARD, MEDIA_NEXT, MEDIA_PLAY_PAUSE, MEDIA_PREVIOUS, MEDIA_REWIND, MEDIA_STOP, +}; use std::collections::HashMap; pub enum DpyMod { @@ -334,62 +335,62 @@ impl KeyCode { KeyCode::SuperL => 0x00DB, KeyCode::SuperR => 0x00DC, KeyCode::Menu => 0x00DD, - KeyCode::Exclam => 0x0102, // Shift 1 - KeyCode::At => 0x0103, // Shift 2 - KeyCode::Numbersign => 0x0104, // Shift 3 - KeyCode::Dollar => 0x0105, // Shift 4 - KeyCode::Percent => 0x0106, // Shift 5 - KeyCode::Asciicircum => 0x0107, // Shift 6 - KeyCode::Ampersand => 0x0108, // Shift 7 - KeyCode::Asterisk => 0x0109, // Shift 8 - KeyCode::Parenleft => 0x010A, // Shift 9 - KeyCode::Parenright => 0x010B, // Shift 0 - KeyCode::Underscore => 0x010C, // Shift Minus - KeyCode::Plus => 0x010D, // Shift Equal - KeyCode::KeyQ => 0x0110, // Shift q - KeyCode::KeyW => 0x0111, // Shift w - KeyCode::KeyE => 0x0112, // Shift e - KeyCode::KeyR => 0x0113, // Shift r - KeyCode::KeyT => 0x0114, // Shift t - KeyCode::KeyY => 0x0115, // Shift y - KeyCode::KeyU => 0x0116, // Shift u - KeyCode::KeyI => 0x0117, // Shift i - KeyCode::KeyO => 0x0118, // Shift o - KeyCode::KeyP => 0x0119, // Shift p - KeyCode::Braceleft => 0x011A, // Shift Bracketleft - KeyCode::Braceright => 0x011B, // Shift Bracketright - KeyCode::KeyA => 0x011E, // Shift a - KeyCode::KeyS => 0x011F, // Shift s - KeyCode::KeyD => 0x0120, // Shift d - KeyCode::KeyF => 0x0121, // Shift f - KeyCode::KeyG => 0x0122, // Shift g - KeyCode::KeyH => 0x0123, // Shift h - KeyCode::KeyJ => 0x0124, // Shift j - KeyCode::KeyK => 0x0125, // Shift k - KeyCode::KeyL => 0x0126, // Shift l - KeyCode::Colon => 0x0127, // Shift Semicolon - KeyCode::Quotedbl => 0x0128, // Shift Apostrophe - KeyCode::Asciitilde => 0x0129, // Shift Grave - KeyCode::Bar => 0x012B, // Shift Backslash - KeyCode::KeyZ => 0x012C, // Shift z - KeyCode::KeyX => 0x012D, // Shift x - KeyCode::KeyC => 0x012E, // Shift c - KeyCode::KeyV => 0x012F, // Shift v - KeyCode::KeyB => 0x0130, // Shift b - KeyCode::KeyN => 0x0131, // Shift n - KeyCode::KeyM => 0x0132, // Shift m - KeyCode::Less => 0x0133, // Shift Comma - KeyCode::Greater => 0x0134, // Shift Period - KeyCode::Question => 0x0135, // Shift Slash - KeyCode::MetaL => 0x0138, // Shift AltL - KeyCode::MetaR => 0x01B8, // Shift AltR - KeyCode::Brokenbar => 0x0956, // Shift Altgr Less - Keycode::MediaPlayPause => MEDIA_PLAY_PAUSE, // Play/Pause - Keycode::MediaStop => MEDIA_STOP, // Stop - Keycode::MediaPrevious => MEDIA_PREVIOUS, // Scan Previous Track - Keycode::MediaNext => MEDIA_NEXT, // Scan Next Track - Keycode::MediaRewind => MEDIA_REWIND, // Rewind - Keycode::MediaFastFoward => MEDIA_FAST_FORWARD, // Fast Forward + KeyCode::Exclam => 0x0102, // Shift 1 + KeyCode::At => 0x0103, // Shift 2 + KeyCode::Numbersign => 0x0104, // Shift 3 + KeyCode::Dollar => 0x0105, // Shift 4 + KeyCode::Percent => 0x0106, // Shift 5 + KeyCode::Asciicircum => 0x0107, // Shift 6 + KeyCode::Ampersand => 0x0108, // Shift 7 + KeyCode::Asterisk => 0x0109, // Shift 8 + KeyCode::Parenleft => 0x010A, // Shift 9 + KeyCode::Parenright => 0x010B, // Shift 0 + KeyCode::Underscore => 0x010C, // Shift Minus + KeyCode::Plus => 0x010D, // Shift Equal + KeyCode::KeyQ => 0x0110, // Shift q + KeyCode::KeyW => 0x0111, // Shift w + KeyCode::KeyE => 0x0112, // Shift e + KeyCode::KeyR => 0x0113, // Shift r + KeyCode::KeyT => 0x0114, // Shift t + KeyCode::KeyY => 0x0115, // Shift y + KeyCode::KeyU => 0x0116, // Shift u + KeyCode::KeyI => 0x0117, // Shift i + KeyCode::KeyO => 0x0118, // Shift o + KeyCode::KeyP => 0x0119, // Shift p + KeyCode::Braceleft => 0x011A, // Shift Bracketleft + KeyCode::Braceright => 0x011B, // Shift Bracketright + KeyCode::KeyA => 0x011E, // Shift a + KeyCode::KeyS => 0x011F, // Shift s + KeyCode::KeyD => 0x0120, // Shift d + KeyCode::KeyF => 0x0121, // Shift f + KeyCode::KeyG => 0x0122, // Shift g + KeyCode::KeyH => 0x0123, // Shift h + KeyCode::KeyJ => 0x0124, // Shift j + KeyCode::KeyK => 0x0125, // Shift k + KeyCode::KeyL => 0x0126, // Shift l + KeyCode::Colon => 0x0127, // Shift Semicolon + KeyCode::Quotedbl => 0x0128, // Shift Apostrophe + KeyCode::Asciitilde => 0x0129, // Shift Grave + KeyCode::Bar => 0x012B, // Shift Backslash + KeyCode::KeyZ => 0x012C, // Shift z + KeyCode::KeyX => 0x012D, // Shift x + KeyCode::KeyC => 0x012E, // Shift c + KeyCode::KeyV => 0x012F, // Shift v + KeyCode::KeyB => 0x0130, // Shift b + KeyCode::KeyN => 0x0131, // Shift n + KeyCode::KeyM => 0x0132, // Shift m + KeyCode::Less => 0x0133, // Shift Comma + KeyCode::Greater => 0x0134, // Shift Period + KeyCode::Question => 0x0135, // Shift Slash + KeyCode::MetaL => 0x0138, // Shift AltL + KeyCode::MetaR => 0x01B8, // Shift AltR + KeyCode::Brokenbar => 0x0956, // Shift Altgr Less + KeyCode::MediaPlayPause => MEDIA_PLAY_PAUSE, // Play/Pause + KeyCode::MediaStop => MEDIA_STOP, // Stop + KeyCode::MediaPrevious => MEDIA_PREVIOUS, // Scan Previous Track + KeyCode::MediaNext => MEDIA_NEXT, // Scan Next Track + KeyCode::MediaRewind => MEDIA_REWIND, // Rewind + KeyCode::MediaFastForward => MEDIA_FAST_FORWARD, // Fast Forward } } -- Gitee From 20129cc1fb6aec805a0b131bd51bd856d397e278 Mon Sep 17 00:00:00 2001 From: liye Date: Wed, 6 Aug 2025 15:45:09 +0800 Subject: [PATCH 3/5] add wire control: fmt --- devices/src/usb/consumer.rs | 15 ++++++++++++--- devices/src/usb/hid.rs | 6 ++++-- devices/src/usb/mod.rs | 4 ++-- machine/src/lib.rs | 4 ++-- machine/src/standard_common/mod.rs | 3 ++- ui/src/ohui_srv/msg_handle.rs | 28 +++++++++++++++++----------- 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/devices/src/usb/consumer.rs b/devices/src/usb/consumer.rs index 9b3e976d..49082ad8 100644 --- a/devices/src/usb/consumer.rs +++ b/devices/src/usb/consumer.rs @@ -25,8 +25,7 @@ use super::hid::{Hid, HidType, CONSUMER_REPORT_DESCRIPTOR, QUEUE_LENGTH, QUEUE_M use super::xhci::xhci_controller::{endpoint_number_to_id, XhciDevice}; use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; use super::{ - notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, - UsbPacketStatus, + notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus, }; use machine_manager::config::valid_id; use ui::input::{register_consumer, unregister_consumer, ConsumerOpts, CONSUMER_UP}; @@ -83,7 +82,17 @@ static DESC_IFACE_CONSUMER: Lazy> = Lazy::new(|| { }, other_desc: vec![Arc::new(UsbDescOther { // HID descriptor - data: vec![0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, CONSUMER_REPORT_DESCRIPTOR.len() as u8, 0], + data: vec![ + 0x09, + 0x21, + 0x11, + 0x01, + 0x00, + 0x01, + 0x22, + CONSUMER_REPORT_DESCRIPTOR.len() as u8, + 0, + ], })], endpoints: vec![Arc::new(UsbDescEndpoint { endpoint_desc: UsbEndpointDescriptor { diff --git a/devices/src/usb/hid.rs b/devices/src/usb/hid.rs index 78260fb0..7dd1fb0a 100644 --- a/devices/src/usb/hid.rs +++ b/devices/src/usb/hid.rs @@ -16,8 +16,10 @@ use log::error; use super::config::*; use super::{UsbDeviceRequest, UsbPacket, UsbPacketStatus}; -use ui::input::{set_kbd_led_state, MEDIA_FAST_FORWARD, MEDIA_NEXT, MEDIA_PLAY_PAUSE, MEDIA_PREVIOUS, - MEDIA_REWIND, MEDIA_STOP}; +use ui::input::{ + set_kbd_led_state, MEDIA_FAST_FORWARD, MEDIA_NEXT, MEDIA_PLAY_PAUSE, MEDIA_PREVIOUS, + MEDIA_REWIND, MEDIA_STOP, +}; /// HID keycode const HID_KEYBOARD_LEFT_CONTROL: u8 = 0xe0; diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index 21f9d7bb..5f7fb3e1 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -15,13 +15,13 @@ pub mod camera; #[cfg(feature = "usb_camera")] pub mod camera_media_type_guid; pub mod config; +#[cfg(feature = "usb_consumer")] +pub mod consumer; pub mod error; pub mod hid; pub mod keyboard; pub mod storage; pub mod tablet; -#[cfg(feature = "usb_consumer")] -pub mod consumer; #[cfg(feature = "usb_uas")] pub mod uas; #[cfg(feature = "usb_host")] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index b6b38833..ef2ff182 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -73,11 +73,11 @@ use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; use devices::sysbus::{devices_register_sysbusdevops_type, to_sysbusdevops, SysBus, SysBusDevType}; #[cfg(feature = "usb_camera")] use devices::usb::camera::{UsbCamera, UsbCameraConfig}; +#[cfg(feature = "usb_consumer")] +use devices::usb::consumer::{UsbConsumer, UsbConsumerConfig}; use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; use devices::usb::storage::{UsbStorage, UsbStorageConfig}; use devices::usb::tablet::{UsbTablet, UsbTabletConfig}; -#[cfg(feature = "usb_consumer")] -use devices::usb::consumer::{UsbConsumer, UsbConsumerConfig}; #[cfg(feature = "usb_uas")] use devices::usb::uas::{UsbUas, UsbUasConfig}; #[cfg(feature = "usb_host")] diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index ed5fe003..4f44cf87 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1278,7 +1278,8 @@ impl DeviceInterface for StdMachine { ); } } - "usb-kbd" | "usb-tablet" | "usb-consumer" |"usb-camera" | "usb-host" | "usb-storage" | "usb-uas" => { + "usb-kbd" | "usb-tablet" | "usb-consumer" | "usb-camera" | "usb-host" + | "usb-storage" | "usb-uas" => { let cfg_args = locked_vmconfig.add_device_config(args.as_ref()); if let Err(e) = self.add_usb_device(&mut vm_config_clone, &cfg_args) { error!("{:?}", e); diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 9c9d3ebc..b371526b 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -28,10 +28,10 @@ use crate::{ input::{ self, get_kbd_led_state, input_button, input_move_abs, input_point_sync, keyboard_update, release_all_btn, release_all_key, trigger_key, Axis, ABS_MAX, CAPS_LOCK_LED, - INPUT_BUTTON_WHEEL_DOWN, INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, - INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, INPUT_POINT_FORWARD, INPUT_POINT_LEFT, - INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, - KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, CONSUMER_PREFIX, + CONSUMER_PREFIX, INPUT_BUTTON_WHEEL_DOWN, INPUT_BUTTON_WHEEL_LEFT, + INPUT_BUTTON_WHEEL_RIGHT, INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, INPUT_POINT_FORWARD, + INPUT_POINT_LEFT, INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, KEYCODE_CAPS_LOCK, + KEYCODE_NUM_LOCK, KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, }, keycode::{DpyMod, KeyCode}, }; @@ -89,17 +89,23 @@ impl WindowState { fn do_key_action(&self, keycode: u16, action: u16) -> Result<()> { let press = action != 0; if keycode & CONSUMER_PREFIX == CONSUMER_PREFIX { - input::consumer_event(keycode, press).map_err(|e| anyhow!( - "do consumer event failed: code: {}, action: {}, {:?}", keycode, press, e)); + input::consumer_event(keycode, press).map_err(|e| { + anyhow!( + "do consumer event failed: code: {}, action: {}, {:?}", + keycode, + press, + e + ) + }); } else { keyboard_update(press, keycode)?; input::key_event(keycode, press).map_err(|e| { anyhow!( - "do key event failed: code: {}, action: {}, {:?}", - keycode, - press, - e - ) + "do key event failed: code: {}, action: {}, {:?}", + keycode, + press, + e + ) }) } } -- Gitee From f3cb4045020126273376f9544f51e9ea0195e9d4 Mon Sep 17 00:00:00 2001 From: liye Date: Wed, 6 Aug 2025 16:12:52 +0800 Subject: [PATCH 4/5] add wire control: optimize --- devices/src/usb/consumer.rs | 2 +- devices/src/usb/hid.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/src/usb/consumer.rs b/devices/src/usb/consumer.rs index 49082ad8..1f065605 100644 --- a/devices/src/usb/consumer.rs +++ b/devices/src/usb/consumer.rs @@ -154,7 +154,7 @@ impl ConsumerOpts for UsbConsumerAdapter { let mut scan_code = keycode; if !down { - scan_code = scan_code | CONSUMER_UP; + scan_code |= CONSUMER_UP; } let mut locked_consumer = self.usb_consumer.lock().unwrap(); diff --git a/devices/src/usb/hid.rs b/devices/src/usb/hid.rs index 7dd1fb0a..5e4a951e 100644 --- a/devices/src/usb/hid.rs +++ b/devices/src/usb/hid.rs @@ -470,7 +470,7 @@ impl Hid { } HidType::Consumer => { data[..CONSUMER_REPORT_DESCRIPTOR.len()] - .clone_from_slice(&CONSUMER_REPORT_DESCRIPTOR[..]); + .clone_from_slice(&CONSUMER_REPORT_DESCRIPTOR); packet.actual_length = CONSUMER_REPORT_DESCRIPTOR.len() as u32; } _ => { -- Gitee From d78a11b671500db38eb23abcd485b557e5ec435a Mon Sep 17 00:00:00 2001 From: liye Date: Wed, 6 Aug 2025 16:21:00 +0800 Subject: [PATCH 5/5] add wire control: optimize --- devices/src/usb/hid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/usb/hid.rs b/devices/src/usb/hid.rs index 5e4a951e..cf90aea0 100644 --- a/devices/src/usb/hid.rs +++ b/devices/src/usb/hid.rs @@ -470,7 +470,7 @@ impl Hid { } HidType::Consumer => { data[..CONSUMER_REPORT_DESCRIPTOR.len()] - .clone_from_slice(&CONSUMER_REPORT_DESCRIPTOR); + .clone_from_slice(CONSUMER_REPORT_DESCRIPTOR); packet.actual_length = CONSUMER_REPORT_DESCRIPTOR.len() as u32; } _ => { -- Gitee