0

I am trying to find a good way to make the mouse movement smoother then just "warping" around. I used to use this code in C# and so I thought I could convert it into Swift. This is what I've got so far but the app crashes as soon as I click the button. What's going wrong?

 @IBAction func btnMove(_ sender: Any) {

    var test: NSPoint = NSMakePoint(200, 150)
    LinearMovement(newPosition: test)


    }


func LinearMovement(newPosition: NSPoint) {
    let n = Int(readLine()!)!

    var start: NSPoint! = NSMakePoint(self.mouseLocation.x, self.mouseLocation.y)
    var iterPoint: NSPoint! = start
    var slope: NSPoint! = NSPoint(x: newPosition.x - start.x, y: newPosition.y - start.y)


    //  Convert CGFloat to Int
    var myIntValuex:Int = Int(slope.x)
    var myIntValuey:Int = Int(slope.y)
    // Devide by the number of steps
    var slopex = myIntValuex / n
    var slopey = myIntValuey / n


    //  Move the mouse to each iterative point.

    for i in 0 ..< n  {

        var intIterx:Int = Int(iterPoint.x)
        var intItery:Int = Int(iterPoint.y)

        var iterPointx = intIterx + slopex
        var iterPointy = intItery + slopey

        var iterPointf: NSPoint = NSPoint(x: iterPointx, y: iterPointy)


        CGWarpMouseCursorPosition(iterPointf)
       //  Thread.Sleep(MouseEventDelayMS)   ??????
    }

    CGWarpMouseCursorPosition(newPosition)
}
  • How exactly does the app crash? What is printed into the console? At the moment it just looks like you're blocking the main thread which makes your application unresponsive. – Palle Jun 23 '17 at 14:25
  • It just stops working. "Application is not responding" – Benoît Kidey Jun 23 '17 at 14:28
  • Did you run the application in a debugger and paused it while you're having this issue? – Palle Jun 23 '17 at 14:57
  • When I put a breakpoint after `let n = Int(readLine()!)! ` it crashes already – Benoît Kidey Jun 23 '17 at 15:37
  • So it does crash? Then Xcode should show you the line in which the code crashed and print into the console why it crashed. – Palle Jun 23 '17 at 15:41
  • fatal error: unexpectedly found nil while unwrapping an Optional value 2017-06-23 17:43:20.844214 Mouse Movement SWIFT[52636:9068644] fatal error: unexpectedly found nil while unwrapping an Optional value – Benoît Kidey Jun 23 '17 at 15:45

2 Answers2

1

According to the console message you got it looks like either readLine() or Int(readLine()!) returns nil. If you're force unwrapping an optional value and the value is nil your app will crash.

Only force unwrap if you're absolutely 100% sure the value you're unwrapping will NEVER be nil!

To avoid these kinds of crashes unwrap with if let or guard let statements:

guard let line = readLine() else {
    // handle the error appropriately here
    // readLine() may return nil if STDIN was closed
    print("Could not read line")
    return
}
guard let n = Int(line) else {
    // handle the error appropriately here
    // Int(line) returns nil if line is not a valid Integer string
    print("Expected an Int value")
    return // or whatever fits here
}

You can - with some modification - do this in a loop so if the user enters an invalid value he can try again.

Palle
  • 11,511
  • 2
  • 40
  • 61
  • Okay this now just keeps giving me "Could not read". Would you know how to fix my code that it does the linear mouse movement? – Benoît Kidey Jun 23 '17 at 16:59
  • It looks like you're closing your standard input stream (e.g. by not launching your app in a Terminal). You have to use another way to get the user input, for example by using a text field, a slider or something similar. – Palle Jun 24 '17 at 14:49
0

After coming back at this I fixed this problem. The problem was that readLine() didn't have any input. I now replaced this with and Int called steps which I give an input. (A number of how many steps between the start position of the cursor and the final position of the cursor.

To flip the y-axis for correct reading with all the location points:

var start = NSPoint(x: 0, y: 0)
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
        let screenheight = NSScreen.main?.frame.height
        
        NSEvent.addLocalMonitorForEvents(matching: .mouseMoved)
            {
            self.start = NSEvent.mouseLocation
            self.start.y = screenheight! - self.start.y
            print(self.start)
            return $0
            
        }

The function itself:

func LinearMovement(newPosition: NSPoint, steps: Int) {
        
        var iterPoint: NSPoint = start
        var slope: NSPoint = NSPoint(x: newPosition.x - start.x, y: newPosition.y - start.y)

            // Divide by the number of steps
        slope.x = slope.x / CGFloat(steps)
        print(slope.x)
        slope.y = slope.y / CGFloat(steps)
        print(slope.y)

            // Move the mouse to each iterative point.
        for i in 0 ..< steps
            {
            
            let randomtime = Int.random(in: 150..<300)
            iterPoint = NSPoint(x: iterPoint.x + slope.x, y: iterPoint.y + slope.y)
            print(randomtime)
                CGWarpMouseCursorPosition(iterPoint)
            do {
                usleep(UInt32(randomtime))
                }
            
            }

            // Move the mouse to the final destination.
            CGWarpMouseCursorPosition(newPosition)
        start = newPosition
        print(start)
        }

And to call the function:

var newloc = CGPoint(x: 200 , y: 200)
LinearMovement(newPosition: newloc, steps: 1920)