Rust 相關

Posted by Adam on August 24, 2022
```rust // 導入 macOS 底層事件循環的核心控制與通用模式常數 use core_foundation::runloop::{CFRunLoop, kCFRunLoopCommonModes}; // 導入處理 Quartz Window Server 滑鼠事件的所有核心組件 use core_graphics::event::{CGEvent, CGEventTap, CGEventTapLocation, CGEventTapOptions, CGEventTapPlacement, CGEventType, CGEventTapProxy}; // 處理所有滑鼠事件的回調函式 fn handler_print(_proxy: CGEventTapProxy, etype: CGEventType, ev: &CGEvent) -> Option<CGEvent> { // 標記不安全代碼塊,因為直接讀取 C 語言層級的記憶體欄位不受 Rust 安全檢查保護 unsafe { // 透過 transmute 強行將整數 4 轉為欄位類型,讀取 MouseEventDeltaX (水平位移增量) let dx = ev.get_integer_value_field(std::mem::transmute(4)); // 透過 transmute 強行將整數 5 轉為欄位類型,讀取 MouseEventDeltaY (垂直位移增量) let dy = ev.get_integer_value_field(std::mem::transmute(5)); // 透過 transmute 強行將整數 3 轉為欄位類型,讀取 MouseEventButtonNumber (按鈕編號) let btn = ev.get_integer_value_field(std::mem::transmute(3)); // 將捕獲到的事件類型、位移數據與按鈕編號格式化輸出到終端機 println!("Type: {:?} | Delta: ({:3}, {:3}) | Btn: {}", etype, dx, dy, btn); // 不安全區塊結束 } // 回傳原始事件的副本給 OS,代表我們只是觀測而不攔截,確保滑鼠功能正常 Some(ev.clone()) } // 程式進入點,負責初始化環境與啟動監聽循環 fn main() { // 定義一個向量陣列,存放我們打算攔截的特定事件類型 let events = vec![ // 右鍵按下的事件 (用於偵測滾輪啟動時機) CGEventType::RightMouseDown, // 右鍵放開的事件 (用於恢復一般模式) CGEventType::RightMouseUp, // 鼠標移動的事件 (用於獲取紅球位移數據) CGEventType::MouseMoved, // 監聽按住右鍵時的移動事件,此時系統會將位移識別為拖拽 CGEventType::RightMouseDragged, // 事件清單定義結束 ]; // 調用系統 API 建立一個 Event Tap (事件鉤子) let tap = CGEventTap::new( // 設定監聽層級在 HID (人機介面裝置),這是最接近硬體、最原始的數據源 CGEventTapLocation::HID, // 將我們的鉤子插入在處理鏈的最頂端,確保我們是第一個拿到數據的程序 CGEventTapPlacement::HeadInsertEventTap, // 使用預設選項,允許我們觀測、攔截或修改分發中的事件 CGEventTapOptions::Default, // 將定義好的監聽清單傳入,告訴 OS 我們只對這些特定訊號感興趣 events, // 指定當事件觸發時,要跳轉執行哪一個處理函式 handler_print, // 如果建立失敗則拋出錯誤訊息,這通常與 macOS 的輔助功能權限未開啟有關 ).expect("錯誤:建立 EventTap 失敗。請檢查系統設定中的輔助功能權限。"); // 標記不安全代碼塊,因為操作 RunLoop 涉及直接與系統核心執行緒交互 unsafe { // 透過 tap 的通訊埠建立一個可供事件循環監聽的來源 (Source) let loop_source = tap.mach_port.create_runloop_source(0) // 若建立來源失敗則終止,通常發生在系統資源耗盡或權限異常時 .expect("無法建立 RunLoop Source"); // 獲取當前執行緒的 RunLoop 並將建立的事件來源掛載到「通用模式」中 CFRunLoop::get_current().add_source(&loop_source, kCFRunLoopCommonModes); // 在終端機提示使用者程式已進入監控就緒狀態 println!(">>> 探測啟動!請操作木星軌跡球,按下 Ctrl+C 可停止..."); // 啟動阻塞式的事件循環,程式將在此停住並持續監聽直到被手動終止 core_foundation::runloop::CFRunLoopRun(); // 不安全區塊結束 } // main 函數結束 } ```