GGGlide - Mouse Pointer Momentum [v1.97.1](ergonomic/productivity enhancement)

Post your working scripts, libraries and tools
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

GGGlide - Mouse Pointer Momentum [v1.97.1](ergonomic/productivity enhancement)

16 Aug 2017, 17:49

GGGlide v1.97.1

GGGlide is an ergonomic and productivity feature for touchpad users.

The GGGlide function is reminiscent of the behavior of the Synaptics touchpad setting 'Momentum' (or the more familiar two-finger inertial scrolling but for pointing).
One quick flick of the finger on the TouchPad surface can move the cursor across the entire computer screen. Momentum reduces the repetitive motion and fatigue associated with moving the cursor long distances.
It is a great feature which now is available to any touchpad/trackpad ! :bravo:

Depending on the forcefulness and direction of the finger flick the cursor glides on the screen an equivalent distance.
After a flick of the finger, your movements inertia is "transferred" to the pointer which continues its trajectory with the same speed and direction of your finger, effectively gliding through your desktop. The gliding pointers' physics include friction and hence it will slow down over time eventually stopping. After some tries it is easy to estimate intuitively where the pointer will stop, vastly improving touchpad ergonomics by drastically reducing the total distance of finger/hand travel required. It also works very well with multiple monitor setups.

