Subversion Repositories Mobile Apps.GyroMouse

Rev

Rev 5 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
//
2
//  ServerHandler.swift
3
//  GyroMouse
4
//
5
//  Created by Matteo Riva on 07/08/15.
6
//  Copyright © 2015 Matteo Riva. All rights reserved.
7
//
8
 
9
import Cocoa
10
import CocoaAsyncSocket
11
 
12
let ServerDidConnectNotification = Notification.Name("ServerDidConnectNotification")
13
let ServerDidDisconnectNotification = Notification.Name("ServerDidDisconnectNotification")
14
 
15
protocol ServerHandlerDelegate: AnyObject {
7 pmbaty 16
    func computePointerMovement(grav: (X: Double, Y: Double, Z: Double), rotat: (X: Double, Z: Double), acc: (X: Double, Y: Double, Z: Double), moveVelocity: Double)
17
    func scrollWithRoll(roll: Double, velocity: Double)
18
    func clickButton(isRightButton: Bool, isButtonDown: Bool)
19
    func resetPointerPosition(moveMouse: Bool)
20
    func runAppleScript(_ scriptText: String)
1 pmbaty 21
}
22
 
23
class ServerHandler: NSObject, NetServiceDelegate, GCDAsyncSocketDelegate {
24
 
25
    weak var delegate: ServerHandlerDelegate?
26
 
27
    private var service: NetService?
28
    private var socket: GCDAsyncSocket?
29
 
30
    deinit {
31
        delegate = nil
32
 
33
        socket?.setDelegate(nil, delegateQueue: nil)
34
        socket = nil
35
 
36
        service?.delegate = nil
37
        service = nil
38
    }
39
 
40
    //MARK: - Privates
41
 
42
    private func sendNotificationWithName(_ name: Notification.Name, userInfo: [String : Any]?) {
43
        let center = NotificationCenter.default
44
        let notif = Notification(name: name, object: self, userInfo: userInfo)
45
        center.post(notif)
46
    }
7 pmbaty 47
 
1 pmbaty 48
    //MARK: - Publics
49
 
50
    func endConnection() {
51
        socket?.disconnect()
52
    }
53
 
54
    func startBroadcast() {
55
        // Initialize GCDAsyncSocket
56
        socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
57
 
58
        // Start Listening for Incoming Connections
59
        do {
60
            try socket!.accept(onPort: 0)
61
            service = NetService(domain: "local.", type: "_gyroserver._tcp.", name: "", port: Int32(socket!.localPort))
62
            service!.delegate = self
63
            service!.publish()
64
        } catch let error as NSError {
65
            print("Unable to create socket. Error \(error) with user info \(error.userInfo).", terminator: "\n")
66
        }
67
    }
68
 
69
    func endBroadcast() {
70
        socket?.setDelegate(nil, delegateQueue: nil)
71
        socket = nil
72
 
73
        service?.delegate = nil
74
        service = nil
75
    }
76
 
77
    //MARK: - NSNetServiceDelegate
78
 
79
    func netServiceDidPublish(_ sender: NetService) {
80
        print("Bonjour Service Published: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
81
    }
82
 
83
    func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
84
        print("Failed to Publish Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
85
    }
86
 
87
    //MARK: - GCDAsyncSocketDelegate
88
 
89
    func socket(_ sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) {
90
        print("Accepted New Socket from \(newSocket.connectedHost as Optional):\(newSocket.connectedPort as Optional)", terminator: "\n")
91
 
92
        socket = newSocket
93
 
7 pmbaty 94
        // read first packet header from socket
95
        newSocket.readData(toLength: UInt(2 * MemoryLayout<Int32>.size), withTimeout: -1, tag: 0)
1 pmbaty 96
 
97
        let notif = NSUserNotification()
98
        notif.title = "connected".localized
99
        notif.informativeText = "connect_with".localized + ":\(socket!.connectedHost as Optional) " + "completed".localized
100
        notif.deliveryDate = Date()
101
        NSUserNotificationCenter.default.scheduleNotification(notif)
102
        NotificationCenter.default.post(name: ServerDidConnectNotification, object: self)
103
    }
104
 
105
    func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
106
        if socket == sock {
107
            if err != nil {
108
                print("Socket did disconnect with error \(err as Optional)", terminator: "\n")
109
            } else {
110
                print("Socket did disconnect", terminator: "\n")
111
            }
112
 
113
            let notif = NSUserNotification()
114
            notif.title = "disconnected".localized
115
            notif.informativeText = "conn_terminated".localized
116
            notif.deliveryDate = Date()
117
            NSUserNotificationCenter.default.scheduleNotification(notif)
118
 
119
            NotificationCenter.default.post(name: ServerDidDisconnectNotification, object: self)
120
 
121
            endBroadcast()
122
            startBroadcast()
123
 
124
        }
125
    }
126
 
127
    func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
7 pmbaty 128
        var expectedByteCount = -1
129
        var expectedNextTag = -1
130
 
131
        if (tag == 0) { // read packet header
132
            let protocolVersion = Int(data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Int32>.size, as: Int32.self) })
133
            if (protocolVersion == 1) {
134
                expectedNextTag = Int(data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Int32>.size, as: Int32.self) })
135
                if      (expectedNextTag == 1) { expectedByteCount = 1 * MemoryLayout<UInt32>.size } // "key" packet type requires 1 uint32
