Rev 1 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | // |
2 | // MouseHandler.swift |
||
3 | // GyroServer |
||
4 | // |
||
5 | // Created by Matteo Riva on 07/08/15. |
||
6 | // Copyright © 2015 Matteo Riva. All rights reserved. |
||
7 | // |
||
8 | |||
9 | import CoreGraphics |
||
10 | import Cocoa |
||
11 | import Carbon |
||
12 | import CoreServices |
||
13 | |||
14 | class MouseHandler: NSObject, ServerHandlerDelegate { |
||
15 | |||
16 | private let server = ServerHandler() |
||
17 | |||
18 | private var activeScreen: Int { |
||
19 | get { |
||
20 | return UserDefaults.standard.integer(forKey: "activeScreen") |
||
21 | } |
||
22 | } |
||
23 | private var mLoc: (x: CGFloat, y: CGFloat) = (x: 0, y: 0) |
||
24 | private var isDragging = false |
||
25 | |||
26 | override init() { |
||
27 | super.init() |
||
28 | resetPointerPosition(moveMouse: false) |
||
29 | server.startBroadcast() |
||
30 | NotificationCenter.default.addObserver(forName: ActiveScreenDidChangeNotification, object: nil, queue: OperationQueue.main) {[unowned self] (_) -> Void in |
||
31 | self.resetPointerPosition(moveMouse: false) |
||
32 | } |
||
33 | NotificationCenter.default.addObserver(forName: ServerDidConnectNotification, object: nil, queue: OperationQueue.main) {[unowned self] (_) -> Void in |
||
34 | self.resetPointerPosition(moveMouse: true) |
||
35 | self.server.delegate = self |
||
36 | } |
||
37 | NotificationCenter.default.addObserver(forName: ServerDidDisconnectNotification, object: nil, queue: OperationQueue.main) {[unowned self] (_) -> Void in |
||
38 | self.server.delegate = nil |
||
39 | self.resetPointerPosition(moveMouse: false) |
||
40 | } |
||
41 | } |
||
42 | |||
43 | deinit { |
||
44 | NotificationCenter.default.removeObserver(self) |
||
45 | } |
||
46 | |||
47 | //MARK: - Mouse movements |
||
48 | |||
49 | private func computePointerMovementWithPacket(_ packet: GyroPacket) { |
||
50 | let roll = packet.roll |
||
51 | let sgn: Double = roll ?? 0 < 0 ? -1 : 1 |
||
52 | let gate = 0.75 |
||
53 | let changeMovCond = roll == nil || (roll! > -gate && roll! < gate) |
||
54 | |||
55 | let rotatZ = changeMovCond ? packet.rotatZ! : packet.rotatX! * -sgn |
||
56 | let accZ = changeMovCond ? packet.accZ! : packet.accX! |
||
57 | let rotatX = changeMovCond ? packet.rotatX! : packet.rotatZ! * sgn |
||
58 | let accX = changeMovCond ? packet.accX! : packet.accZ! |
||
59 | let gravZ = changeMovCond ? packet.gravZ! : packet.gravX! * sgn |
||
60 | |||
61 | var dx = ((rotatZ * -1) * (1 + abs(accZ))) * packet.moveVelocity! * abs(gravZ) |
||
62 | var dy = ((rotatX * -1) * (1 + abs(accX))) * packet.moveVelocity! * abs(gravZ) |
||
63 | |||
64 | if packet.type == .scroll { |
||
65 | dx = min(dx,1) |
||
66 | dy = min(dy,1) |
||
67 | } |
||
68 | |||
69 | var x = mLoc.x + CGFloat(dx) |
||
70 | var y = mLoc.y + CGFloat(dy) |
||
71 | |||
72 | let frame = NSScreen.screens[activeScreen].frame |
||
73 | let s = (o: frame.origin, w: frame.maxX - 1, h: frame.maxY - 1) |
||
74 | |||
75 | mLoc = (x: x, y: y) |
||
76 | x = max(s.o.x,min(x, s.w)) |
||
77 | y = max(0,min(y, s.h)) |
||
78 | |||
79 | let point = CGPoint(x: x, y: y) |
||
80 | |||
81 | let mouseEvent = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: point, mouseButton: .left) |
||
82 | mouseEvent?.post(tap: CGEventTapLocation.cghidEventTap) |
||
83 | |||
84 | if isDragging { |
||
85 | let mouseEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDragged, mouseCursorPosition: point, mouseButton: .left) |
||
86 | mouseEvent?.post(tap: CGEventTapLocation.cghidEventTap) |
||
87 | } |
||
88 | } |
||
89 | |||
90 | func resetPointerPosition(moveMouse: Bool) { |
||
91 | let aIndex = UserDefaults.standard.integer(forKey: "activeScreen") |
||
92 | let frame = NSScreen.screens[aIndex].frame |
||
93 | let x = frame.midX |
||
94 | let y = frame.midY - frame.origin.y |
||
95 | NSLog("x: %f, y: %f, origin x: %f, y: %f, mid x: %f, y: %f", x,y,frame.origin.x, frame.origin.y, frame.midX, frame.midY) |
||
96 | mLoc = (x: x, y: y) |
||
97 | if moveMouse { |
||
98 | let point = CGPoint(x: x, y: y) |
||
99 | let mouseEvent = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: point, mouseButton: .left) |
||
100 | mouseEvent?.post(tap: CGEventTapLocation.cghidEventTap) |
||
101 | } |
||
102 | } |
||
103 | |||
104 | //MARK: - Mouse actions |
||
105 | |||
106 | var rollGate = 0 |
||
107 | |||
108 | private func scrollWithRoll(_ roll: Double, velocity: Double) { |
||
109 | rollGate += 1 |
||
110 | if rollGate == 10 { |
||
111 | let amount = (Int32) (roll * velocity * -50) |
||
112 | let mouseEvent = CGEvent(scrollWheelEvent2Source: nil, units: .pixel, wheelCount: 1, wheel1: amount, wheel2: 0, wheel3: 0) |
||
113 | mouseEvent?.post(tap: CGEventTapLocation.cghidEventTap) |
||
114 | |||
115 | rollGate = 0 |
||
116 | } |
||
117 | } |
||
118 | |||
119 | private func clickButton(_ button: ButtonType, click: ClickType) { |
||
120 | let mousePos = CGPoint(x: mLoc.x, y: mLoc.y) |
||
121 | let mouseEventType: CGEventType |
||
122 | let mouseButton: CGMouseButton |
||
123 | |||
124 | if button == .left { |
||
125 | mouseButton = .left |
||
126 | mouseEventType = (click == .down ? .leftMouseDown : .leftMouseUp) |
||
127 | isDragging = (click == .down) |
||
128 | } else { |
||
129 | mouseButton = .right |
||
130 | mouseEventType = (click == .down ? .rightMouseDown : .rightMouseUp) |
||
131 | isDragging = false |
||
132 | } |
||
133 | |||
134 | let mouseEvent = CGEvent(mouseEventSource: nil, mouseType: mouseEventType, mouseCursorPosition: mousePos, mouseButton: mouseButton) |
||
135 | mouseEvent?.post(tap: CGEventTapLocation.cghidEventTap) |
||
136 | } |
||
137 | |||
138 | //MARK: - AppleScript launcher |
||
139 | |||
140 | private func runAppleScript(_ scriptText: String) { |
||
141 | let script = NSAppleScript(source: scriptText)! |
||
142 | var error: NSDictionary? = nil |
||
143 | let resultMaybe = script.executeAndReturnError(&error) as NSAppleEventDescriptor? |
||
5 | pmbaty | 144 | if (resultMaybe == nil) |
1 | pmbaty | 145 | { |
5 | pmbaty | 146 | let myStringDict = error as? [String:AnyObject] |
147 | if (myStringDict?["NSAppleScriptErrorNumber"] as! Int16 == 1002) { |
||
148 | let alert = NSAlert() |
||
149 | alert.addButton(withTitle: "OK".localized) |
||
150 | alert.messageText = "system_message".localized + "\n" + (myStringDict?["NSAppleScriptErrorBriefMessage"] as! String) |
||
151 | alert.informativeText = "allow_perms".localized |
||
152 | alert.alertStyle = .warning |
||
153 | alert.runModal() |
||
154 | } |
||
1 | pmbaty | 155 | print (error as Any) |
156 | return |
||
157 | } |
||
158 | } |
||
159 | |||
160 | //MARK: - ServerHandlerDelegate |
||
161 | |||
162 | func serverDidReceivePacket(_ packet: GyroPacket) { |
||
163 | switch packet.type { |
||
164 | case .scroll: |
||
165 | scrollWithRoll(packet.roll!, velocity: packet.scrollVelocity!) |
||
166 | computePointerMovementWithPacket(packet) |
||
167 | case .movement: |
||
168 | computePointerMovementWithPacket(packet) |
||
169 | case .click: |
||
170 | clickButton(packet.button!, click: packet.click!) |
||
171 | case .keyTapped: |
||
172 | runAppleScript("tell app \"System Events\" to keystroke \"\(packet.key!)\"") |
||
173 | case .deleteBackward: |
||
174 | runAppleScript ("tell app \"System Events\" to key code 51") |
||
175 | case .returnTapped: |
||
176 | runAppleScript("tell app \"System Events\" to keystroke return") |
||
177 | case .resetPointerPosition: |
||
178 | resetPointerPosition(moveMouse: true) |
||
179 | } |
||
180 | } |
||
181 | } |