After a short 'flick' of the finger on the touchpad surface the pointer starts gliding. While gliding:
  • If the user interacts with the position of the pointer (e.g. moves the pointer/mouse) the glide is interrupted.
  • If the user presses down the left click the glide is interrupted (e.g. use tap-to-click to click/stop the gliding pointer at specific point).
  • If the user releases the left click the glide is interrupted (e.g. hold down left click, initiate glide, release left click to stop).
  • If the pointer encounters the screen edge, the glide is interrupted (when starting at the edge you can still glide on the screens' borders).
  • The user can perform another pointer glide while still gliding (e.g. while gliding vertically, flick horizontally for horizontal glide).
  • Any mouse input received will interrupt the current glide (scrolling, right click, etc).
  • The pointer will decelerate until it stops if none of the above occurs.
I have a Logitech T650 touchpad and this has been a feature I had been sorely missing and which I have enriched over time. Apart from AHK I guess another alternative would have been to implement some sort of driver.

The script functions mostly satisfactory but I would greatly appreciate and value any input, suggestions or improvements!


Instructions

The script below will prompt you for the speed of the pointer above which a glide will be performed. Then, it will create and run GGGlide. You can run the GGG setup as many times required or every time you want to change the glide activation speed. A higher value means you need to move your pointer faster before it glides and vice versa. You will need to experiment with different values due to hardware variability (e.g. my laptop Synaptics touchpad on highest sensitivity is good at 1700 but the T650 on Win drivers fares sublime at 390). The setup dialog will have as default speed your current GGGlide value for easier tweaking.
Optionally, GGGlide can change the OS pointer settings of Windows to the recommended defaults at every script launch.
Do not use the GGGlide script created on one PC on other machines. It will not work as expected. Note the glide parameters and then rerun the GGGSetup on the new machine (or copy the ggglide.ini file).

Code: Select all


;
;GGGlideSetup v0.42 by IOrot - Ergonomic & Productivity Pointer Momentum Enhancement Setup 
;
;	Notes:		-Will output the GGGlide script with the selected parameters.
;				-Toggles for access to advanced parameters added.
;				-GGGlide runs faster but includes hardcoded parameters specific to the hardware it was created on. The resulting GGGlide script *cannot* be used in other PCs.
;			
;
;---------- Settings Toggles ----------
enabledAdvancedParams	:= 0	;0 - disabled	, 1 - enabled
skipStartupDialogs		:= 0	;0 - show		, 1 - skip
;---------- ---------------- ----------

If GetKeyState("CapsLock","t")
	enabledAdvancedParams:=skipStartupDialogs:= 1

Gosub, readParts

glideahk:="GGGlide.ahk"
glideini:="GGGlide.ini"

stD:= 35			;Default speed in dialog.
ttD:= 1055			;Default time in dialog.
tdD:= 1007500		;Default time in dialog.
gdD:= 0.665			;Default distance in dialog.
grD:=-0.71575335	;Default rate in dialog.

st:=iniFileGet("GlideParameters", "speedThreshold", stD)
tt:=iniFileGet("GlideParameters", "timeThreshold", ttD)
td:=iniFileGet("GlideParameters", "timeDial", tdD)
gdp:=gd:=iniFileGet("GlideParameters", "distance", gdD)
grp:=gr:=iniFileGet("GlideParameters", "rate", grD)
skip_startup_dialog:=0	;Default value - DO NOT MODIFY.

If NOT(skipStartupDialogs) {
	MsgBox, 65 , GGGlide Setup, The GGGlide script will be created at:`n`t%A_WorkingDir%\%glideahk% `n`nThe resulting script will work *only* on the machine/PC it was created.`nAny previous %glideahk% found will be replaced.
	IfMsgBox Cancel
		ExitApp
	}


Gui, Add, Text,, Lower for easier gliding (%stD%).`t`t`tAverage speed threshold:
Gui, Add, Text,, Lower for larger deadzone (%ttD%).`t`t`tAbsolute time limit:
Gui, Add, Text,, Lower for faster gliding (%tdD%).`t`tTime dial:
If (enabledAdvancedParams) {
	Gui, Add, Text,, Lower for shorter gliding (%gdD%).`t`t`tGlide distance:
	Gui, Add, Text,, Lower for constant acceleration (%grD%).`tGlide rate:
	}
If (skipStartupDialogs)
	Gui, Add, Text,, Disable Startup Dialog:
	
Gui, Add, Edit, Number vGst ym  ; The ym option starts a new column of controls.
Gui, Add, Edit, Number vGtt
Gui, Add, Edit, Number vGtd
If (enabledAdvancedParams) {
	Gui, Add, Edit, Number vGgd
	Gui, Add, Edit, Number vGgr
	}
If (skipStartupDialogs)
	Gui, Add, Checkbox, vSkipD Checked 

Gui, Add, Edit, Number vGst0 ym ReadOnly  ; The ym option starts a new column of controls.
Gui, Add, Edit, Number vGtt0 ReadOnly
Gui, Add, Edit, Number vGtd0 ReadOnly
If (enabledAdvancedParams) {
	Gui, Add, Edit, Number vGgd0 ReadOnly
	Gui, Add, Edit, Number vGgr0 ReadOnly
	}
	
Gui, Add, Button, default, OK  ; The label ButtonOK (if it exists) will be run when the button is pressed.

GuiControl,, Gst, %st%
GuiControl,, Gtt, %tt%
GuiControl,, Gtd, %td%
GuiControl,, Ggd, %gd%
GuiControl,, Ggr, %gr%

GuiControl,, Gst0, %st%
GuiControl,, Gtt0, %tt%
GuiControl,, Gtd0, %td%
GuiControl,, Ggd0, %gd%
GuiControl,, Ggr0, %gr%

Gui, Show,, GGGlide Parameters
Return  ; End of auto-execute section. The script is idle until the user does something.

ButtonOK:
Gui, Submit  ; Save the input from the user to each control's associated variable.
time_to_travel:=Gtt
speed_to_glide:=Gst
time_dial:=Gtd
If (enabledAdvancedParams) {
	gdp:=Ggd
	grp:=Ggr
}
If (skipStartupDialogs)
	skip_startup_dialog:=SkipD
Goto, Resume

Return

Resume:
If FileExist(glideahk)
	FileDelete, %glideahk%
IniWrite, %speed_to_glide%, %glideini%, GlideParameters, speedThreshold
IniWrite, %time_to_travel%, %glideini%, GlideParameters, timeThreshold
IniWrite, %time_dial%,		%glideini%, GlideParameters, timeDial
IniWrite, %gdp%,			%glideini%, GlideParameters, distance
IniWrite, %grp%,			%glideini%, GlideParameters, rate

DllCall("QueryPerformanceFrequency", "Int64*", cFr)
cFf:=	Round(grp*1000000/cFr,3)	;cFf:=	Round(grp*1000000/cFr,3) ;cFf:=	Round(-1.5*1000000/cFr,3)
df_f:=	Round(gdp,3)

part1:=StrReplace(part1,"cFf",cFf)
part1:=StrReplace(part1,"cFr",cFr)
part1:=StrReplace(part1, "speed_to_glide", speed_to_glide)
part1:=StrReplace(part1, "time_to_travel", time_to_travel)
part1:=StrReplace(part1, "time_dial", time_dial)
part1:=StrReplace(part1, "skip_startup_dialog", skip_startup_dialog)
part1:=StrReplace(part1, "glide_rate_par", grp)
part1:=StrReplace(part1, "df_f", df_f)

FileAppend, %part1%, %glideahk%
FileAppend, `n, %glideahk%	
FileAppend, %part2%, %glideahk%	
Run %glideahk%

ExitApp
Return

GuiClose:
ExitApp
Return

iniFileGet(sect, name, def) {
Global glideini
IniRead, par, %glideini%, %sect%, %name%
If (par=="ERROR")
	par:= def
Return par
}

readParts:

part1=
(
;
;GGGlide v1.97.1 by IOrot - Ergonomic & Productivity Pointer Momentum Enhancement
;
;	Notes:
;			- Hardcoded physics.
;			- Glide Activation Threshold was setup at speed_to_glide.
;			- Time Activation Threshold was setup at time_to_travel.
;
#NoEnv	;Recommended for performance and compatibility with future AutoHotkey releases.
;#Warn	;Enable warnings to assist with detecting common errors.
#SingleInstance	Force
#Persistent
ListLines,	Off
Critical	1000000000000000
SetFormat, Floatfast,	0.11
SetFormat, IntegerFast,	d
ver:="1.97.1"
skipStartupDialog:=skip_startup_dialog	;1 - skip, 0 - show.
iniFile:="GGGlide.ini"
Gosub, GGGlideIcon
start:
Gosub, SettingsIni			;Create/read script ini file.
Gosub, OSPointerSettings	;Set default pointer settings.
Gosub, VarInit				;Initialise variables.
GGGlide:
	OnExit("ExitFunc")		;Register a function to be called on exit.
	OnMessage(0x8080,"Change_Ico")
	If NOT(RI_RegisterDevices())	;RawInput register. Flag QS_RAWINPUT = 0x0400
		MsgBox RegisterRawInputDevices failure.
	DllCall("Winmm\timeBeginPeriod", "UInt", TimePeriod)	;Provide adequate resolution for Sleep.
	VarSetCapacity(lpP, 12, 0)
	lpP_addr := &lpP			;Pointer reference to XY pointer coordinates.
	Menu, Tray, Icon, HICON:*`%hICon`%
	TrayTip, GGGlide, Enabled, 0, 0
velocity_monitor:
Loop {		;Velocity Loop - pointer movement monitor.
	Sleep, -1
	DllCall("Sleep", "UInt", 19)
	If !((DllCall("GetQueueStatus", "UInt", 0x0400) >> 16) & 0xFFFF) {
		If (Array2+Array1+Array0<speed_to_glide) {	;Compare filtered average speed to Glide Activation Threshold.
			i:=mod(A_Index,3), Array`%i`%:=0		;Update speed reading.
			Continue		;Below speed threshold, resume velocity monitoring.
			}
		Break				;Pointer has stopped moving. Exit velocity monitor loop and glide.
		}
	;Calculate: x/y axis pointer velocity vx/vy, pointer speed. Store speed and velocity components for each data point in moving average window.
	DllCall("QueryPerformanceCounter", "Int64*", cT1), DllCall("GetCursorPos", "Ptr", lpP_addr), i:=mod(A_Index,3), ArrayX`%i`%:=vx:=cFr*((x1:= NumGet(lpP, 0, "Int"))-x0)/(cT1-cT0), ArrayY`%i`%:=vy:=cFr*((y1:= NumGet(lpP, 4, "Int"))-y0)/(cT1-cT0), Array`%i`%:=Round(Sqrt(vx**2+vy**2)), x0:=x1, y0:=y1, cT0:=cT1
	}
;Get highest speed and equivalent velocity readings within moving average window.
	Array0>Array1 ? (Array0>Array2 ? (vx:=Round(df_f*ArrayX0),vy:=Round(df_f*ArrayY0),v:=Sqrt(vx**2+vy**2)) : (vx:=Round(df_f*ArrayX2),vy:=Round(df_f*ArrayY2),v:=Sqrt(vx**2+vy**2))) : (Array1>Array2 ? (vx:=Round(df_f*ArrayX1),vy:=Round(df_f*ArrayY1),v:=Sqrt(vx**2+vy**2)) : (vx:=Round(df_f*ArrayX2),vy:=Round(df_f*ArrayY2),v:=Sqrt(vx**2+vy**2)))
;If pointer will travel below 200 pixels within approx. 1s
If ((1-Exp(time_to_travel*glide_rate_par/1000))*v<200)
	Goto, velocity_monitor
Array2:=Array1:=Array0:=0
Loop {		;Gliding Loop - pointer glide.
	;Calculate elapsed time from Velocity Loop exit and simulate inertial pointer displacement.
	DllCall("Sleep", "UInt", 1), DllCall("QueryPerformanceCounter", "Int64*", cT0), fff:= 1-Exp((cT0-cT1)*cFf/time_dial)
	If (((DllCall("GetQueueStatus", "UInt", 0x0400) >> 16) & 0xFFFF) OR fff>0.978) { ;Halt on user input/thresh.
		DllCall("GetCursorPos", "Ptr", lpP_addr), x0:=NumGet(lpP, 0, "Int"), y0:=NumGet(lpP, 4, "Int")
		Goto, velocity_monitor
		}
	DllCall("SetCursorPos", "Int", vx*fff+x1, "Int", vy*fff+y1)
	}
Return

)

part2=
(

VarInit:	;Initialise variables.
	TimePeriod:=1
	cT0:=cT1:=0	;Counters
	x1:=y1:=x0:=y0:=0	;Coordinates
	i:=0, vx:=vy:=0, fff:=0.0, v:=0.0
	Array0:=Array1:=Array2:=0		;Speeds
	ArrayX0:=ArrayY0:=ArrayX1:=ArrayY1:=ArrayX2:=ArrayY2:=0.0	;Velocity components
Return
 
SettingsIni:
IniRead, resetDefaults, `%iniFile`%, OSsettings, resetDefaults
if (!FileExist(iniFile) OR resetDefaults=="ERROR")	{
    MsgBox, 67,Welcome to GGGlide ver. `%ver`% by IOrot,It is highly recommended to use the default Windows settings for your pointing device.``nProceed changing to defaults at launch?``n(Revert anytime at 'Start>Mouse>Pointer Options>Motion').
	IfMsgBox Yes
		IniWrite,  1, `%iniFile`%, OSsettings, resetDefaults
	IfMsgBox No
    	IniWrite,  0, `%iniFile`%, OSsettings, resetDefaults
	IfMsgBox Cancel
		ExitApp
	}
IniRead, resetDefaults, `%iniFile`%, OSsettings, resetDefaults
Return

OSPointerSettings: ;Restore to default any OS pointer settings and confirm OS pointer settings values.
	SPI_GETMOUSESPEED = 0x70
	SPI_SETMOUSESPEED = 0x71
	SPI_GETMOUSE = 0x0003
	SPI_SETMOUSE = 0x0004
	MouseSpeed:="", lpParams:=""
	;Set mouse speed to default 10 and get value.
	If (resetDefaults)
		DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, Ptr, 10, UInt, 0)
	DllCall("SystemParametersInfo", UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, MouseSpeed, UInt, 0)
	;Set mouse acceleration to off and get values.
	VarSetCapacity(vValue, 12, 0)
	NumPut(0, lpParams, 0, "UInt"),	NumPut(0, lpParams, 4, "UInt"),	NumPut(0, lpParams, 8, "UInt")
	If (resetDefaults)
		DllCall("SystemParametersInfo", UInt, SPI_SETMOUSE, UInt, 0, UInt, &vValue, UInt, 1)
	DllCall("SystemParametersInfo", UInt, SPI_GETMOUSE, UInt, 0, UInt, &vValue, UInt, 0)
    acThr1:=NumGet(vValue, 0, "UInt"), acThr2:= NumGet(vValue, 4, "UInt"),acOn:= NumGet(vValue, 8, "UInt") ;"Enhance pointer precision" setting
	VarSetCapacity(vValue, 0)
	If (resetDefaults)
		resetText:=	"``t                 OS settings modified !"
	Else
		resetText:=	"``t                 OS settings unchanged."
	IniRead, st, `%iniFile`%, GlideParameters, speedThreshold
	If NOT(skipStartupDialog) {
		MsgBox, 3,  GGGlide `%ver`% by IOrot, Speed Glide Threshold:``t`%st`%``n``n   Windows Mouse Parameters``n``tSpeed:``t`%MouseSpeed`%``n``tAcceleration``n``t  EnhPPr:``t`%acOn`%``n``t  Thr1:``t`%acThr1`%``n``t  Thr2:``t`%acThr2`%``n``n`%resetText`%``n``nRetain GGGlide launch options?, 7
	IfMsgBox No
		{
		IniDelete, `%iniFile`%, OSsettings, resetDefaults
		Goto, start	;Reload
		}
	IfMsgBox Cancel
		ExitApp
	}
	Else
		DllCall("Sleep", "UInt", 850)
Return

GGGlideIcon:
;Icons by IOrot.
;
global hIConOff, hICon
IconDataHex =0000010001001010000001002000810200001600000089504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff61000000097048597300000b1300000b1301009a9c180000023349444154388d8dd05f4853711407f0efbddbfdb3ed4e7130dd76d585fdd1c5b451442f15a340582ff5d45b504f3ed440422432881e427a280b25224744afa3049f82c010828494a1861581e0b4e9a8f6cfdddddd7b7f77bf1e82186b5c3d705e0edff3e170184a29ea6be8e6c8158e18af98aafa73f2f98376c0c4dfae01a0001800fe7f79a6117896984e5577cb9164f235646fdb72b8bb2b12bf10455bec329a15db38306b6c297af634823d07b0b0bc7aaca555bac40b5cd3e5a6805a5145629ab8188bc129b9f166eec38c5de09dfb0674a2398ac512048788c1f3e7a0d628ae3e4c14f60d504aed6a5545b15040c0df8193278e63fbd76feecef0f5f793f7c6b036376b0dd408950d9d40a96a50550da1de2338dcdb87d497ef51c92d0df3a2c31a30296175c380a6692084a0582a61a03f0c7f6710f38bab13026f3fb3d705122104ba6180520a9d1064b67710e892e1f67a917cf731610d50130621d0340d92e482e470229d4e63676b733728cbf1d60edfa025c0711c5c2e17ec2c0bd3acc1e76b8720f05015c53d323a3a55512a1b7bfc80229fcf81b20cba8341783c1ef082887ca1881713e3b7e2f11bd64f9c5f58bc9ddecafcd8cce6afe5ca4a5674883874b007a58a8a4f2b5fef36e6ff036c36769ce7b84ea7c0bf4cad7d4b28650591817e844247912b2be2d2db99687ddede08300c033b67c3d3e42c40e9f4a970df98a745822cfbe112789de5c4b4e5050c001bc3022c03d8d88da595cff73399ec7a500e4c3d7af25820c458afcfff015876e73759199f9a0000000049454e44ae426082
hICon:=Hex2Icon(IconDataHex)
IconDataHex =0000010001001010000001002000a70200001600000089504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff61000000097048597300000b1300000b1301009a9c180000025949444154388d75d25d4853611cc7f1ef993bdbcee6668a96db4437937c814a1114236c45174a17194a17451004d5ad7553187823bddc4620641408dd0c52a2842ea482228444b3f28d42d406e994f6d2ceced9dc3c5d38edb4d973f73ccffff7795e85f1c646f4ed61abef8298da18145465ede2c4c45efe6d66a014b001ab40c8905540435df5b52aaf8789af3325f7dcce4fba2907d001f40383c055a03007486f1aa2bed6a354547a189bfa72f85ddb890ec00e7401778036a001380338730025ae5852e934a7dbdbb1e6db1979fd7e384fb29c037a800a40c894ae03b11c20994a48914814b364e194ef1875a934e1e4463f50a90b2f014f809fc66c40d334a3a22ac48241ea3792949944ecaaba1d1480efc06de01590c8d9c1664a73a77fcb98e7e6f1cccce24824fede8f288681bbc03320029003084925cf343d8d6b7212aba280a68120103599795b54b4a7e8567700886ed76703f6d21f015be1d8181659de19942d16166aaa59f17a199e5dbaaf0fe8efc00e74d5cccf222acacea06ab3f1c16e27a06dc63ce5e5370b8a8b5fec0638804ea047d285e3361be1e626165783c8aa9a7fdcef7f907d6443267c16e865eba9b6569624422d2d189a9bc06a23148e3075bef3c66e800fb84ee69368a0c52529b5ec2878bce87405cd050eaaf657128d2b7cfc3cd7fb3fc09be96b022c5b15e5ca81d595eef16f0b03724ca6fed0416a6bebf815932df4f5f8b28118a0002a300ff4017e20ea1f191d08ac04595b5fc3ed76e27695250da265590fe45d76b95420044c018f809719944b5663e4b9d1244a46b1ccb5afe4e9c9a1a123dae89b901ef8030acdd4325779f2940000000049454e44ae426082   
hIConOff:=Hex2Icon(IconDataHex)
IconDataHex:=""
Menu, Tray, Icon, HICON:*`%hIConOff`%
Menu, Tray, Tip, GGGlide
Return

Hex2Icon(IconDataHex) {
;Code by SKAN: https://autohotkey.com/board/topic/31044-crazy-scripting-include-an-icon-in-your-script/
VarSetCapacity( IconData,( nSize:=StrLen(IconDataHex)//2) )
Loop `%nSize`% ; MCode by Laszlo Hars: http://www.autohotkey.com/forum/viewtopic.php?t=21172
  NumPut( "0x" . SubStr(IconDataHex,2*A_Index-1,2), IconData, A_Index-1, "Char" )
IconDataHex := ""  
hIConf := DllCall( "CreateIconFromResourceEx", UInt,&IconData+22, UInt,NumGet(IconData,14)
       , Int,1, UInt,0x30000, Int,16, Int,16, UInt,0 )
VarSetCapacity(IconData, 0)	;IOrot: added freeing up of memory.
Return hIConf
}

;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
RI_RegisterDevices(Page := 1, Usage := 2, Flags := 0x0100, HGUI := "") {
   Flags &= 0x3731 ; valid flags
   If Flags Is Not Integer
      Return False
   If (Flags & 0x01) ; for RIDEV_REMOVE you must call RI_UnRegisterDevices()
      Return False
   StructSize := 8 + A_PtrSize ; size of a RAWINPUTDEVICE structure
   ; Usage has to be zero in case of RIDEV_PAGEONLY, flags must include RIDEV_PAGEONLY if Usage is zero.
   If ((Flags & 0x30) = 0x20)
      Usage := 0
   Else If (Usage = 0)
      Flags |= 0x20
   ; HWND needs to be zero in case of RIDEV_EXCLUDE
   If ((Flags & 0x30) = 0x10)
      HGUI := 0
   Else If (HGUI = "")
      HGUI := A_ScriptHwnd
   VarSetCapacity(RID, StructSize, 0) ; RAWINPUTDEVICE structure
   NumPut(Page,  RID, 0, "UShort")
   NumPut(Usage, RID, 2, "UShort")
   NumPut(Flags, RID, 4, "UInt")
   NumPut(HGUI,  RID, 8, "Ptr")
   Return DllCall("RegisterRawInputDevices", "Ptr", &RID, "UInt", 1, "UInt", StructSize, "UInt")
}

ExitFunc(ExitReason, ExitCode) {
	global TimePeriod, lpP, hIConOff
	Menu, Tray, Icon, HICON:*`%hIConOff`%
	TrayTip, GGGlide, Terminating, 0, 0
	DllCall("Sleep", "UInt", 1500)
	DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; Should be called to restore system to normal.
	VarSetCapacity(lpP, 0)	;Free memory.
	Return
}

Change_Ico(wP) {
global change_ico_tog
If (wP==0)
	change_ico_tog := !change_ico_tog
Else If (wP==1) ;Force resume
	change_ico_tog := 0
Else 			;Force pause
	change_ico_tog := 1
	
If (change_ico_tog = 1)
	toPause()
Else If (change_ico_tog = 0)
	toResume()
}

toPause()
{
global hIConOff
TrayTip, GGGlide, Paused., 0, 0
Menu, Tray, Icon, HICON:*`%hIConOff`%
Menu, Tray, Icon,,, 1
Gosub, VarInit				;Initialise variables.
}

toResume()
{
global hICon
TrayTip, GGGlide, Resumed!, 0, 0
Menu, Tray, Icon, HICON:*`%hICon`%
}



)

 Return 


SSStumble v0.01

(GGGlide Add-On)

For those who work using both mice and touchpads and which prefer disabling GGGlide while "mousing" there is SSStumble!


Instructions

Download and run on the same directory with your trusty GGGlide. Upon launch you can select pointing devices where GGGlide gliding will be disabled by SSStumble. You can launch SSStumble and wait for the message box to expire and GGGlide will be launched soon after. All settings are preserved in the GGGlide ".ini" file.

SSStumble Notes:
- SSStumble disables GGGlide only once the current glide has been completed/interrupted (assuming the pointer is currently gliding when switching to the disabled mouse/device). This is evident only when triggering a pause to GGGlide via a hotkey.
- SSStumble only works with the new version of GGGlide v1.97.1 and above. Any older version will not work.
- SSStumble must be running in the background in order to monitor the device which you are using.
- It can distinguish between identical pointing devices operating simultaneously (e.g. two mice or two trackpads which are of the same make).
- Saved devices need to be added again if they are plugged in a different USB port.

Code: Select all


;
;SSStumble v0.01 by IOrot - GGGlide Add-On
;
;	Notes:
;			- This is meant to disable GGGlide (v1.97.1 and above) on user selected pointing devices.
;			- GGGlide is an Ergonomic & Productivity Pointer Momentum Enhancement.
;			
;

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance	Force
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

glideahk:="GGGlide.ahk"
glideini:="GGGlide.ini"

SSStumble:
global detected_handles, disabled_devices
disabled_devices:=[]
detected_handles:=[]
Menu, Tray, Icon, Shell32.dll, 126, 1
OnExit("ExitFunc")

IniRead, disabled_devices_t, %glideini%, SSStumble, disabledOnDevices
If (disabled_devices_t=="ERROR")
	disabled_devices:=[]
Else
	disabled_devices:=StrSplit(disabled_devices_t, ",")

If NOT(RI_RegisterDevices())
	MsgBox RegisterRawInputDevices failure.
OnMessage(0x00FF, "OnRawInput")  ; WM_INPUT
Sleep, 250

MsgBox , 3, SSStumble, Would you like to disable GGGlide on a pointing device?`n (Move your pointer after clicking "Yes" with the said device to select it)., 10
IfMsgBox Yes
	Gosub, add_device
IfMsgBox Cancel
	ExitApp

disabled_handles:=[]
DevArr := RI_GetDeviceList()
For Index, Dev In DevArr.Lst {
	DevName := RI_GetDeviceName(Dev.Handle)
	DevInfo := RI_GetDeviceInfo(Dev.Handle)
	If (DevInfo.Page==1 AND DevInfo.Usage==2) {
		for k, v in disabled_devices
			If (DevName==v)
				disabled_handles.Push(Dev.Handle)
		}
}

	
monitor_input:
If (disabled_devices.Length()==0) {
	MsgBox, , SSStumble, No devices stored. Terminating., 5
	ExitApp
}
If (disabled_handles.Length()==0) {
	MsgBox, ,SSStumble, No disabled devices detected., 5
	;Run %glideahk%	;Launch GGGlide
	;ExitApp
}
Run %glideahk%	;Launch GGGlide
running := 1
Sleep, 1000
detected_handles:=[]
Loop {
	If (detected_handles.Length()!=0) {
		same_state:=1
		active_handle:=GetMax(detected_handles), detected_handles:=[]
		for k, v in disabled_handles
			If (active_handle==v){
				same_state:=0
				If (running) {
					;running := 0
					TogglePause()
					Break
				}
			}
		If (same_state AND NOT(running)) {
			TogglePause()
			;running := 1
			}
	}
	Sleep, 100
}
Return

add_device:
global detected_handles, disabled_devices
detected_handles:=[]
Loop 100 {
ToolTip, % A_Index "/100`n" ExploreObj(detected_handles), 0, 0
Sleep, 50
}
ToolTip, ,0 ,0
If (detected_handles.Length()==0) {
		MsgBox , 3, SSStumble - No Mouse Input, No input was detected.`nMove the pointer with the mouse you want to add to the disabled devices list.`nTry again?,
		IfMsgBox Yes
			Gosub, add_device
		IfMsgBox Cancel
			ExitApp
		IfMsgBox No
			Goto, monitor_input
}
selected_handle:=GetMax(detected_handles)
detected_handles:=[]
handle:=Format("0x{:X}", selected_handle)
selected_device_name:=RI_GetDeviceName(handle)
for k, v in disabled_devices {
	If (selected_device_name==v){
		MsgBox , 3, SSStumble - Duplicate Device, The selected device is already saved. Try again?,
		IfMsgBox Yes
			Gosub, add_device
		IfMsgBox Cancel
			ExitApp
		IfMsgBox No
			Goto, monitor_input
	}
}
MsgBox, 3, SSStumble - Save Device,% "Device found !`nWhen this device receives input GGGlide will be paused automatically and resumed again when using any other pointing device.`nAdd device: " selected_device_name "`n?",
IfMsgBox Cancel
	ExitApp
IfMsgBox No
	Goto, monitor_input
disabled_devices.Push(selected_device_name)
strDH:=Join(",", disabled_devices)
ToolTip, % strDH
IniWrite, % RTrim(strDH, ","), %glideini%, SSStumble, disabledOnDevices
ToolTip, ,0 ,0
MsgBox, 0, SSStumble - Success!,% "Device added!`nWhen this device receives input GGGlide will be paused.`n(If you change the USB port of the device you need to add it again).",
Return

TogglePause(){
global running
running := ! running
ToggleGGGlidePause()
}

ToggleGGGlidePause()
{
global glideahk
DetectHiddenWindows On	; Allows a script's hidden main window to be detected.
SetTitleMatchMode 2		; Avoids the need to specify the full path of the file below.
SendMessage, 0x8080, 0,,, 	 %glideahk% - AutoHotkey	; Change Tray Icon.
PostMessage, 0x111, 65306,,, %glideahk% - AutoHotkey	; Pause.
;PostMessage, 0x111, 65306, 1,, %glideahk% - AutoHotkey	; Pause On
;PostMessage, 0x111, 65306, 2,, %glideahk% - AutoHotkey	; Pause Off
}

ExitFunc()
{
global glideahk
DetectHiddenWindows On  ; Allows a script's hidden main window to be detected.
SetTitleMatchMode 2  ; Avoids the need to specify the full path of the file below.
WinClose %glideahk% - AutoHotkey
}

;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
RI_RegisterDevices(Page := 1, Usage := 2, Flags := 0x0100, HGUI := "") {
   Flags &= 0x3731 ; valid flags
   If Flags Is Not Integer
      Return False
   If (Flags & 0x01) ; for RIDEV_REMOVE you must call RI_UnRegisterDevices()
      Return False
   StructSize := 8 + A_PtrSize ; size of a RAWINPUTDEVICE structure
   ; Usage has to be zero in case of RIDEV_PAGEONLY, flags must include RIDEV_PAGEONLY if Usage is zero.
   If ((Flags & 0x30) = 0x20)
      Usage := 0
   Else If (Usage = 0)
      Flags |= 0x20
   ; HWND needs to be zero in case of RIDEV_EXCLUDE
   If ((Flags & 0x30) = 0x10)
      HGUI := 0
   Else If (HGUI = "")
      HGUI := A_ScriptHwnd
   VarSetCapacity(RID, StructSize, 0) ; RAWINPUTDEVICE structure
   NumPut(Page,  RID, 0, "UShort")
   NumPut(Usage, RID, 2, "UShort")
   NumPut(Flags, RID, 4, "UInt")
   NumPut(HGUI,  RID, 8, "Ptr")
   Return DllCall("RegisterRawInputDevices", "Ptr", &RID, "UInt", 1, "UInt", StructSize, "UInt")
}
;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
; ================================================================================================================================
; Raw input message handlers
; ================================================================================================================================
OnRawInput(Type, RawInput, Msg, HWND) { ; WM_INPUT
   ;Gui, Main: Default
   ;Gui, ListView, RawInput
   global detected_handles
   If (InputObj := RI_GetData(RawInput)) {
      ;InputStr := ""
      ;For Each, Key In InputObj["*Keys"]
       ;  InputStr .= (InputStr ? ", " : "") . Key . ": " . InputObj[Key]
      ;LV_Add("", InputStr)
	  ;ToolTip, % InputStr, 0, 0
	  ;ToolTip, % InputObj["Handle"], 0, 0
	  ;detected_handles.Push(InputObj["Handle"])
	  If (detected_handles[InputObj["Handle"]]=="")
		detected_handles[InputObj["Handle"]]:=0
	  detected_handles[InputObj["Handle"]]+=1
	  ;Array[Key] := Value
   }
   Return DllCall("DefWindowProc", "Ptr", HWND, "UInt", Msg, "Ptr", Type, "Ptr", RawInput, "Ptr")
}
; ================================================================================================================================
; GetRawInputData() -> msdn.microsoft.com/en-us/library/windows/desktop/ms645596(v=vs.85).aspx
; You must pass the lParam of the WM_INPUT message as the data handle.
; On success, the function returns an object containing the following key-value pairs:
;     All devices:
;        *Keys       -  A simple array containing the valid keys for this object.
;        DevType     -  The type of device: 0 = TYPEMOUSE, 1 = TYPEKEYBOARD, 2 = TYPEHID
;        Handle      -  The handle to the device generating the raw input data.
;        Param       -  The value passed in the wParam parameter of the WM_INPUT message.
;     Mouse devices (DevType = 0) -> msdn.microsoft.com/en-us/library/windows/desktop/ms645578(v=vs.85).aspx:
;        State       -  The mouse state.
;        BtnFlags    -  The transition state of the mouse buttons.
;        BtnData     -  If BtnFlags is RI_MOUSE_WHEEL, this member is a signed value that specifies the wheel delta.
;        RawBtns     -  The raw state of the mouse buttons.
;        LastX       -  The motion in the X direction, signed relative or absolute motion, depending on the value of State.
;        LastY       -  The motion in the Y direction, signed relative or absolute motion, depending on the value of State.
;        Extra       -  The device-specific additional information for the event.
;     Keyboard devices (DevType = 1) -> msdn.microsoft.com/en-us/library/windows/desktop/ms645575(v=vs.85).aspx:
;        SC          -  The scan code from the key depression.
;        Flags       -  Flags for scan code information.
;        VK          -  Windows message compatible virtual-key code.
;        Msg         -  The corresponding window message, for example WM_KEYDOWN, WM_SYSKEYDOWN, and so forth
;        Extra       -  The device-specific additional information for the event.
;     HID devices (DevType = 2) ->  msdn.microsoft.com/en-us/library/windows/desktop/ms645549(v=vs.85).aspx:
;        Size        -  The size, in bytes, of each HID input in Data.
;        Count       -  The number of HID inputs in Data.
;        Data        -  The raw input data, as hexadecial strings separated by one space.
; ================================================================================================================================
;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
RI_GetData(Handle) {
   ; RID_INPUT = 0x10000003
   Static Keys := {0: ["DevType", "Handle", "Param", "State", "BtnFlags", "BtnData", "RawBtns", "LastX", "LastY", "Extra"]
                 , 1: ["DevType", "Handle", "Param", "SC", "Flags", "VK", "Msg", "Extra"]
                 , 2: ["DevType", "Handle", "Param", "Size", "Count", "Data"]}
   HdrSize := 8 + (A_PtrSize * 2)
   Size := 0
   DllCall("GetRawInputData", "Ptr", Handle, "UInt", 0x10000003, "Ptr", 0, "UIntP", Size, "UInt", HdrSize)
   If (Size) {
      VarSetCapacity(Data, Size, 0)
      If (DllCall("GetRawInputData", "Ptr", Handle, "UInt", 0x10000003, "Ptr", &Data, "UIntP", Size, "UInt", HdrSize) = Size) {
         DevType := NumGet(Data, 0, "UInt")
         DataObj := {}
         DataObj["*Keys"]   := Keys[DevType]
         DataObj["DevType"] := DevType
         DataObj["Handle"]  := NumGet(Data, 8, "UPtr")
         DataObj["Param"]   := NumGet(Data, 8 + A_PtrSize, "UPtr")
         DataAddr := &Data + HdrSize
         If (DevType = 0) { ; RIM_TYPEMOUSE
            DataObj["State"]    := Format("0x{:04X}", NumGet(DataAddr + 0, "UShort"))
            DataObj["BtnFlags"] := Format("0x{:04X}", NumGet(DataAddr + 4, "UShort"))
            DataObj["BtnData"]  := Format("0x{:04X}", NumGet(DataAddr + 6, "UShort"))
            DataObj["RawBtns"]  := Format("0x{:08X}", NumGet(DataAddr + 8, "UInt"))
            DataObj["LastX"]    := NumGet(DataAddr + 12, "Int")
            DataObj["LastY"]    := NumGet(DataAddr + 16, "Int")
            DataObj["Extra"]    := Format("0x{:08X}", NumGet(DataAddr + 20, "UInt"))
            Return DataObj
         }
         If (DevType = 1) { ; RIM_TYPEKEYBOARD
            DataObj["SC"]    := Format("{:03X}", NumGet(DataAddr + 0, "UShort"))
            DataObj["Flags"] := NumGet(DataAddr + 2, "UShort")
            DataObj["VK"]    := Format("{:02X}", NumGet(DataAddr + 6, "UShort"))
            DataObj["Msg"]   := Format("0x{:04X}", NumGet(DataAddr + 8, "UInt"))
            DataObj["Extra"] := Format("0x{:08X}", NumGet(DataAddr + 12, "UInt"))
            Return DataObj
         }
         If (DevType = 2) { ; RIM_TYPEHID
            SizeHID := NumGet(DataAddr + 0, "UInt")
            CountHID := NumGet(DataAddr + 4, "UInt")
            RawData := ""
            DataAddr += 8
            Loop, %CountHID% {
               Loop, %SizeHID%
                  RawData .= Format("{:02X}", NumGet(DataAddr++, "UChar"))
               RawData .= " "
            }
            DataObj["Size"]  := SizeHID
            DataObj["Count"] := CountHID
            DataObj["Data"]  := RTrim(RawData)
            Return DataObj
         }
      }
   }
   Return False
}
;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
; ================================================================================================================================
; GetRawInputDeviceList() -> msdn.microsoft.com/en-us/library/windows/desktop/ms645598(v=vs.85).aspx
; On success, the function returns a simple array of objects containing the following key-value pairs:
;     Handle   -  The handle to the raw input device.
;     Type     -  The type of device: 0 = TYPEMOUSE, 1 = TYPEKEYBOARD, 2 = TYPEHID
;     Page     -  The top-level collection Usage Page for the device (always 1 for type 0 and 1).
;     Usage    -  The top-level collection Usage for the device (always 2 for type 0 and 6 for type 1).
;     Name     -  The name of the device.
; ================================================================================================================================
RI_GetDeviceList() {
   Static RIM := {0: "M", 1: "K", 2: "H"} ; RIM_TYPE...
   StructSize := A_PtrSize * 2 ; size of a RAWINPUTDEVICELIST structure
   DevCount := 0
   DllCall("GetRawInputDeviceList", "Ptr", 0, "UIntP", DevCount, "UInt", StructSize)
   If (DevCount) {
      VarSetCapacity(ListArr, StructSize * DevCount, 0) ; array of RAWINPUTDEVICELIST structures
      If (DllCall("GetRawInputDeviceList", "Ptr", &ListArr, "UIntP", DevCount, "UInt", StructSize, "Int") = DevCount) {
         DevObj := {Cnt: {H: 0, K: 0, M: 0, T: DevCount}, Lst: {}} ; Cnt = counters, Lst = device list
         Addr := &ListArr
         Loop, %DevCount% {
            DevType := NumGet(Addr + A_PtrSize, "UInt")
            DevHandle := Format("0x{:X}", NumGet(Addr + 0, "UPtr"))
            DevObj.Cnt[RIM[DevType]]++
            DevObj.Lst.Push({Handle: DevHandle, Type: DevType})
            Addr += StructSize
         }
         Return DevObj
      }
   }
   Return False
}
;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
; ================================================================================================================================
; GetRawInputDeviceInfo() -> msdn.microsoft.com/en-us/library/windows/desktop/ms645597(v=vs.85).aspx
; On success, the dunction returns the name of the device.
; ================================================================================================================================
RI_GetDeviceName(DevHandle) {
   ; RIDI_DEVICENAME = 0x20000007
   DevName := ""
   Length := 0
   DllCall("GetRawInputDeviceInfo", "Ptr", DevHandle, "UInt", 0x20000007, "Ptr", 0, "UIntP", Length)
   If (Length) {
      VarSetCapacity(DevName, Length << !!A_IsUnicode, 0)
      DllCall("GetRawInputDeviceInfo", "Ptr", DevHandle, "UInt", 0x20000007, "Str", DevName, "UIntP", Length)
   }
   Return DevName
}
;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
; ================================================================================================================================
; GetRegisteredRawInputDevices() -> msdn.microsoft.com/en-us/library/windows/desktop/ms645599(v=vs.85).aspx
; On success, the function returns a simple array of objects containing the following key-value pairs:
;     Page     -  The top-level collection Usage Page for the device (always 1 for type 0 and 1).
;     Usage    -  The top-level collection Usage for the device (always 2 for type 0 and 6 for type 1).
;     Flags    -  The mode flag that specifies how to interpret the information provided by Page and Usage.
;     HWND     -  The handle to the target window. If NULL it follows the keyboard focus.
; ================================================================================================================================
RI_GetRegisteredDevices() {
   StructSize := 8 + A_PtrSize ; size of a RAWINPUTDEVICE structure
   DevCount := 0
   DllCall("GetRegisteredRawInputDevices", "Ptr", 0, "UIntP", DevCount, "UInt", StructSize)
   If (DevCount) {
      VarSetCapacity(DevArr, StructSize * DevCount, 0) ; array of RAWINPUTDEVICE structures
      If (DllCall("GetRegisteredRawInputDevices", "Ptr", &DevArr, "UIntP", DevCount, "UInt", StructSize, "Int") = DevCount) {
         Registered := []
         Addr := &DevArr
         Loop, %DevCount% {
            Page  := NumGet(Addr + 0, "UShort")
            Usage := NumGet(Addr + 2, "UShort")
            Flags := Format("0x{:04X}", NumGet(Addr + 4, "UInt"))
            HWND  := NumGet(Addr + 8, "UPtr")
            Registered.Push({Flags: Flags, HWND: (HWND = 0 ? HWND : Format("0x{:X}", HWND)), Page: Page, Usage: Usage})
            Addr += StructSize
         }
         Return Registered
      }
   }
   Return False
}
;Code by https://github.com/AHK-just-me/RawInput/blob/master/Sources/RI.ahk
; ================================================================================================================================
; GetRawInputDeviceInfo() -> msdn.microsoft.com/en-us/library/windows/desktop/ms645597(v=vs.85).aspx
; On success, the function returns an object containing the following key-value pairs:
;     All devices:
;        DevType     -  The type of device: 0 = TYPEMOUSE, 1 = TYPEKEYBOARD, 2 = TYPEHID
;        Page        -  The top-level collection Usage Page for the device (always 1 for type 0 and 1).
;        Usage       -  The top-level collection Usage for the device (always 2 for type 0 and 6 for type 1).
;     Mouse devices (DevType = 0):
;        ID          -  The identifier of the mouse device.
;        Buttons     -  The number of buttons for the mouse.
;        Rate        -  The number of data points per second. This information may not be applicable for every mouse device.
;        HWheel      -  True if the mouse has a wheel for horizontal scrolling; otherwise, False (Win Vista+).
;     Keyboard devices (DevType = 1):
;        Type        -  The type of the keyboard.
;        SubType     -  The subtype of the keyboard.
;        ScanMode    -  The scan code mode.
;        FnKeys      -  The number of function keys on the keyboard.
;        Indicators  -  The number of LED indicators on the keyboard.
;        TotalKeys   -  The total number of keys on the keyboard.
;     HID devices (DevType = 2:
;        VendorID    -  The vendor identifier for the HID.
;        ProductID   -  The product identifier for the HID.
;        Version     -  The version number for the HID.
; ================================================================================================================================
RI_GetDeviceInfo(DevHandle) {
   ; RIDI_DEVICEINFO = 0x2000000B
   Static OSV := DllCall("GetVersion", "UChar")
   DevInfo := ""
   Length := 0
   DllCall("GetRawInputDeviceInfo", "Ptr", DevHandle, "UInt", 0x2000000B, "Ptr", 0, "UIntP", Length)
   If (Length) {
      VarSetCapacity(DevInfoBuffer, Length, 0)
      If (DllCall("GetRawInputDeviceInfo", "Ptr", DevHandle, "UInt", 0x2000000B, "Ptr", &DevInfoBuffer, "UIntP", Length) > 0) {
         DevType := NumGet(DevInfoBuffer, 4, "UInt")
         If (DevType = 0) {      ; RIM_TYPEMOUSE - for the mouse, the Usage Page is 1 and the Usage is 2.
            DevInfo := {DevType: DevType}
            DevInfo.ID := NumGet(DevInfoBuffer, 8, "UInt")
            DevInfo.Buttons := NumGet(DevInfoBuffer, 12, "UInt")
            DevInfo.Rate := NumGet(DevInfoBuffer, 16, "UInt")
            DevInfo.HWheel := OSV > 5 ? NumGet(DevInfoBuffer, 20, "UInt") : 0
            DevInfo.Page := 1
            DevInfo.Usage := 2
         }
         Else If (DevType = 1) { ; RIM_TYPEKEYBOARD - for the keyboard, the Usage Page is 1 and the Usage is 6.                                                 ;
            DevInfo := {DevType: DevType}
            DevInfo.Type := NumGet(DevInfoBuffer, 8, "UInt")
            DevInfo.SubType := NumGet(DevInfoBuffer, 12, "UInt")
            DevInfo.ScanMode := NumGet(DevInfoBuffer, 16, "UInt")
            DevInfo.FnKeys := NumGet(DevInfoBuffer, 20, "UInt")
            DevInfo.Indicators := NumGet(DevInfoBuffer, 24, "UInt")
            DevInfo.TotalKeys := NumGet(DevInfoBuffer, 28, "UInt")
            DevInfo.Page := 1
            DevInfo.Usage := 6
         }
         Else If (DevType = 2) { ; RIM_TYPEHID
            DevInfo := {DevType: DevType}
            DevInfo.VendorID := NumGet(DevInfoBuffer, 8, "UInt")
            DevInfo.ProductID := NumGet(DevInfoBuffer, 12, "UInt")
            DevInfo.Version := NumGet(DevInfoBuffer, 16, "UInt")
            DevInfo.Page := NumGet(DevInfoBuffer, 20, "UShort")
            DevInfo.Usage := NumGet(DevInfoBuffer, 22, "UShort")
         }
      }
   }
   Return DevInfo
}

GetMax(arr){
for k,v in arr
  {
  if (v>max)
      {
      keymax:=k
      max:=v
      }
  }
return keymax
}

;Code by Lexikos:
;autohotkey.com/board/topic/70490-print-array/?p=492728
ExploreObj(Obj, NewRow="`n", Equal="  =  ", Indent="`t", Depth=12, CurIndent="") { 
    for k,v in Obj 
        ToReturn .= CurIndent . k . (IsObject(v) && depth>1 ? NewRow . ExploreObj(v, NewRow, Equal, Indent, Depth-1, CurIndent . Indent) : Equal . v) . NewRow 
    return RTrim(ToReturn, NewRow) 
}

Join(sep, params) {
    for index,param in params
        str .= sep . param
    return SubStr(str, StrLen(sep)+1)
}

General Notes:
  • Any mouse settings changes can be reverted painlessly by doing the following: 'Start>Mouse>Pointer Options' you will see a "Motion" box. There you can revert to any settings. If you untick "enhanced pointer precision" and move the speed slider exactly at the middle (6th line) you will replicate the GGGlide settings.
  • Added moving average filtering
  • R.I.P. readability (single line code)
  • Default Sleep was highly unreliable for such short intervals
  • Did not notice any overall performance hit by timeBeginPeriod setting
  • It has not been tested with a traditional mouse but it should still work (you may have to lift your mouse from the surface as to simulate a finger flick).
Issues:
Non-detection of "tap to click" left click when using Logitech trackpad drivers (works fine with default Win trackpad drivers for Logitech trackpad).
Last edited by IOrot on 22 Jun 2018, 11:15, edited 48 times in total.
GeekDude
Posts: 843
Joined: 02 Oct 2013, 22:13

Re: GGGlide - Mouse cursor momentum for touchpad (or any pointing device)

17 Aug 2017, 22:18

Great work! My only Windows system I have on hand is virtual, so I can't actually use this script, but it sounds pretty nice. One thing I noticed is that you don't seem to tweak the SetBatchLines setting. The default has AHK automatically performing a 10ms (effectively 15-16ms) every 10ms, which can limit the fluidity of scripts that do motion.

I use SetBatchLines, -1 as one of only two lines in my default script template (the other being #NoEnv). This disables the feature entirely and makes the script run at full speed. You can still insert your own sleep commands at opportune moments if you need them.
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (or any pointing device)

20 Aug 2017, 07:45

Thanks for the tip ! :D I had missed that particular setting and I did see improvement (although Critical supposedly alters that anyway?). :wtf:
It was rather helpful because I stumbled upon a slew of other things I had totally missed which made the script much more consistent and smooth. Cheers, GeekDude !
User avatar
evilC
Posts: 4341
Joined: 27 Feb 2014, 12:30

Re: GGGlide - Mouse cursor momentum for touchpad (or any pointing device)

21 Aug 2017, 04:35

I have a version of this which uses mouse delta instead of cursor position - it will work in games (eg first person shooters) as well as on the desktop.
https://autohotkey.com/boards/viewtopic.php?t=8439

I also have a version which is partially backed by C# code, so it is a bit more CPU efficient: https://autohotkey.com/boards/viewtopic ... 62#p152062
Also see the MicroTimer library that this version uses, it will give you more accurate, lower CPU usage timers than QPX - it will quite happily do 1ms ticks.
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (or any pointing device)

22 Aug 2017, 12:41

evilC wrote:I have a version of this which uses mouse delta instead of cursor position - it will work in games (eg first person shooters) as well as on the desktop.
https://autohotkey.com/boards/viewtopic.php?t=8439

I also have a version which is partially backed by C# code, so it is a bit more CPU efficient: https://autohotkey.com/boards/viewtopic ... 62#p152062
Also see the MicroTimer library that this version uses, it will give you more accurate, lower CPU usage timers than QPX - it will quite happily do 1ms ticks.
Wow… Wish I knew this sooner it would have been much easier.!! :headwall: Impressive to say the least..! Plus, the GUI is very appealing. Thanks for bringing your work to my attention. :clap:

Haven’t looked at the C# yet but I tested briefly the RollMouse script. Unfortunately it does not perform exactly as expected on my setup (win7 x64, Core 2 Duo 2.45Ghz). Don’t know if this is by design/use case or due to my touchpad.

I have adjusted the MoveFactor and MoveThreshold to match my speeds and I do get a roll/glide to occur, which is what you would expect (constant velocity with no deceleration, infinite displacement). Then, if I perform a finger flick while gliding, lets say perpendicular to the direction of travel, often enough although my mouse movement is registered (the pointer moves visibly in perpendicular fashion) the current glide is not interrupted albeit shifted by the pointer movement.

Would that be because of the MOVE_BUFFER_SIZE ?
Might it be caused by the Sleep in this part?

Code: Select all

while (this.State == this.STATE_ROLLING){

; Send output

DllCall("user32.dll\mouse_event", "UInt", 0x0001, "UInt", this.LastMove.x, "UInt", this.LastMove.y, "UInt", 0, "UPtr", 0)

; Wait for a bit (allow real mouse movement to be detected, which will turn off roll)

Sleep % this.RollFreq

}
Something felt off while trying it and I have perused the code a little further but cannot experiment currently so I will go forward with some of my thoughts even if nobody asked for them! I understand that RollMouse is intended for FPS games using mice but I will be looking at it from a desktop use standpoint with a touchpad.

I think your approach of the xy movement threshold makes its use somewhat inconsistent especially when around the lowest activation speeds.
It ignores the actual resultant displacement vector of x and y and treats them independently which means you may need to perform up to 40% larger movement (e.g. at 45 degrees angles) to reach the thresholds when not moving strictly on the x or y axis. You can end up with an actual delta larger than either the x or y delta component threshold but still have no activation.
More importantly this also affects the direction vector of your glide, presumably this further interacts with the smoothing you perform based on discarding input smaller than MOVE_BUFFER_SIZE as relatively small perpendicular vectors can have a noticeable effect in direction.

When you add up the last deltas at LastMove you essentially integrate the pointers’ change in displacement over time. Assuming a constant sampling rate this would provide the total displacement over some time period. I cannot find any such time period within the gliding context (but I am rather ignorant of the nature of the delta movement capture mechanics). The summing will also zero out displacements with both negative and positive readings, which makes the gliding less responsive.

Is there a specific way/methodology to check CPU usage or should I prop up taskmangr?

As I mentioned previously I am aware this was not necessarily designed with desktop use in mind and I apologise for neat picking your script but I wouldn’t have if it weren’t so interesting and informative. :D :D To be honest I cannot be sure I fully understood your code so hopefully I did not misinterpret it. :oops:
User avatar
evilC
Posts: 4341
Joined: 27 Feb 2014, 12:30

Re: GGGlide - Mouse cursor momentum for touchpad (or any pointing device)

23 Aug 2017, 08:48

Sounds like you have a pretty good understanding of ways to make this work, maybe even better than me. TBH maths is not my strongest suit ;)
The old (AHK implementation) of RollMouse is not hugely reliable TBH, and I would like to improve the technique - would you like to work together to take what we have and improve it?
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (or any pointing device)

30 Aug 2017, 14:02

I think that it will be easy to change most of the things I mentioned so I can help you out with my suggestions. That said, my script above currently works pretty well even within games (tested strategy games, I own no FPS). It is very responsive in my system and I see no high CPU load issues. I am also planning to test some further optimizations and add some additional physics in the gliding. I would be glad to help with anything that comes to my attention but as is I see no incentive for switching and re-implementing the GGGlide features in RollMouse.
CapGuy

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

22 Nov 2017, 09:48

Hell(o) 10rot,

Thanks a lot for this simple and efficient AHK script : tested and approved !

The best for a just-user like me could be to have a simple graphic user interface (say : to run a kind of assistant-screens could be perfect) to set up easily the speed of cursor, duration of momentum (setting of inertia), and so on...

But already as this, it will let me happy as I can use my Logitech Touchpad almost as easy and useful as my Synaptics ones !

(for those who could think this function is not needed : no mistake, only one try with a trackpad and you will not want to do without !)

Best Regards,
Guy
CapGuy
Posts: 8
Joined: 22 Nov 2017, 11:52

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

25 Nov 2017, 10:08

Hell(o),

One thing which could be very useful is just to do the cursor stops when we touch the pad without moving the finger touching.
For now we need to move the finger while touching pad, but when we only touch it without moving our finger the cursor continues on its own momentum, say it is not possible to stop it just touching the pad without moving the finger.
This behavior could be very interesting, because if now we can continue the cursor movement where we need to "send" it, it is more difficult to just stop it where we need.

Do you thing you could implement just this easily ?

Best Regards,
Guy
User avatar
boiler
Posts: 2372
Joined: 21 Dec 2014, 02:44

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

25 Nov 2017, 12:10

Thanks for sharing this. Works well on my Surface Laptop. I found that adjusting the speed threshold to around 400 works better for me so I have to purposely flick it and it doesn't keep running when I am just making small movements.

I understand that there may not be much reason for you to spend time to add a GUI interface or work with evilC to incorporate your techniques into RollMouse, but I'll note my interest in that for what it's worth.
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

03 Jan 2018, 14:35

boiler wrote:Thanks for sharing this. Works well on my Surface Laptop. I found that adjusting the speed threshold to around 400 works better for me so I have to purposely flick it and it doesn't keep running when I am just making small movements.

I understand that there may not be much reason for you to spend time to add a GUI interface or work with evilC to incorporate your techniques into RollMouse, but I'll note my interest in that for what it's worth.
Hi Boiler ! Glad you found it useful ! Unfortunately the Windows OS mouse settings (enhanced precision/acceleration and speed) are in the way and can change drastically the speed curve of the pointer and consequently mess with GGGlide speed thresholds. I have implemented a fix for the issue by setting the Windows mouse settings to values which do not interfere with user input so the script settings should be better calibrated or at least have a sounder basis. The Windows mouse settings can always be adjusted back to any old settings through Windows Mouse Properties. This does not address any sensitivity differences from the various trackpads so tinkering might be needed in many cases.
I agree that a GUI interface would be nice and the current script makes tinkering with the speed thresholds an absolute pain. Unfortunately, I am still working on eliminating lag and I might be getting paranoid but even adding variables at some places instead of actual values seem to slow down the script noticeably.
Let me know if you prefer the new version. You are the second person using it afaik, so it's definitely worth something ! :D
I will try and add some obvious labels above lines with values which might help out with that issue.
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

03 Jan 2018, 15:54

CapGuy wrote:Hell(o),

One thing which could be very useful is just to do the cursor stops when we touch the pad without moving the finger touching.
For now we need to move the finger while touching pad, but when we only touch it without moving our finger the cursor continues on its own momentum, say it is not possible to stop it just touching the pad without moving the finger.
This behavior could be very interesting, because if now we can continue the cursor movement where we need to "send" it, it is more difficult to just stop it where we need.

Do you thing you could implement just this easily ?

Best Regards,
Guy
Hi CapGuy ! Thank you for your kind words ! :D A GUI interface will eventually come but as I am changing how things operate I need some time to settle that first. You are asking for a way of terminating the glide just by tapping/touching but not moving your finger on the touchpad. This can be accomplished if you can enable "tap to click" at your touchpad settings so when you tap/touch the trackpad it registers a click and stops the gliding without the need to move the pointer. Btw, I am not running the Setpoint Logitech drivers or application with my trackpad. I am using the default drivers provided by Windows when you plug in the USB wireless adapter.
I have two more simple but life saving ergonomics scripts specifically for touchpads, one of which taps in the gesture shortcuts for the Logitech. Will create a separate post for them at some point.
CapGuy
Posts: 8
Joined: 22 Nov 2017, 11:52

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

04 Jan 2018, 02:37

Hi IOrot,
Thanks a lot for your answer and your tips. Unfortunately I have to use the Logitech drivers because I use both the Touchpad and a mouse in the same time (3D stuff request it). Also nowadays Windows 10 does not ask me which driver I want, and it install Logitech ones automatically, and with 'tap to click' activated the behavior is the same (cursor does not stop when we just touch the pad without any movement) :-/
Anyway no matter, it is just a question of habits :)
Thanks again for your very useful software !
Cordially,
Guy
User avatar
boiler
Posts: 2372
Joined: 21 Dec 2014, 02:44

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

04 Jan 2018, 12:09

Hi IOrot. I do find it very useful, and I have it running on my laptop all the time. If I turn it off, it's like the mouse cursor is stuck in the mud. This should be default operation for touchpads. Great job!

Because it's working so well and because the new version will change my Windows mouse settings, I'm a little hesitant to try the new version. I know you said I could change the settings back, though. Which settings does it change so I can note what they are so I can change them back if I have to? Actually, I think I'd rather use code that doesn't change the mouse settings as long as it's working well, but if it is noticeably better, I might use it. I'm not seeing any lag or any other issues on mine, so I'm not sure how it could be better.

It would be nice if the 2-finger drag to scroll on my touchpad also worked like this, where momentum would keep it scrolling. I made an attempt at that but wasn't happy with it yet, so I wrote another one that acts more like the middle mouse button click approach with a standard mouse. I may post that when I refine it some, but a momentum-based scroll would be much preferred. Have you ever looked at doing anything with that?
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

04 Jan 2018, 12:52

CapGuy wrote:Hi IOrot,
Thanks a lot for your answer and your tips. Unfortunately I have to use the Logitech drivers because I use both the Touchpad and a mouse in the same time (3D stuff request it). Also nowadays Windows 10 does not ask me which driver I want, and it install Logitech ones automatically, and with 'tap to click' activated the behavior is the same (cursor does not stop when we just touch the pad without any movement) :-/
Anyway no matter, it is just a question of habits :)
Thanks again for your very useful software !
Cordially,
Guy
Yes for some bizarre reason the left click from the "tap to click" option from the Logitech drivers registers differently than a normal left click and my script cannot detect it, so the glide does not stop. Also the trackpad behaves differently with the Logitech drivers, seems like there is more processing done on the touch input before it is translated to on-screen pointer movement. Both issues are fixed with the default Win driver on Win 7, I have no Win 10 machine so I am not sure how to help. Maybe if someone knows how to detect the Logitech left click I could fix it because it is an essential feature and others may have the same problem. As a temporary workaround I believe if you press hard enough on the touchpad it should perform a left click which should stop the glide. In any case, I will eventually tweak the momentum settings to make it easier to target a spot on screen using the glide, as for now I was only aiming to make it efficient at traveling large distances.
CapGuy wrote:Hi IOrot. I do find it very useful, and I have it running on my laptop all the time. If I turn it off, it's like the mouse cursor is stuck in the mud. This should be default operation for touchpads. Great job!

Because it's working so well and because the new version will change my Windows mouse settings, I'm a little hesitant to try the new version. I know you said I could change the settings back, though. Which settings does it change so I can note what they are so I can change them back if I have to? Actually, I think I'd rather use code that doesn't change the mouse settings as long as it's working well, but if it is noticeably better, I might use it. I'm not seeing any lag or any other issues on mine, so I'm not sure how it could be better.

It would be nice if the 2-finger drag to scroll on my touchpad also worked like this, where momentum would keep it scrolling. I made an attempt at that but wasn't happy with it yet, so I wrote another one that acts more like the middle mouse button click approach with a standard mouse. I may post that when I refine it some, but a momentum-based scroll would be much preferred. Have you ever looked at doing anything with that?
Well I may have been overly cautious with my warnings about the OS mouse changes. I does not modify anything within the registry or similar. If you go at Start>Mouse>Pointer Options you will see a "Motion" box. If you untick "enhanced pointer precision" and move the speed slider exactly at the middle (6th line) you can replicate my settings. So maybe download the new one ver 1.6 comment out 'Gosub, MouseSettings' and see if it suits you. I have also changed the gliding slightly but the physics part will be changing with each version as I am not happy with the gliding response yet. Fortunately, my T650 already has this inertial scrolling feature but I do not know if it is possible to detect gestures.

Very glad to hear people find it useful :)
User avatar
boiler
Posts: 2372
Joined: 21 Dec 2014, 02:44

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

