Subversion Repositories Mobile Apps.GyroMouse

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

//
//  MouseViewController.swift
//  GyroMouse
//
//  Created by Matteo Riva on 08/08/15.
//  Copyright © 2015 Matteo Riva. All rights reserved.
//

import UIKit
import CoreMotion


// Extend from MyUITextFieldDelegate instead of UITextFieldDelegate in your class
protocol MyUITextFieldDelegate : UITextFieldDelegate {
    func didPressBackspace(_ textField: MyUITextField)
}
class MyUITextField: UITextField {
    override func deleteBackward() {
        super.deleteBackward()
        if let myDelegate = self.delegate as? MyUITextFieldDelegate {
            myDelegate.didPressBackspace(self)
        }
    }
}


class MouseViewController: UIViewController, MyUITextFieldDelegate, SettingsViewControllerDelegate {
    
    private var txtInput = MyUITextField(frame: CGRect(x: UIScreen.main.bounds.size.width * 1 / 8,
                                                       y: UIScreen.main.bounds.size.height * 1 / 32,
                                                       width: UIScreen.main.bounds.size.width * 6 / 8,
                                                       height: UIScreen.main.bounds.size.width * 1 / 16))
    
    private var lButton = UIButton(frame: CGRect(x: 0,
                                                 y: UIScreen.main.bounds.size.height * 2 / 16,
                                                 width: UIScreen.main.bounds.size.width * 3 / 4,
                                                 height: UIScreen.main.bounds.size.height * 14 / 16))
    private var rButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.size.width * 3 / 4,
                                                 y: UIScreen.main.bounds.size.height * 2 / 16,
                                                 width: UIScreen.main.bounds.size.width * 1 / 4,
                                                 height: UIScreen.main.bounds.size.height * 14 / 16))
    
    private let client = (UIApplication.shared.delegate as! AppDelegate).client
    private let manager = CMMotionManager()
    
    private var moveVelocity = UserDefaults.standard.double(forKey: "moveVelocity")
    private var scrollVelocity = UserDefaults.standard.double(forKey: "scrollVelocity")
    private var shakeToReset = UserDefaults.standard.bool(forKey: "shakeToReset")
    
    private lazy var handler: CMDeviceMotionHandler = {
        return {[weak self] (data, error) -> Void in
            if error == nil {
                
                let roll = data!.attitude.roll
                
                var type = GyroPacketType.scroll
                
                if roll > -0.45 && roll < 0.45 {
                    type = .movement
                }
                
                let packet = GyroPacket(type: type, minimumVersion: minimumVersion)
                
                packet.gravX = data!.gravity.x
                packet.gravY = data!.gravity.y
                packet.gravZ = data!.gravity.z
                packet.rotatX =  data!.rotationRate.x//data!.attitude.pitch
                packet.roll = roll
                packet.rotatZ = data!.rotationRate.z//data!.attitude.yaw
                packet.accX = data!.userAcceleration.x
                packet.accY = data!.userAcceleration.y
                packet.accZ = data!.userAcceleration.z
                packet.moveVelocity = self?.moveVelocity ?? 0
                packet.scrollVelocity = self?.scrollVelocity ?? 0
                
                self?.client.sendPacket(packet)
            }
        }
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if manager.isDeviceMotionAvailable {
            manager.deviceMotionUpdateInterval = 0.01
            manager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: handler)
        }
        
        NotificationCenter.default.addObserver(forName: ClientDidDisconnectNotification, object: client, queue: OperationQueue.main) {[weak self] (_) -> Void in
            _=self?.navigationController?.popViewController(animated: true)
        }

        txtInput.tintColor = UIColor.white
        txtInput.backgroundColor = UIColor.darkGray.withAlphaComponent(0.7)
        txtInput.textColor = UIColor.white
        txtInput.textAlignment = .center
        txtInput.font = UIFont.systemFont(ofSize: 15)
        txtInput.borderStyle = UITextField.BorderStyle.roundedRect
        txtInput.keyboardType = UIKeyboardType.default
        txtInput.returnKeyType = UIReturnKeyType.done
        txtInput.clearButtonMode = UITextField.ViewMode.whileEditing
        txtInput.autocorrectionType = .no
        txtInput.spellCheckingType = .no
        txtInput.delegate = self
        self.view.addSubview(txtInput)
        
        lButton.backgroundColor = .black
        lButton.layer.borderWidth = CGFloat(1.0)
        lButton.layer.borderColor = UIColor.darkGray.cgColor//(gray: 0.25, alpha: 1)//(red: 0.25, green: 0.25, blue: 0.25, alpha: 1)
        lButton.addTarget(self, action: #selector(lButtonDown), for: .touchDown)
        lButton.addTarget(self, action: #selector(lButtonUp), for: .touchUpInside)
        self.view.addSubview(lButton)

        rButton.backgroundColor = .black
        rButton.layer.borderWidth = CGFloat(1.0)
        rButton.layer.borderColor = UIColor.darkGray.cgColor//CGColor(red: 0.25, green: 0.25, blue: 0.25, alpha: 1)
        rButton.addTarget(self, action: #selector(rButtonDown), for: .touchDown)
        rButton.addTarget(self, action: #selector(rButtonUp), for: .touchUpInside)
        self.view.addSubview(rButton)
    }

    @objc func lButtonDown()
    {
        let packet = GyroPacket(type: .click, minimumVersion: minimumVersion)
        packet.button = ButtonType.left
        packet.click = .down
        lButton.backgroundColor = UIColor (red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5) // grey
        client.sendPacket(packet)
    }
    @objc func lButtonUp()
    {
        let packet = GyroPacket(type: .click, minimumVersion: minimumVersion)
        packet.button = ButtonType.left
        packet.click = .up
        lButton.backgroundColor = UIColor (red: 0, green: 0, blue: 0, alpha: 0.8) // black
        client.sendPacket(packet)
    }

    @objc func rButtonDown()
    {
        let packet = GyroPacket(type: .click, minimumVersion: minimumVersion)
        packet.button = ButtonType.right
        packet.click = .down
        rButton.backgroundColor = UIColor (red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5) // grey
        client.sendPacket(packet)
    }

    @objc func rButtonUp()
    {
        let packet = GyroPacket(type: .click, minimumVersion: minimumVersion)
        packet.button = ButtonType.right
        packet.click = .up
        rButton.backgroundColor = UIColor (red: 0, green: 0, blue: 0, alpha: 0.8) // black
        client.sendPacket(packet)
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
        manager.stopDeviceMotionUpdates()
        client.endConnection()
    }
    
    //MARK: - Mouse actions

    override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
        if event?.subtype == .motionShake && shakeToReset {
            resetPointerPositionAction()
        }
    }
    
    //MARK: - Button actions

    @IBAction func resetPointerPositionAction() {
        let packet = GyroPacket(type: .resetPointerPosition, minimumVersion: minimumVersion)
        client.sendPacket(packet)
    }
    
    //MARK: - KeyboardHandlerDelegate
    
    override func viewDidAppear(_ animated: Bool) {
        txtInput.becomeFirstResponder() // forces iOS keyboard to appear
    }

    func didPressBackspace(_ textField: MyUITextField) {
        let packet = GyroPacket(type: .deleteBackward, minimumVersion: minimumVersion)
        client.sendPacket(packet)
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let packet = GyroPacket(type: .keyTapped, minimumVersion: minimumVersion)
        packet.key = string
        client.sendPacket(packet)
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        let packet = GyroPacket(type: .returnTapped, minimumVersion: minimumVersion)
        client.sendPacket(packet)
        txtInput.text = ""
        return false
    }
    
    //MARK: - SettingsViewControllerDelegate
    
    func settingsDidChangeMoveVelocity(_ moveVelocity: Double) {
        self.moveVelocity = moveVelocity
    }
    
    func settingsDidChangeScrollVelocity(_ scrollVelocity: Double) {
        self.scrollVelocity = scrollVelocity
    }
    
    func settingsDidChangeShakeToReset(_ shakeActive: Bool) {
        self.shakeToReset = shakeActive
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "settingsSegue" {
            let controller = segue.destination as! UINavigationController
            let view = controller.viewControllers.first! as! SettingsViewController
            view.delegate = self
        }
    }
    
}