Имитация нажатия клавиш с помощью Swift
Я ищу способ моделирования нажатий клавиш в OSX. Я нашел другое решение ( имитация нажатия клавиш для системных горячих клавиш) используя Objective-C, но мне нужно сделать это с помощью Swift. Как я могу адаптировать CGEventCreateKeyboardEvent?
4 ответов
код на этом связанном ответе довольно легко конвертируется в Swift-код, однако есть несколько gotchas, о которых вам нужно будет позаботиться по пути:
CGEventSourceCreate
принимает CGEventSourceStateID
, который является typealiase для UInt32
, но константы, такие как kCGEventSourceStateHIDSystemState
определяется как Int
, так что вам придется бросить их т. е. CGEventSourceStateID(kCGEventSourceStateHIDSystemState)
. Аналогично с CGEventFlags
.
CGEventSourceCreate
и CGEventCreateKeyboardEvent
возвратить Unmanaged<CGEventSource>
(или Unmanaged<CGEvent>
). Автоматически сгенерированный Swift API для Core Графика не знает, должны ли возвращаемые объекты быть выпущены вами или нет, поэтому вам нужно проверить документы API для этих вызовов, а затем использовать takeRetainedValue()
или takeUnretainedValue()
соответственно возвращаемому значению, чтобы преобразовать их в базовый тип, с которым вы хотите работать.
наконец, они возвращаются неявно развернутые optionals, поэтому вам нужно будет решить, хотите ли вы проверить nils или просто жить с волнением взрывов времени выполнения, если они когда-либо вернутся один.
учитывая все, что довольно просто превратить Objective-C в этом ответе, демонстрирующем нажатие Cmd-Space в Swift, я просто попытался вставить это в приложение для царапин, и это сработало отлично:
(хотя я не проверял документы API для того, является ли сохранение правильной вещью или нет)
let src = CGEventSourceCreate(CGEventSourceStateID(kCGEventSourceStateHIDSystemState)).takeRetainedValue()
let cmdd = CGEventCreateKeyboardEvent(src, 0x38, true).takeRetainedValue()
let cmdu = CGEventCreateKeyboardEvent(src, 0x38, false).takeRetainedValue()
let spcd = CGEventCreateKeyboardEvent(src, 0x31, true).takeRetainedValue()
let spcu = CGEventCreateKeyboardEvent(src, 0x31, false).takeRetainedValue()
CGEventSetFlags(spcd, CGEventFlags(kCGEventFlagMaskCommand));
CGEventSetFlags(spcd, CGEventFlags(kCGEventFlagMaskCommand));
let loc = CGEventTapLocation(kCGHIDEventTap)
CGEventPost(loc, cmdd)
CGEventPost(loc, spcd)
CGEventPost(loc, spcu)
CGEventPost(loc, cmdu)
работа с Swift 3
let src = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)
let cmdd = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: true)
let cmdu = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: false)
let spcd = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: true)
let spcu = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: false)
spcd?.flags = CGEventFlags.maskCommand;
let loc = CGEventTapLocation.cghidEventTap
cmdd?.post(tap: loc)
spcd?.post(tap: loc)
spcu?.post(tap: loc)
cmdu?.post(tap: loc)
Я сделал это для проекта Swift 4, Не забывайте, что приложение sandboxing не позволит приложению отправлять такие нажатия клавиш, поэтому его нужно отключить. Это означает, что ваше приложение будет запрещено в AppStore.
import Foundation
class FakeKey {
static func send(_ keyCode: CGKeyCode, useCommandFlag: Bool) {
let sourceRef = CGEventSource(stateID: .combinedSessionState)
if sourceRef == nil {
NSLog("FakeKey: No event source")
return
}
let keyDownEvent = CGEvent(keyboardEventSource: sourceRef,
virtualKey: keyCode,
keyDown: true)
if useCommandFlag {
keyDownEvent?.flags = .maskCommand
}
let keyUpEvent = CGEvent(keyboardEventSource: sourceRef,
virtualKey: keyCode,
keyDown: false)
keyDownEvent?.post(tap: .cghidEventTap)
keyUpEvent?.post(tap: .cghidEventTap)
}
}
Swift 3
для меня шестнадцатеричные Ключевые значения, такие как: 0x124 не работали, но простой UInt 124 сделал трюк!
хорошая коллекция кодов может быть найти здесь! Этот фрагмент кода копирования и вставки имитирует нажатие клавиши со стрелкой вправо. Измените номер ключа для того, что вы хотите имитировать:
// Simulate Right Arrow keypress
let rightArrowKeyCode: UInt16 = 124
let keyDownEvent = CGEvent(keyboardEventSource: nil, virtualKey: rightArrowKeyCode, keyDown: true)
keyDownEvent?.flags = CGEventFlags.maskCommand
keyDownEvent?.post(tap: CGEventTapLocation.cghidEventTap)
let keyUpEvent = CGEvent(keyboardEventSource: nil, virtualKey: rightArrowKeyCode, keyDown: false)
keyUpEvent?.flags = CGEventFlags.maskCommand
keyUpEvent?.post(tap: CGEventTapLocation.cghidEventTap)