04 Jan 2018, 14:47

IOrot wrote:Well I may have been overly cautious with my warnings about the OS mouse changes. I does not modify anything within the registry or similar. If you go at Start>Mouse>Pointer Options you will see a "Motion" box. If you untick "enhanced pointer precision" and move the speed slider exactly at the middle (6th line) you can replicate my settings. So maybe download the new one ver 1.6 comment out 'Gosub, MouseSettings' and see if it suits you. I have also changed the gliding slightly but the physics part will be changing with each version as I am not happy with the gliding response yet.
Thanks, I'll check it out then.
IOrot wrote:Fortunately, my T650 already has this inertial scrolling feature but I do not know if it is possible to detect gestures.
Wish mine did that. I tried seeing if the two-finger drag gesture itself might register as a keystroke using one of the scripts that shows key presses on an on-screen display, and it apparently doesn't (although I can detect the wheel ups and downs that result if I have it set for that), even though things like 3-finger and 4-finger taps do register as a key combination. Detecting the wheel ups and downs didn't seems like the best method for determining speed.
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

05 Mar 2018, 12:36

boiler wrote:
IOrot wrote:Well I may have been overly cautious with my warnings about the OS mouse changes. I does not modify anything within the registry or similar. If you go at Start>Mouse>Pointer Options you will see a "Motion" box. If you untick "enhanced pointer precision" and move the speed slider exactly at the middle (6th line) you can replicate my settings. So maybe download the new one ver 1.6 comment out 'Gosub, MouseSettings' and see if it suits you. I have also changed the gliding slightly but the physics part will be changing with each version as I am not happy with the gliding response yet.
Thanks, I'll check it out then.
IOrot wrote:Fortunately, my T650 already has this inertial scrolling feature but I do not know if it is possible to detect gestures.
Wish mine did that. I tried seeing if the two-finger drag gesture itself might register as a keystroke using one of the scripts that shows key presses on an on-screen display, and it apparently doesn't (although I can detect the wheel ups and downs that result if I have it set for that), even though things like 3-finger and 4-finger taps do register as a key combination. Detecting the wheel ups and downs didn't seems like the best method for determining speed.
Well you could possibly:
detect the wheel ups/downs to enable a "scrolling mode" where you could use the pointers vertical displacement to scroll an equivalent amount (like middle-click on
Firefox). Then wheel up/down again to exit mode. Btw, there is an updated version of GGGlide, much smoother and with sane defaults.
User avatar
IOrot
Posts: 23
Joined: 16 Aug 2017, 15:33

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics enhancement)

