Subversion Repositories Mobile Apps.GyroMouse

Rev

Rev 1 | 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 * 7 / 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 * 5 / 16))
    private var resetButton = UIButton(frame: CGRect(x: UIScreen.main.bounds.size.width * 3 / 4,
                                                     y: UIScreen.main.bounds.size.height * 7 / 16,
                                                     width: UIScreen.main.bounds.size.width * 1 / 4,
                                                     height: UIScreen.main.bounds.size.height * 2 / 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 var suspendMotionPacketsUntil: Date = Date()
    
    private lazy var handler: CMDeviceMotionHandler = {
        return {[weak self] (data, error) -> Void in
            if (error == nil) && (self != nil) && (Date() > self!.suspendMotionPacketsUntil) {
                self?.client.sendPacket(
                    ((data!.attitude.roll > -0.45) && (data!.attitude.roll < 0.45) ? "move" : "scroll"),
                    keyTapped: "",
                    isButtonDown: false,
                    isRightButton: false,
                    roll: data!.attitude.roll,
                    scrollVelocity: (self?.scrollVelocity ?? 0),
                    grav: (X: data!.gravity.x, Y: data!.gravity.y, Z: data!.gravity.z),
                    rotat: (X: data!.rotationRate.x, Z: data!.rotationRate.z),
                    acc: (X: data!.userAcceleration.x, Y: data!.userAcceleration.y, Z: data!.userAcceleration.z),
                    moveVelocity: (self?.moveVelocity ?? 0)
                )
            }
        }
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if manager.isDeviceMotionAvailable {
            manager.deviceMotionUpdateInterval = 0.01
            manager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: handler)
        }
        
        NotificationCenter.default.addObserver(forName: GyroMouseDisconnectedNotification, 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)

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

    @objc func lButtonDown()
    {
        lButton.backgroundColor = UIColor (red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5) // grey
        self.suspendMotionPacketsUntil = Date() + TimeInterval(0.25) // block motion packets for 250 milliseconds to facilitate precise clicks
        self.client.sendPacket("click", keyTapped: "", isButtonDown: true, isRightButton: false, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
    }
    @objc func lButtonUp()
    {
        lButton.backgroundColor = UIColor (red: 0, green: 0, blue: 0, alpha: 0.8) // black
        self.client.sendPacket("click", keyTapped: "", isButtonDown: false, isRightButton: false, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
    }

    @objc func rButtonDown()
    {
        rButton.backgroundColor = UIColor (red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5) // grey
        self.suspendMotionPacketsUntil = Date() + TimeInterval(0.25) // block motion packets for 250 milliseconds to facilitate precise clicks
        self.client.sendPacket("click", keyTapped: "", isButtonDown: true, isRightButton: true, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
    }

    @objc func rButtonUp()
    {
        rButton.backgroundColor = UIColor (red: 0, green: 0, blue: 0, alpha: 0.8) // black
        self.client.sendPacket("click", keyTapped: "", isButtonDown: false, isRightButton: true, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
    }

    @objc func resetButtonTouched()
    {
        self.client.sendPacket("reset", keyTapped: "", isButtonDown: false, isRightButton: false, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
    }
    
    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() {
        self.client.sendPacket("reset", keyTapped: "", isButtonDown: false, isRightButton: false, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
    }
    
    //MARK: - KeyboardHandlerDelegate
    
    override func viewDidAppear(_ animated: Bool) {
        txtInput.becomeFirstResponder() // forces iOS keyboard to appear
    }

    func didPressBackspace(_ textField: MyUITextField) {
        self.client.sendPacket("backspace", keyTapped: "", isButtonDown: false, isRightButton: false, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        self.client.sendPacket("key", keyTapped: string, isButtonDown: false, isRightButton: false, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        self.client.sendPacket("enter", keyTapped: "", isButtonDown: false, isRightButton: false, roll: 0, scrollVelocity: 0, grav: (X: 0, Y: 0, Z: 0), rotat: (X: 0, Z: 0), acc: (X: 0, Y: 0, Z: 0), moveVelocity: 0)
        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
        }
    }
    
}