Return cursor to original location on external monitor after touching touchscreen

Post your working scripts, libraries and tools for AHK v1.1 and older
neek
Posts: 2
Joined: 07 May 2020, 03:11

Return cursor to original location on external monitor after touching touchscreen

Post by neek » 07 May 2020, 16:22

I use a laptop with a touchscreen and an active pen, and I often have it connected to a secondary display. If I'm working on the secondary display and I need to tap the touchscreen or jot down a quick note, the mouse pointer moves down to the touchscreen and then I have to drag it back up to where I was working on the secondary. I couldn't find any solutions to this problem that did quite what I needed, so I wrote this script.

What it does: It detects the following mouse event: the cursor is initially sitting on a secondary display, and then the user interacts with the touchscreen (finger or pen). Then it waits for the user to disengage with the touchscreen and returns the cursor to its original position on the secondary display.

How it does it: Instead of actually detecting touchscreen input, the script listens for a specific event: when an initially stationary cursor jumps discontinuously from a secondary display to the touchscreen. It also re-calibrates in real time to changes in screen configuration, e.g. when the external display is disconnected for some netflix on the couch.

Usage notes: Make sure to adjust touchscreen_width and touchscreen_height to match the resolution of your touchscreen. Also, the workarounds I used to get the script to play nicely with my active pen may not work for your setup. If you don't use an active pen, you should be able to set pen_sleep_time := 0, though I don't expect it would be necessary.

If this behavior has been bothering you too, I hope you find my solution helpful! This is sure to be far from the most efficient implementation, but it works perfectly for me in normal use -- including handwriting with the active pen! My setup is a Lenovo c940 14-inch with a 4k touchscreen/active pen hooked up to a 2560x1440 external display. The only way I have been able to "fool" the script is by doing silly things like tapping the screen as fast as I possibly can.

Code: Select all

#SingleInstance, Force
CoordMode, Mouse, Screen

;;;;;;;;;;;;;;;
; ADJUSTABLES ;
;;;;;;;;;;;;;;;
touchscreen_width := 3840 ; The script identifies the touchscreen's coordinates based on its resolution.
touchscreen_height := 2160
trigger_speed := 10 ; The speed threshold in px/ms for detecting the cursor event. May need to adjust this if
			        ; your screen resolutions are significantly different from mine.
pen_sleep_time := 50 ; You can set this to zero if you don't use an active pen on your touchscreen. See below
                     ; for details on what it does.

; Initialize variables for "previous mouse position" and "previous previous mouse position".
MouseGetPos, x_prev, y_prev
x_pprev := x_prev - 1
y_pprev := y_prev - 1
time_prev := A_TickCount
last_rescheck := A_TickCount - 6000

Loop
{	
	time_now := A_TickCount
	
	; Every 5 seconds, re-identify the touchscreen coordinates. This accounts for connecting/disconnecting
	; an external display while the script is running. I took this snippet (and a couple others) from a post
	; by boiler: https://www.autohotkey.com/boards/viewtopic.php?p=37073#p37073
	if (time_now - last_rescheck > 5000)
	{
		SysGet, MonCount, MonitorCount
		Loop, %MonCount%
		{
			SysGet, Mon, Monitor, %A_Index%
			Width := MonRight - MonLeft
			Height := MonBottom - MonTop
			if (Width = touchscreen_width) && (Height = touchscreen_height)
				break
		}
	}
	
	MouseGetPos, x_curr, y_curr
	
	; Check if cursor was stationary between previous two iterations AND cursor moved since the previous iteration.
	; x_prev = cursor x-coordinate at last iteration		x_pprev = cursor x-coordinate at second-to-last iteration
	if (x_prev = x_pprev && y_prev = y_pprev && not (x_curr = x_prev && y_curr = y_prev))
	{
		; Check if cursor entered the touchscreen since the previous iteration
		if ((x_curr >= MonLeft) && (x_curr <= MonRight) && (y_curr >= MonTop) && (y_curr <= MonBottom))
		&& not ((x_prev >= MonLeft) && (x_prev <= MonRight) && (y_prev >= MonTop) && (y_prev <= MonBottom))
		{
			; Check if cursor moved faster than trigger_speed during the time between the previous iteration and this
			; iteration. If so, it's almost certain that the cursor abruptly "jumped" into the touchscreen from
			; outside, and we interpret this as the signal that the touchscreen has been touched.
			if (((x_curr-x_prev)**2 + (y_curr-y_prev)**2) > (trigger_speed*(time_now - time_prev))**2)
			{
				Loop
				{
					Sleep, pen_sleep_time ; works around lag in pen updating LButton state
					
					; Wait until the finger or pen is lifted from the touchscreen AND (if using pen) the cursor is stationary
					; for a short time.
					Loop
					{
						if (GetKeyState("LButton", "P") = 0)
						{
							Sleep, 2*pen_sleep_time
							MouseGetPos, xx_pprev, yy_pprev
							Sleep, 2*pen_sleep_time
							MouseGetPos, xx_prev, yy_prev
							Sleep, 2*pen_sleep_time
							MouseGetPos, xx_curr, yy_curr
							if (xx_pprev = xx_prev && xx_prev = xx_curr && yy_pprev = yy_prev && yy_prev = yy_curr)
								break
						}
					}
					
					Sleep, pen_sleep_time ; I also found I needed this to make it work with my pen, but I don't
										  ; know why.
					
					DllCall("SetCursorPos", int, x_prev, int, y_prev) ; Return from whence you came!!
					
					; Wait a very short time and check if the cursor is still (roughly) where we put it.
					; If it's not, probably the user was hovering the pen over the screen, momentarily holding
					; it stationary. We incorrectly concluded that as the user was done with the touchscreen and
					; returned the cursor to its original position, but then it was moved right back to the
					; touchscreen by the hovering pen. In that case, we need to run the loop again.
					Sleep, 1
					MouseGetPos, x_test, y_test
					if (((x_test - x_prev)**2 + (y_test - y_prev)**2) < 6)
					{
						break
					}
				}
			}
		}
	}
	
	x_pprev := x_prev
	y_pprev := y_prev
	x_prev := x_curr
	y_prev := y_curr
	time_prev := time_now
	Sleep, 1
}

nirito
Posts: 1
Joined: 09 Dec 2022, 12:13

Re: Return cursor to original location on external monitor after touching touchscreen

Post by nirito » 09 Dec 2022, 12:17

I currently use an Android tablet as a third monitor and this solution worked PERFECTLY for my case. I just sign in just to thank you, I didn't knew about autohotkey before this.

Post Reply

Return to “Scripts and Functions (v1)”