05 Mar 2018, 12:39

CapGuy wrote:Hi IOrot,
Thanks a lot for your answer and your tips. Unfortunately I have to use the Logitech drivers because I use both the Touchpad and a mouse in the same time (3D stuff request it). Also nowadays Windows 10 does not ask me which driver I want, and it install Logitech ones automatically, and with 'tap to click' activated the behavior is the same (cursor does not stop when we just touch the pad without any movement) :-/
Anyway no matter, it is just a question of habits :)
Thanks again for your very useful software !
Cordially,
Guy

Changed the way the pointer slows down, let me know if it suits you any better.
User avatar
evilC
Posts: 4341
Joined: 27 Feb 2014, 12:30

Re: GGGlide - Mouse cursor momentum for touchpad (ergonomics & productivity enhancement)

05 Mar 2018, 13:19

I previously mentioned how to get better timers, but I realised that I did not point out that as far as I can tell, part of your code is not doing what you think it is.
DllCall("Sleep", UInt, 2) will not sleep for 2ms surely, will it not sleep for the min system granularity? (Probably ~15ms)

Code: Select all

start := A_TickCount
Loop 100 {
    DllCall("Sleep", UInt, 2)
}
MsgBox % (A_TickCount - start) / 100
On my work system , I get ~7, not 2
If you want to get a "smooth" glide, you probably do not want sleep (Use QPX or MicroTimer instead)

To address your previous comments (Better late than never!), my general point was that your current code is based on cursor position, which suffers from a number of drawbacks:
1) You have to do calculations to find the delta change. If the cursor hits the edge of the screen, you get none.
2) Detecting that the user moved the mouse (stop glide) requires further calculations (It looks like you are saying "Well the glide alone would have put the cursor here, so if it is somewhere else, the user moved the mouse")
If you used RawInput to detect input, and a mouse_event dllcall to do the glide, then you could just check each RawInput packet for the LLMHF_INJECTED flag - if it is set, then the movement was caused your dllcall, if it is not set, the movement came from the real mouse, and so stop the glide.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Banayat and 28 guests