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
}