本文轉(zhuǎn)自(原文太雜亂,這里調(diào)整了格式及內(nèi)容):
http://enkichen.com/2018/09/12/osx-mouse-keyboard-event/
最近完成了 Mac OSX 平臺下的遠程控制功能扫步,期間找了不少資料赚窃,這里做個總結(jié)劲装,主要涉及到一下知識點:
- OSX 的事件機制
- OSX/iOS 響應(yīng)鏈者鏈
- 鼠標(biāo)事件的監(jiān)聽及模擬(鼠標(biāo)單擊蠢琳、雙擊捻爷、拖動姻僧、滾動等事件)
- 鍵盤事件的監(jiān)聽及模擬(包括組合鍵的模擬)
- Keycode 鍵盤編碼(統(tǒng)一 Windows规丽、OSX、瀏覽器端鍵盤按鍵的編碼值)
事件分發(fā)機制
在 OSX 系統(tǒng)中鼠標(biāo)和鍵盤的活動事件都會產(chǎn)生底層的系統(tǒng)事件撇贺,首先傳遞到 IOKit 框架處理后存儲到隊列中赌莺,通知 Window Server 服務(wù)層處理。Window Server 存儲到 FIFO 優(yōu)先隊列中松嘶,然后逐一轉(zhuǎn)發(fā)到當(dāng)前活動窗口或者能響應(yīng)這個事件的應(yīng)用程序去處理艘狭。
在 OSX 或者 iOS 程序中,都會有一個 Main Run Loop 的線程翠订,RunLoop 循環(huán)中會遍歷 event 消息隊列巢音,逐一分發(fā)這些事件到應(yīng)用中合適的對象去處理。具體來說就是調(diào)用 NSApp
的 sendEvent:
方法發(fā)送消息到NSWindow
尽超,NSWindow
再分發(fā)到 NSView
視圖對象官撼,由其鼠標(biāo)或鍵盤事件響應(yīng)方法去處理。
事件響應(yīng)鏈
在 OSX 和 iOS 程序中響應(yīng)者鏈?zhǔn)?Application Kit 事件處理架構(gòu)的中心機制似谁,它由一系列鏈接在一起的響應(yīng)者對象組成傲绣,事件或者動作消息可以沿著這些對象進行傳遞掠哥。如果一個響應(yīng)者對象不能處理某個事件或動作,也就是說秃诵,它不響應(yīng)那個消息龙致,或者不認識那個事件,則將該消息重新發(fā)送給鏈中的下一個響應(yīng)者顷链。消息沿著響應(yīng)者鏈向上目代、向更高級別的對象傳遞,直到最終被處理(如果最終還是沒有被處理嗤练,就會被拋棄)榛了。
事件響應(yīng)者 Responders
類為核心應(yīng)用程序架構(gòu)的三個主要模式或機制定義了一個接口:
- 它聲明了一些處理事件消息(也就是源自用戶事件的消息,比如象鼠標(biāo)點擊或按鍵按下這樣的事件)的方法煞抬。
- 它聲明了數(shù)十個處理動作消息的方法霜大,它們和標(biāo)準(zhǔn)的鍵綁定(比如那些在文本內(nèi)部移動插入點的綁定)密切相關(guān)。動作消息會被派發(fā)到目標(biāo)對象革答;如果目標(biāo)沒有被指定战坤,應(yīng)用程序會負責(zé)檢索合適的響應(yīng)者。
- 它定義了一套在應(yīng)用程序中指派和管理響應(yīng)者的方法残拐。這些響應(yīng)者組成了我們所知道的響應(yīng)者鏈途茫,即一系列響應(yīng)者,事件或動作消息在它們之間傳遞溪食,直到找到能夠?qū)λ鼈冞M行處理的對象囊卜。
當(dāng) Application Kit 在應(yīng)用程序中構(gòu)造對象時,會為每個窗口建立響應(yīng)者鏈错沃。響應(yīng)者鏈中的基本對象是NSWindow
對象及其視圖層次栅组。在視圖層次中級別較低的視圖將比級別更高的視圖優(yōu)先獲得處理事件或動作消息的機會。NSWindow
中保有一個第一響應(yīng)者的引用枢析,它通常是當(dāng)前窗口中處于選擇狀態(tài)的視圖玉掸,窗口通常把響應(yīng)消息的機會首先給它。對于事件消息醒叁,響應(yīng)者鏈通常以發(fā)生事件的窗口對應(yīng)的 NSWindow
對象作為結(jié)束司浪,雖然其它對象也可以作為下一個響應(yīng)者被加入到 NSWindow
對象的后面。
從層級上看離觀察者最近的視圖優(yōu)先響應(yīng)事件辐益,通過 view
的 hitTest
方法檢測断傲,滿足 hitTest
方法的的子視圖優(yōu)先響應(yīng)事件。
NSApplication
, NSWindow
, NSDrawer
, NSWindowController
, NSView
以及繼承于 NSView
的所有控件對象都直接或間接繼承了 Responders
類智政,所以這些類都能處理鼠標(biāo)和鍵盤事件。
iOS 程序相比于 OSX 程序會有點不一樣:
- OSX 程序可能存在多個窗口箱蝠,會有多個響應(yīng)者鏈续捂,iPhone 的應(yīng)用程序就一個窗口垦垂,所以只會有一個響應(yīng)者鏈。
- 在 iOS 程序中與加速計牙瓢、陀螺儀和磁力計相關(guān)的運動事件不遵循響應(yīng)者鏈劫拗,Core Motion 會將這些事件直接傳遞給我們指定的對象。有關(guān)更多信息矾克,可以參看 Core Motion Framework页慷。
相關(guān)類的解析說明
NSResponder
NSResponder
在這里是非常重要的一個類,其中定義了鼠標(biāo)鍵盤觸控板等多種事件胁附,這里列舉一些鼠標(biāo)跟鍵盤的主要方法:
// 鼠標(biāo)按下事件
- (void)mouseDown:(NSEvent *)event;
// 鼠標(biāo)右鍵按下事件
- (void)rightMouseDown:(NSEvent *)event;
// 鼠標(biāo)抬起事件
- (void)mouseUp:(NSEvent *)event;
// 鼠標(biāo)右鍵抬起事件
- (void)rightMouseUp:(NSEvent *)event;
// 鼠標(biāo)移動事件
- (void)mouseMoved:(NSEvent *)event;
// 鼠標(biāo)拖拽事件
- (void)mouseDragged:(NSEvent *)event;
// 鼠標(biāo)滾動事件
- (void)scrollWheel:(NSEvent *)event;
// 鼠標(biāo)右鍵拖拽事件
- (void)rightMouseDragged:(NSEvent *)event;
// 鼠標(biāo)進入監(jiān)控區(qū)域事件
- (void)mouseEntered:(NSEvent *)event;
// 鼠標(biāo)離開監(jiān)控區(qū)域事件
- (void)mouseExited:(NSEvent *)event;
// 鍵盤按下事件
- (void)keyDown:(NSEvent *)event;
// 鍵盤按下事件
- (void)keyUp:(NSEvent *)event;
// 鍵盤控制鍵的按下標(biāo)記狀態(tài)發(fā)送改變酒繁,后面用該方法來獲取控制按下事件,參考 NSEventModifierFlags 定義
- (void)flagsChanged:(NSEvent *)event;
NSResponder
除了定義基本的響應(yīng)事件外控妻,還定義了很多其他事件方法州袒。具體請參考 NSResponder.h
的頭文件定義。
NSEvent
NSEvent
類描述了事件的具體信息弓候,這里列舉跟鼠標(biāo)和鍵盤相關(guān)的一些字段的介紹:
// 事件類型
@property (readonly) NSEventType type;
// 鍵盤控制鍵的按下狀態(tài)的標(biāo)記
@property (readonly) NSEventModifierFlags modifierFlags;
// 事件的時間戳
@property (readonly) NSTimeInterval timestamp;
// 鼠標(biāo)點擊的次數(shù)(只有鼠標(biāo)事件郎哭,才可使用)
@property (readonly) NSInteger clickCount;
@property (readonly) NSInteger buttonNumber;
@property (readonly) NSInteger eventNumber;
// 壓力值
@property (readonly) float pressure;
// 鼠標(biāo)在窗口的位置
@property (readonly) NSPoint locationInWindow;
// 鼠標(biāo)滾動時。分別在 X 和 Y 軸上的偏移
@property (readonly) CGFloat scrollingDeltaX NS_AVAILABLE_MAC(10_7);
@property (readonly) CGFloat scrollingDeltaY NS_AVAILABLE_MAC(10_7);
// 鍵盤事件的字符編碼和 key code 值
@property (nullable, readonly, copy) NSString *characters;
@property (readonly) unsigned short keyCode;
NSEventType
NSEventType
類型定義了事件的具體類型菇存,如下:
typedef NS_ENUM(NSUInteger, NSEventType) { /* various types of events */
NSEventTypeLeftMouseDown = 1,
NSEventTypeLeftMouseUp = 2,
NSEventTypeRightMouseDown = 3,
NSEventTypeRightMouseUp = 4,
NSEventTypeMouseMoved = 5,
NSEventTypeLeftMouseDragged = 6,
NSEventTypeRightMouseDragged = 7,
NSEventTypeMouseEntered = 8,
NSEventTypeMouseExited = 9,
NSEventTypeKeyDown = 10,
NSEventTypeKeyUp = 11,
NSEventTypeFlagsChanged = 12,
NSEventTypeAppKitDefined = 13,
NSEventTypeSystemDefined = 14,
NSEventTypeApplicationDefined = 15,
NSEventTypePeriodic = 16,
NSEventTypeCursorUpdate = 17,
NSEventTypeScrollWheel = 22,
NSEventTypeTabletPoint = 23,
NSEventTypeTabletProximity = 24,
NSEventTypeOtherMouseDown = 25,
NSEventTypeOtherMouseUp = 26,
NSEventTypeOtherMouseDragged = 27,
/* The following event types are available on some hardware on 10.5.2 and later */
NSEventTypeGesture NS_ENUM_AVAILABLE_MAC(10_5) = 29,
NSEventTypeMagnify NS_ENUM_AVAILABLE_MAC(10_5) = 30,
NSEventTypeSwipe NS_ENUM_AVAILABLE_MAC(10_5) = 31,
NSEventTypeRotate NS_ENUM_AVAILABLE_MAC(10_5) = 18,
NSEventTypeBeginGesture NS_ENUM_AVAILABLE_MAC(10_5) = 19,
NSEventTypeEndGesture NS_ENUM_AVAILABLE_MAC(10_5) = 20,
#if __LP64__
NSEventTypeSmartMagnify NS_ENUM_AVAILABLE_MAC(10_8) = 32,
#endif
NSEventTypeQuickLook NS_ENUM_AVAILABLE_MAC(10_8) = 33,
#if __LP64__
NSEventTypePressure NS_ENUM_AVAILABLE_MAC(10_10_3) = 34,
NSEventTypeDirectTouch NS_ENUM_AVAILABLE_MAC(10_10) = 37,
#endif
};
NSEventModifierFlags
NSEventModifierFlags
類型描述了一些控制鍵夸研,是否處于按下狀態(tài),定義如下:
/* Device-independent bits found in event modifier flags */
typedef NS_OPTIONS(NSUInteger, NSEventModifierFlags) {
NSEventModifierFlagCapsLock = 1 << 16, // Set if Caps Lock key is pressed.
NSEventModifierFlagShift = 1 << 17, // Set if Shift key is pressed.
NSEventModifierFlagControl = 1 << 18, // Set if Control key is pressed.
NSEventModifierFlagOption = 1 << 19, // Set if Option or Alternate key is pressed.
NSEventModifierFlagCommand = 1 << 20, // Set if Command key is pressed.
NSEventModifierFlagNumericPad = 1 << 21, // Set if any key in the numeric keypad is pressed.
NSEventModifierFlagHelp = 1 << 22, // Set if the Help key is pressed.
NSEventModifierFlagFunction = 1 << 23, // Set if any function key is pressed.
// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information.
NSEventModifierFlagDeviceIndependentFlagsMask = 0xffff0000UL
};
事件的監(jiān)聽方法
鼠標(biāo)鍵盤事件的監(jiān)聽有多種方法依鸥,第一種方法是重寫事件響應(yīng)者 Responders
對應(yīng)的方法來獲取對應(yīng)的事件陈惰;第二是通過重寫 NSWindow
的 sendEvent:
方法; 第三是通過的 NSEvent
提供靜態(tài)方法來監(jiān)聽對應(yīng)的事件:
+ (nullable id)addGlobalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(void (^)(NSEvent*))block`
+ (nullable id)addLocalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(NSEvent* __nullable (^)(NSEvent*))block
+ (void)removeMonitor:(id)eventMonitor
NSEvent
提供的靜態(tài)方法可以用監(jiān)聽整個系統(tǒng)的事件或者當(dāng)前應(yīng)用程序內(nèi)的事件毕籽。全局事件是異步過程因此無法修改事件抬闯,應(yīng)用程序內(nèi)的消息可以在捕獲到消息后,修改事件然后繼續(xù)交由響應(yīng)者鏈中下一個響應(yīng)者處理关筒。
鼠標(biāo)事件監(jiān)聽
這里介紹鼠標(biāo)的一下事件處理方法和注意事項:
- 左/右鍵的按下抬起事件
- 左鍵的雙擊(或者多擊事件)
- 左鍵或者右鍵的拖拽事件
- 鼠標(biāo)移動事件
- 鼠標(biāo)的滾動事件
前面介紹了三種監(jiān)聽事件的方法溶握,這里使用重寫 Responders
的方法來監(jiān)聽鼠標(biāo)事件:
- (void)mouseDown:(NSEvent *)event;
- (void)rightMouseDown:(NSEvent *)event;
- (void)mouseUp:(NSEvent *)event;
- (void)rightMouseUp:(NSEvent *)event;
- (void)mouseMoved:(NSEvent *)event;
- (void)mouseDragged:(NSEvent *)event;
- (void)rightMouseDragged:(NSEvent *)event;
- (void)scrollWheel:(NSEvent *)event;
鼠標(biāo)按鍵的按下抬起事件,只要判斷一下 NSEvent
的 type
屬性即可知道蒸播。
當(dāng)前鼠標(biāo)的位置信息可通過 locationInWindow
屬性來獲取睡榆,該坐標(biāo)是當(dāng)前 Window 窗口的坐標(biāo),其中包含了 Window 窗口標(biāo)題欄的高度袍榆,所以如果要想獲取當(dāng)前鼠標(biāo)在當(dāng)前 NSView
中的位置胀屿,需要做一次坐標(biāo)轉(zhuǎn)換,可以調(diào)用 NSView
的 convertPoint:
方法來轉(zhuǎn)換坐標(biāo)包雀。
鼠標(biāo)左鍵的 按下 - 抬起
兩個連續(xù)的動作被定義為單擊事件宿崭,clickCount
屬于用于描述當(dāng)前點擊的次數(shù)。在模擬鼠標(biāo)雙擊時才写,需要用到該字段值葡兑,而不能用連續(xù)兩次點擊事件來模擬雙擊奖蔓。
監(jiān)聽鼠標(biāo)的移動事件時需要設(shè)置一個跟蹤區(qū)域,只有在跟蹤區(qū)域內(nèi)的鼠標(biāo)移動事件才會觸發(fā)讹堤∵汉祝可以通過 NSView
的 - (void)addTrackingArea:(NSTrackingArea *)trackingArea
方法來設(shè)置跟蹤區(qū)域。同時需要重寫 - (void)updateTrackingAreas
方法洲守,當(dāng)跟蹤區(qū)域發(fā)送改變時疑务,需要手動將之前的跟蹤區(qū)域移除,再添加新的跟蹤區(qū)域梗醇。
鼠標(biāo)的拖拽事件是指用戶按下鼠標(biāo)左鍵或右鍵移動鼠標(biāo)知允,當(dāng)拖拽事件發(fā)生時 mouseMoved:
事件將不會觸發(fā)。
鼠標(biāo)的滾動可以通過 deltaX
和 deltaY
兩個屬性來獲取分別在水平方向和垂直方向的滾動偏移婴削。
OSX 的坐標(biāo)系統(tǒng)以左下角為 (0,0) 右上角為 (x_max, y_max)
鍵盤事件的監(jiān)聽
鍵盤事件的監(jiān)聽也使用重寫事件響應(yīng)者 Responders
對應(yīng)的方法來實現(xiàn)廊镜,需要重寫的方法如下:
- (void)keyDown:(NSEvent *)event;
- (void)keyUp:(NSEvent *)event;
- (void)flagsChanged:(NSEvent *)event;
鍵盤事件重寫上述方法外還需要重寫以下方法:
- (BOOL)acceptsFirstResponder;
該方法用來說明是否成為響應(yīng)者鏈的第一個響應(yīng)者,這里需要返回 YES
表示成為第一響應(yīng)者唉俗,否則無法監(jiān)聽鍵盤消息嗤朴。
NSEvent
的 characters
描述了當(dāng)前鍵盤按鍵的字符,keyCode
描述了按鍵的值虫溜,每個按鍵的 keyCode
值定義可以在 Carbon/HIToolbox/Events.h
文件中找到對應(yīng)的按鍵的宏定義雹姊。
在 keyDown:
和 keyUp:
方法中可以監(jiān)聽到大部分的按鍵的消息,但一些控制鍵需要通過 flagsChanged:
方法來處理衡楞,當(dāng) NSEventModifierFlags
定義的按鍵狀態(tài)發(fā)送改變時吱雏,該方法就會被觸發(fā)。這里需要注意的是大小寫鎖定鍵 NSEventModifierFlagCapsLock
只有當(dāng)大寫鎖定或者取消鎖定時瘾境,該方法才會被調(diào)用歧杏,并不會因為 CapsLock
按鍵按下或者抬起時觸發(fā)迷守。
keyCode 值在 Windows 和瀏覽器上都有對應(yīng)的鍵盤按鍵的值的定義犬绒,當(dāng)需要與其他平臺進行通信時兑凿,例如遠程控制時凯力,可以將 Mac 下的 keyCode 值轉(zhuǎn)換成瀏覽器 JS 上的對應(yīng)值定義礼华,因為瀏覽器和 Windows 平臺的定義是一致的咐鹤。
CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, kVK_CapsLock)
方法可以用來獲取按鍵是否處于按下狀態(tài)。
鼠標(biāo)鍵盤事件的模擬
OSX 下的鼠標(biāo)和鍵盤事件模擬需要用到 CoreGraphics
及 Carbon
框架圣絮,在 CoreGraphics
框架中定義了一些用于創(chuàng)建底層事件的方法祈惶,Carbon
框架定義了一些跟鍵盤相關(guān)的宏和方法。
在模擬鼠標(biāo)或者鍵盤事件時,都需要使用 CGEventSourceCreate(CGEventSourceStateID stateID)
方法來創(chuàng)建事件源奸腺,事件源類型定義了 3 個類型餐禁,如下:
typedef CF_ENUM(int32_t, CGEventSourceStateID) {
kCGEventSourceStatePrivate = -1,
kCGEventSourceStateCombinedSessionState = 0,
kCGEventSourceStateHIDSystemState = 1
};
-
kCGEventSourceStatePrivate
:代表專門的應(yīng)用血久,如遠程控制程序可以生成和跟蹤事件源狀態(tài)獨立于其他進程帮非。 -
kCGEventSourceStateCombinedSessionState
:該狀態(tài)表反映了所有事件源的組合狀態(tài)發(fā)布到當(dāng)前用戶的登錄會話氧吐。如果您的程序發(fā)布的事件在一個登錄會話,您應(yīng)該使用這個源狀態(tài)當(dāng)你創(chuàng)建一個事件源末盔。 -
kCGEventSourceStateHIDSystemState
:該狀態(tài)表反映了組合硬件輸入源從 HID 系統(tǒng)硬件層面發(fā)送的事件源筑舅。生成的事件。 就是外接鍵盤或者 macbook 本機鍵盤以及一些系統(tǒng)定義的按鍵點擊事件陨舱。
這里自己封裝了鼠標(biāo)事件翠拣、鼠標(biāo)滾動事件及鍵盤事件的方法游盲,需要引入 <Carbon/Carbon.h>
及 <AppKit/AppKit.h>
頭文件
1. 模擬鼠標(biāo)事件:
void PostMouseEvent(CGMouseButton button, CGEventType type, const CGPoint &point, int64_t clickCount)
{
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
CGEventRef theEvent = CGEventCreateMouseEvent(source, type, point, button);
CGEventSetIntegerValueField(theEvent, kCGMouseEventClickState, clickCount);
CGEventSetType(theEvent, type);
CGEventPost(kCGHIDEventTap, theEvent);
CFRelease(theEvent);
CFRelease(source);
}
左鍵單擊模擬:
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseDown, CGPointZero, 1);
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseUp, CGPointZero, 1);
左鍵雙擊模擬:
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseDown, CGPointZero, 1);
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseUp, CGPointZero, 1);
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseDown, CGPointZero, 2);
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseUp, CGPointZero, 2);
拖拽事件: 如果是拖拽事件,例如左鍵拖拽事件益缎,則需要先發(fā)送左鍵的 kCGEventLeftMouseDown
事件谜慌,然后連續(xù)發(fā)送 kCGEventLeftMouseDragged
事件莺奔,再發(fā)送 kCGEventLeftMouseUp
事件欣范,代碼如下:
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseDown, CGPointZero, 1);
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseDragged, CGPointZero, 1);
...
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseDragged, CGPointZero, 1);
PostMouseEvent(kCGMouseButtonLeft, kCGEventLeftMouseUp, CGPointZero, 1);
模擬其他鼠標(biāo)事件令哟,將枚舉值修改一下即可恼琼。
2. 模擬鼠標(biāo)滾動事件
void PostScrollWheelEvent(int32_t scrollingDeltaX, int32_t scrollingDeltaY)
{
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
CGEventRef theEvent = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, scrollingDeltaY, scrollingDeltaX);
CGEventPost(kCGHIDEventTap, theEvent);
CFRelease(theEvent);
CFRelease(source);
}
鼠標(biāo)滾輪事件只要傳入水平和垂直方向的偏移即可實現(xiàn)屏富。
3. 模擬鍵盤事件
void PostKeyboardEvent(CGKeyCode virtualKey, bool keyDown, CGEventFlags flags)
{
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
CGEventRef push = CGEventCreateKeyboardEvent(source, virtualKey, keyDown);
CGEventSetFlags(push, flags);
CGEventPost(kCGHIDEventTap, push);
CFRelease(push);
CFRelease(source);
}
鍵盤事件的模擬需要注意的就是 CGEventFlags flags
參數(shù)晴竞,該參數(shù)用來模擬組合鍵的實現(xiàn),類型定義如下:
typedef CF_OPTIONS(uint64_t, CGEventFlags) { /* Flags for events */
/* Device-independent modifier key bits. */
kCGEventFlagMaskAlphaShift = NX_ALPHASHIFTMASK,
kCGEventFlagMaskShift = NX_SHIFTMASK,
kCGEventFlagMaskControl = NX_CONTROLMASK,
kCGEventFlagMaskAlternate = NX_ALTERNATEMASK,
kCGEventFlagMaskCommand = NX_COMMANDMASK,
/* Special key identifiers. */
kCGEventFlagMaskHelp = NX_HELPMASK,
kCGEventFlagMaskSecondaryFn = NX_SECONDARYFNMASK,
/* Identifies key events from numeric keypad area on extended keyboards. */
kCGEventFlagMaskNumericPad = NX_NUMERICPADMASK,
/* Indicates if mouse/pen movement events are not being coalesced */
kCGEventFlagMaskNonCoalesced = NX_NONCOALSESCEDMASK
};
解析如下:
- kCGEventFlagMaskAlphaShift:大小寫鎖定鍵是否處于開啟狀態(tài)
- kCGEventFlagMaskShift:Shift 鍵是否按下
- kCGEventFlagMaskControl:Control 鍵是否按下
- kCGEventFlagMaskAlternate:Alt 鍵是否按下颓鲜,對應(yīng) Mac 鍵盤的 option 鍵
- kCGEventFlagMaskCommand:Command 鍵是否按下,對應(yīng) Windows 的 WIN 鍵
- kCGEventFlagMaskHelp:Help 鍵
- kCGEventFlagMaskSecondaryFn:Fn 鍵
- kCGEventFlagMaskNumericPad:數(shù)字鍵盤
- kCGEventFlagMaskNonCoalesced:沒有任何鍵按下
如果有多個控制鍵同時按下甜滨,則使用位運算的或 |
加上對應(yīng)的鍵值即可。例如模擬 Command + Control + S
:
PostKeyboardEvent(kVK_ANSI_S, true, kCGEventFlagMaskCommand | kCGEventFlagMaskControl)
PostKeyboardEvent(kVK_ANSI_S, false, kCGEventFlagMaskNonCoalesced)
大小寫鎖定鍵瘤袖,無法通過 kVK_CapsLock 按鍵的按下和抬起事件來模擬大小鍵的鎖定,同時按鍵上的 LED 燈也是不會有變化的。