136
                else if (expectedNextTag == 2) { expectedByteCount = 0 } // "backspace" packet type has no payload
137
                else if (expectedNextTag == 3) { expectedByteCount = 0 }// "enter" packet type has no payload
138
                else if (expectedNextTag == 4) { expectedByteCount = 2 * MemoryLayout<Bool>.size } // "click" packet type requires 2 booleans
139
                else if (expectedNextTag == 5) { expectedByteCount = 2 * MemoryLayout<Double>.size } // "scroll" packet type requires 2 doubles
140
                else if (expectedNextTag == 6) { expectedByteCount = 9 * MemoryLayout<Double>.size } // "move" packet type requires 9 doubles
141
                else if (expectedNextTag == 7) { expectedByteCount = 0 } // "reset" packet type has no payload
142
            }
1 pmbaty 143
        }
7 pmbaty 144
        else if (tag == 1) { // read "key" packet payload
145
            var key: String = ""
146
            let unicodeScalarValue: UInt32 = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<UInt32>.size, as: UInt32.self) }
147
            let unicodeScalar = UnicodeScalar(unicodeScalarValue)
148
            if (unicodeScalar != nil) {
149
                key.append(Character(unicodeScalar!))
150
                delegate?.runAppleScript("tell app \"System Events\" to keystroke \"" + key + "\"")
151
            }
152
            expectedNextTag = 0 // prepare to read the next packet header
153
            expectedByteCount = 2 * MemoryLayout<Int32>.size
154
        }
155
        else if (tag == 2) { // read "backspace" packet payload
156
            delegate?.runAppleScript("tell app \"System Events\" to key code 51")
157
            expectedNextTag = 0 // prepare to read the next packet header
158
            expectedByteCount = 2 * MemoryLayout<Int32>.size
159
        }
160
        else if (tag == 3) { // read "enter" packet payload
161
            delegate?.runAppleScript("tell app \"System Events\" to keystroke return")
162
            expectedNextTag = 0 // prepare to read the next packet header
163
            expectedByteCount = 2 * MemoryLayout<Int32>.size
164
        }
165
        else if (tag == 4) { // read "click" packet payload
166
            let isRightButton = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Bool>.size, as: Bool.self) }
167
            let isButtonDown  = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Bool>.size, as: Bool.self) }
168
            delegate?.clickButton(isRightButton: isRightButton, isButtonDown: isButtonDown)
169
            expectedNextTag = 0 // prepare to read the next packet header
170
            expectedByteCount = 2 * MemoryLayout<Int32>.size
171
        }
172
        else if (tag == 5) { // read "scroll" packet payload
173
            let roll           = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Double>.size, as: Double.self) }
174
            let scrollVelocity = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Double>.size, as: Double.self) }
175
            delegate?.scrollWithRoll(roll: roll, velocity: scrollVelocity)
176
            expectedNextTag = 0 // prepare to read the next packet header
177
            expectedByteCount = 2 * MemoryLayout<Int32>.size
178
        }
179
        else if (tag == 6) { // read "move" packet payload
180
            let gravX        = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Double>.size, as: Double.self) }
181
            let gravY        = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Double>.size, as: Double.self) }
182
            let gravZ        = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 2 * MemoryLayout<Double>.size, as: Double.self) }
183
            let rotatX       = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 3 * MemoryLayout<Double>.size, as: Double.self) }
184
            let rotatZ       = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 4 * MemoryLayout<Double>.size, as: Double.self) }
185
            let accX         = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 5 * MemoryLayout<Double>.size, as: Double.self) }
186
            let accY         = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 6 * MemoryLayout<Double>.size, as: Double.self) }
187
            let accZ         = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 7 * MemoryLayout<Double>.size, as: Double.self) }
188
            let moveVelocity = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 8 * MemoryLayout<Double>.size, as: Double.self) }
189
            delegate?.computePointerMovement(grav: (X: gravX, Y: gravY, Z: gravZ), rotat: (X: rotatX, Z: rotatZ), acc: (X: accX, Y: accY, Z: accZ), moveVelocity: moveVelocity)
190
            expectedNextTag = 0 // prepare to read the next packet header
191
            expectedByteCount = 2 * MemoryLayout<Int32>.size
192
        }
193
        else if (tag == 7) { // read "reset" packet payload
194
            delegate?.resetPointerPosition(moveMouse: true)
195
            expectedNextTag = 0 // prepare to read the next packet header
196
            expectedByteCount = 2 * MemoryLayout<Int32>.size
197
        }
198
 
199
        // do we know what to read next ?
200
        if (expectedByteCount == -1) {
201
            endConnection()
202
            let alert = NSAlert()
203
            alert.addButton(withTitle: "OK")
204
            alert.messageText = "vers_incomp".localized
205
            alert.informativeText = "incomp_message".localized
206
            alert.alertStyle = .warning
207
            alert.runModal()
208
        }
209
        else if (expectedByteCount == 0) {
210
            socket(sock, didRead: Data(), withTag: expectedNextTag) // no payload, so chain-call ourselves to process the packet directly
211
        }
212
        else {
213
            sock.readData(toLength: UInt(expectedByteCount), withTimeout: -1, tag: expectedNextTag) // read some bytes
214
        }
1 pmbaty 215
    }
216
}