This repository has been archived by the owner on Sep 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 36
/
mouse.swift
135 lines (118 loc) · 4.71 KB
/
mouse.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* Create a virtual mouse.
* To run: swift mouse.swift
* Stop with CTRL-C.
* Install kernel extension from https://github.com/unbit/foohid/releases/latest first.
*/
import IOKit
let report_descriptor: [CUnsignedChar] = [
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x03, // USAGE_MAXIMUM (Button 3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
]
struct mouse_report_t {
let buttons: UInt8
let x: Int8
let y: Int8
}
let SERVICE_NAME = "it_unbit_foohid"
let FOOHID_CREATE: UInt32 = 0 // create selector
let FOOHID_SEND: UInt32 = 2 // send selector
let DEVICE_NAME = "Foohid Virtual Mouse"
let DEVICE_SN = "SN 123456"
enum VirtualInputError: Error, CustomStringConvertible {
case notAccessIOService
case notOpenIOService
case notSendMessageToHID
var description: String {
switch self {
case .notAccessIOService:
return "Unable to access IOService."
case .notOpenIOService:
return "Unable to open IOService."
case .notSendMessageToHID:
return "Unable to send message to HID device."
}
}
}
func main() throws {
var iterator: io_iterator_t = 0
var connect: io_connect_t = 0
// Get a reference to the IOService
guard IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(SERVICE_NAME), &iterator) == KERN_SUCCESS
else { throw VirtualInputError.notAccessIOService }
defer { IOObjectRelease(iterator) }
guard let service: io_object_t = (sequence(state: iterator) {
let service = IOIteratorNext($0)
return service != IO_OBJECT_NULL ? service : nil
}.first {
if IOServiceOpen($0, mach_task_self_, 0, &connect) == KERN_SUCCESS {
return true
}
IOObjectRelease($0)
return false
}) else { throw VirtualInputError.notOpenIOService }
defer { IOObjectRelease(service) }
let DEVICE_NAME_POINTER = unsafeBitCast(strdup(DEVICE_NAME), to: UInt64.self)
let DEVICE_NAME_LENGTH = UInt64(DEVICE_NAME.utf8.count)
report_descriptor.withUnsafeBufferPointer { report_descriptor in
// Fill up the input arguments.
let input_count: UInt32 = 8
var input = [UInt64](repeatElement(0, count: Int(input_count)))
input[0] = DEVICE_NAME_POINTER // device name
input[1] = DEVICE_NAME_LENGTH // name length
input[2] = unsafeBitCast(report_descriptor.baseAddress, to: UInt64.self) // report descriptor
input[3] = UInt64(report_descriptor.count) // report descriptor len
input[4] = unsafeBitCast(strdup(DEVICE_SN), to: UInt64.self) // serial number
input[5] = UInt64(DEVICE_SN.utf8.count) // serial number len
input[6] = 2 // vendor ID
input[7] = 3 // device ID
if IOConnectCallScalarMethod(connect, FOOHID_CREATE, input, input_count, nil, nil) != KERN_SUCCESS {
print("Unable to create HID device. May be fine if created previously.")
}
}
// Arguments to be passed through the HID message.
let send_count: UInt32 = 4
var send = [UInt64](repeatElement(0, count: Int(send_count)))
send[0] = DEVICE_NAME_POINTER // device name
send[1] = DEVICE_NAME_LENGTH // name length
send[3] = UInt64(MemoryLayout<mouse_report_t>.stride) // mouse struct len
while true {
var mouse = mouse_report_t(buttons: 0, x: 20, y: 20)
try withUnsafePointer(to: &mouse) { mouse in
send[2] = UInt64(UInt(bitPattern: mouse)) // mouse struct
guard IOConnectCallScalarMethod(connect, FOOHID_SEND, send, send_count, nil, nil) == KERN_SUCCESS
else { throw VirtualInputError.notSendMessageToHID }
}
sleep(1)
}
}
do {
try main()
} catch {
print(error)
exit(1)
}