Код слишком длинный, поэтому он разбит на два ответа, и см. Третий ответ для инструкций.
Код Часть 1
#commentflag // ; Change to C++ comment style
// Settings //
global rightbuttonscroll:=0 // set to 1 iff the right button is to be used for scrolling instead of the middle button
global scrollbeforeclick:=1 // set to 1 iff scrolling is allowed before the original button click otherwise scrolling is delayed for (clicklimit)
global leftrighttomiddle:=0 // set to 1 iff pressing both left+right buttons together is to be used to generate the middle button press
global scrolllimit:=3.5 // maximum scroll allowed between scroll button press and release for the original button click to be generated
global clicklimit:=210 // maximum time allowed between scroll button press and release for the original button click to be generated
global resetdelay:=210 // minimum time required between scroll button release and press for the original button click to be allowed
global interval:=35 // minimum interval between scrolling updates
global timelimit:=70 // maximum time allowed for continuing the scrolling update in each direction
global dbg:=false
// Initialization //
#singleinstance,force
#keyhistory 0
#usehook on
process priority,,H
setkeydelay 1
setcontroldelay -1
coordmode mouse,screen
global buttondown:=( rightbuttonscroll==1 ? 0x204 : 0x207 )
global buttonup:=( rightbuttonscroll==1 ? 0x205 : 0x208 )
global buttonoriginal:=( rightbuttonscroll==1 ? "RButton" : "MButton" )
global speed
global handling:=0
global scrolling:=0
global scrolldrag:=0
global scrollsticky:=0
global clicksticky:=0
global leftphysical:=0
global rightphysical:=0
global lefttopress:=0
global righttopress:=0
global middlepressed:=0
global mx,my
global dx,dy
global lx:=0
global ly:=0
global sx:=0
global sy:=0
global totalx:=0
global totaly:=0
global ctrl,window,parent
global methodx
global methody
global scrollbarx
global scrollbary
global max16bit:=32767
global sbinfo
varsetcapacity(sbinfo,28)
numput(28,sbinfo,0)
numput(23,sbinfo,4)
global mousehook:=dllcall("SetWindowsHookEx","int",14,"uint",RegisterCallback("handlemouse","fast"),"uint",0,"uint",0)
message("AutoHotkey loaded")
return
// Reload & Debug & Exit & Disable Mousehook //
LCtrl & RCtrl::reload
LCtrl & AppsKey::dbg:=!dbg
RCtrl & Esc::exitapp
RCtrl & LCtrl::dllcall("UnhookWindowsHookEx","uint",mousehook)
// Message //
messageoff:
tooltip
return
message(text)
{
tooltip % text //,a_screenwidth-strlen(text)*7,a_screenheight-42
settimer messageoff,-1000
}
// Mouse Movement //
moveadjust(byref x,byref y)
{
movespread(x,y)
z2:=x**2+y**2
r:=(70+z2*4)/(70+z2)
x:=rtoz(x*r)
y:=rtoz(y*r)
}
movespread(byref x,byref y)
{
nx:=rtoz(x/2)
ny:=rtoz(y/2)
x-=nx
y-=ny
x+=lx
y+=ly
lx:=nx
ly:=ny
settimer movereset,-210
}
movereset:
lx:=0
ly:=0
return
getspeed()
{
DllCall("SystemParametersInfo","Int",112,"Int",0,"UIntP",speed,"Int",0)
}
setspeed()
{
DllCall("SystemParametersInfo","Int",113,"Int",0,"UInt",speed,"Int",2)
}
showspeed()
{
message("Mouse speed = " . speed)
}
<^>!d::
getspeed()
showspeed()
return
<^>!s::
getspeed()
if( speed>1 )
{
speed:=speed-1
}
setspeed()
showspeed()
return
<^>!f::
getspeed()
if( speed<20 )
{
speed:=speed+1
}
setspeed()
showspeed()
return
// Mouse Scrolling //
/*
Usage
Combination : Function
ScrollButton-Release : ScrollButton-Click (where the intervening time and scroll do not exceed the limits set)
ScrollButton-Modifiers-Move : Modifiers-Scroll (where Modifiers can be any combination of Shift and Ctrl and Alt)
If rightbuttonscroll = 1 :
LButton-RButton : MButton (where the intervening time does not exceed the limit set)
RButton-LButton : MButton (where the intervening time does not exceed the limit set)
Methods
Send wheel messages (0x20a/0x20e) to the control
The wheel amount is only 16-bit which is at most only 32767/120 wheel notches
Some applications do not handle the wheel amount correctly so you may need to send integer multiples of wheel notches or many wheel messages
Microsoft Word apparently assumes that wheel messages are always posted and behaves incorrectly unless PostMessage is used
Send scrollbars' thumb position to the control
This works for many scrollable controls but not all
Send scroll messages (0x115/0x114) to the control unless its scrollbar thumb position is already at the end
Many applications respond rather slowly to scroll messages
Send scroll messages to the scrollbars
This works for some applications and should be slightly faster than scroll messages to the parent
Many applications respond rather slowly so wheel messages are preferable if they work
Send scroll messages to the scrollbars' parents
This is supposed to be a standard way to control scrollbars that are separate from the control
Many applications respond rather slowly so wheel messages are preferable if they work
Send keys (Up/Down/Left/Right/PgUp/PgDn) to the scrollbars
This is equivalent to clicking the arrows or the empty space on either side of the thumb track
Some applications respond slowly so keys should not be sent too fast
Send keys to the control
Only for rare cases that do not respond to anything else
Call Office function SmallScroll
This function only exists for Office applications and even then it is broken in some like Powerpoint
Customization
scrollamount(x)
Can assume that x is non-negative
Must return non-negative output
scrolladjust(x,y)
Can modify scroll amounts (x,y)
gettarget()
Can assume that (mx,my) is the current mouse position
Must set ctrl to the handle of the control that is to be scrolled
Must set parent to getparent(ctrl) if scrolltoscrollbarparent() or keystoscrollbar() is used
*/
scrollamount(x)
{
return x**1.5/8
}
scrolladjust(byref x,byref y)
{
ax:=abs(x)
ay:=abs(y)
z:=sqrt(x**2+y**2)
if( ax>ay*5 )
{
x:=( x>0 ? z : -z )
y:=0
}
if( ay>ax*5 )
{
y:=( y>0 ? z : -z )
x:=0
}
}
gettarget()
{
gosub messageoff
ctrl0:=getctrlat(mx,my)
window:=getwindow(ctrl0)
class:=getclass(window)
title:=gettitle(window)
ctrl:=ctrl0
loop
{
ctrlname:=getnameaschild(ctrl)
ctrlclass:=getclass(ctrl)
parent:=getparent(ctrl)
parentname:=getnameatroot(parent)
parentclass:=getclass(parent)
if( ctrl!=window and ( regexmatch(ctrlclass,"^(Button|T?ComboBox|CtrlNotifySink|SysLink)$")==1 or parentclass=="ComboBox" ) )
{
ctrl:=parent
continue
}
break
}
gp:=getparent(parent)
ggp:=getparent(gp)
gpname:=getnameaschild(gp)
ggpname:=getnameaschild(ggp)
methodx:="wheel" // needed for: Firefox , Gimp , ...
methody:="wheel" // needed for: Firefox , File Chooser , Explorer , Word , Outlook , IE , ...
scrollbarx:=""
scrollbary:=""
if( ctrlclass=="ComboLBox" ) // Standard Combo Boxes dropdown list
{
methodx:="thumbpos"
methody:="thumbpos"
}
if( ctrlclass=="ListBox" ) // Standard List Boxes
{
methodx:="thumbpos"
methody:="thumbpos"
}
if( ctrlclass=="ScrollBar" ) // Standard ScrollBar controls
{
methodx:="scrolltoscrollbarparent" // "scroll" works for most places but not some ( Character Map , ... )
methody:="scrolltoscrollbarparent" // "scroll" works for most places but not some ( Character Map , ... )
scrollbarx:="scrollbar1"
scrollbary:="scrollbar1"
}
if( class=="OpusApp" ) // Microsoft Word
{
methodx:="office"
methody:="postwheel"
if( gpname=="_WwB1" )
{
ctrl:=getdescendant(window,"_WwG1")
}
}
if( class=="XLMAIN" ) // Microsoft Excel
{
methodx:="office"
if( gpname=="EXCEL71" )
{
ctrl:=gp
}
}
if( class=="PPTFrameClass" or class=="PP12FrameClass" ) // Microsoft Powerpoint
{
methody:="wheelsingle"
ctrlnameatroot:=getnameatroot(ctrl)
if( ctrlnameatroot=="NetUIHWND3" or ctrlnameatroot=="NetUIHWND4" )
{
ctrl:=getdescendant(window,"paneClassDC1")
ctrlname:="paneClassDC1"
parent:=getparent(ctrl)
}
if( ctrlname=="paneClassDC1" )
{
methodx:="scrolltoscrollbarparent"
methody:="scrolltoscrollbarparent" // Powerpoint scroll up is broken when there are 9 slides at 100% zoom in normal mode
scrollbarx:="NUIScrollbar2"
scrollbary:="NUIScrollbar1"
//methody:="office" // Powerpoint does not update the view pane immediately and so it is disorienting
}
if( ctrlnameatroot=="NetUIHWND5" )
{
ctrl:=getdescendant(window,"paneClassDC2")
}
}
if( class=="rctrl_renwnd32" ) // Microsoft Outlook
{
methodx:="office"
gpclass:=getclass(gp)
ctrlnameatroot:=getnameatroot(ctrl)
if( ctrlclass=="SUPERGRID" )
{
methodx:="scroll"
methody:="scroll"
}
if( gpclass=="SUPERGRID" )
{
methodx:="scroll"
methody:="scroll"
ctrl:=gp
}
if( gpname=="_WwB1" )
{
ctrl:=getdescendant(window,"_WwG1")
}
}
if( ctrlclass=="OUTEXVLB" ) // Microsoft Outlook { Address Book , Group membership , ... }
{
methodx:="thumbpos"
if( regexmatch(title,"Global Address List")==0 )
{
methody:="scroll"
}
}
if( title=="Symbol" and regexmatch(class,"bosa_sdm_(msword|Microsoft Office Word 12.0|XL9|Mso96)")==1 ) // Microsoft Office Insert Symbol
{
controlget v,visible,,ScrollBar1,ahk_id %ctrl%
if( v==0 )
{
ctrl:=getdescendant(window,"Edit1")
methody:="thumbpos"
}
}
if( class=="wndclass_desked_gsk" ) // Microsoft Visual Basic
{
if( ctrlclass=="VbaWindow" )
{
methodx:="scrolltoscrollbarparent"
parent:=ctrl
scrollbarx:="scrollbar2"
}
}
if( regexmatch(ctrlclass,"^RichEdit20W(PT)?$")==1 ) // Windows Text Areas
{
methodx:="wheel"
methody:="scroll"
}
if( class=="AcrobatSDIWindow" ) // Adobe Reader
{
if( regexmatch(parentname,"AVL_AVView")==1 )
{
ctrl:=getdescendant(parent,"AVL_AVView4")
if( ctrl=="" )
{
ctrl:=getdescendant(parent,"AVL_AVView1")
}
methodx:="scrolltoscrollbarparent"
scrollbarx:="scrollbar1"
methody:="wheel"
}
}
if( ggpname=="SHELLDLL_DefView1" ) // Windows Explorer Scrollbars
{
ctrl:=gp
ctrlname:=gpname
parentname:=ggpname
}
if( ctrlname=="DirectUIHWND1" )
{
if( parentname=="SHELLDLL_DefView1" ) // Windows Explorer (including Standard File Choosers)
{
methodx:="scrolltoscrollbar" // "scrolltoscrollbarparent" also works
scrollbarx:="scrollbar1"
controlget v,visible,,ScrollBar2,ahk_id %ctrl%
methody:=( v==1 ? "wheel" : "" )
}
if( class=="CabinetWClass" )
{
if( parentname=="XBabyHost1" ) // Control Panel
{
methody:="scrolltoscrollbar" // "scrolltoscrollbarparent" also works
scrollbary:="scrollbar1"
if( title=="Personalization" )
{
scrollbary:="scrollbar3"
}
}
}
}
if( ctrlclass=="CharGridWClass" ) // Character Map
{
methody:="scrolltoscrollbarparent"
scrollbary:="scrollbar1"
}
if( class=="ConsoleWindowClass" ) // Console Window
{
methodx:="thumbpos"
methody:="thumbpos"
}
if( class=="WordPadClass" ) // WordPad
{
methodx:="scroll"
methody:="scroll" // WordPad scroll down is broken when scrolling horizontally at the same time
}
if( class=="ATL:006AD5B8" ) // Programmer's Notepad
{
methodx:="scroll"
}
if( class=="SWT_Window0" or ctrlclass=="Internet Explorer_Server" ) // Eclipse
{
methodx:="scroll"
}
if( ctrlclass=="TSynEdit" ) // TSynEdit ; Dev C++ , ...
{
methodx:="thumbpos"
methody:="thumbpos"
}
if( ctrlclass=="TListView" ) // TlistView ; Dev C++ , ...
{
methodx:="scroll"
}
if( ctrlclass=="TPSSynEdit" ) // TPSSynEdit ; PSPad , ...
{
methodx:="thumbpos"
}
if( class=="QWidget" or class=="Qt5QWindowIcon" )
{
if( regexmatch(title,"LyX")==1 ) // Lyx
{
methodx:=""
// prevents horizontal scrolling from becoming vertical scrolling in the edit pane
// but disables horizontal scrolling everywhere else
}
if( regexmatch(title,"TeXworks$")>0 ) // TeXWorks
{
methodx:="wheelint"
methody:="wheelint"
}
}
if( class=="gdkWindowToplevel" ) // Gimp
{
methody:="wheelsingle" // Gimp performs horizontal scrolling when the mouse is scrolled over the horizontal scrollbar
}
if( class=="SunAwtDialog" ) // Java AWT Dialogs ; GeoGebra , Logisim , ...
{
methody:="wheelint"
}
if( regexmatch(ctrlname,"IupCanvas")==1 ) // IupCanvas
{
methodx:="scroll"
}
if( class=="SunAwtFrame" )
{
if( regexmatch(title,"GeoGebra|.*\.ggb$")==1 ) // GeoGebra
{
methody:="wheelint"
}
if( regexmatch(title,"Logisim")==1 ) // Logisim
{
methodx:="keys" // performs scrolling only if the drawing area has the focus
}
}
if( class=="MSPaintApp" ) // MSPaint
{
if( parentname=="MSPaintView1" )
{
methodx:="thumbpos"
methody:="thumbpos"
}
}
if( class=="ATL:643E3490" ) // Real World Paint
{
if( ctrlclass=="RWViewImageEdit" )
{
methodx:="scroll"
methody:="scroll"
}
}
if( ctrlclass=="DSUI:PagesView" ) // PDF-XChange Viewer (also as a browser plugin)
{
methodx:="scroll"
methody:="wheelint"
}
if( ctrlclass=="PuTTY" ) // PuTTY
{
methody:="scroll"
}
if( dbg )
{
p:=getparent(ctrl)
gp:=getparent(p)
ggp:=getparent(gp)
message( "Root class = " class
. "`nRoot title = " title
. "`nTarget = [" ctrl0 "]"
. "`n`t(as child) " getnameaschild(ctrl0)
. "`n`t(at root) " getnameatroot(ctrl0)
. "`nControl = [" ctrl "]"
. "`n`t(at child) " getnameaschild(ctrl)
. "`n`t(as root) " getnameatroot(ctrl)
. "`nControl ancestors = "
. "`n`t < [" p "] " getnameatroot(p)
. "`n`t < [" gp "] " getnameatroot(gp)
. "`n`t < [" ggp "] " getnameatroot(ggp)
. "`nMethod = (" methodx "," methody ")"
. "`nScrollbars = (" scrollbarx "," scrollbary ")" )
}
}
scroll:
critical on
if( getwindow(getctrlat(mx,my))!=window )
{
scrolling:=0
}
if( scrolling==0 )
{
return
}
settimer scroll,-%interval%
if( scrollbeforeclick!=1 and scrolldrag==0 )
{
sx:=0
sy:=0
return
}
tx:=sx
ty:=sy
sx-=tx
sy-=ty
totalx+=tx
totaly+=ty
if( totalx**2+totaly**2>scrolllimit )
{
scrolldrag:=1
}
scrolladjust(tx,ty)
rx:=0
ry:=0
comobjerror(false)
if( tx!=0 )
{
if( methodx=="wheel" )
{
sendwheel("h",tx)
}
else if( methodx=="postwheel" )
{
postwheel("h",tx)
}
else
{
txi:=rtoz(tx)
rx:=tx-txi
if( txi!=0 )
{
if( methodx=="wheelint" )
{
sendwheel("h",txi)
}
else if( methodx=="wheelsingle" )
{
sendwheelsingle("h",txi)
}
else if( methodx=="thumbpos" )
{
sendthumbpos("h",txi)
}
else if( methodx=="scroll" )
{
sendscroll("h",txi)
}
else if( methodx=="scrolltoscrollbar" )
{
sendscrolltoscrollbar(scrollbarx,txi)
}
else if( methodx=="scrolltoscrollbarparent" )
{
sendscrolltoscrollbarparent(scrollbarx,"h",txi)
}
else if( methodx=="keys" )
{
sendkeys("h",txi)
}
else if( methodx=="keystoscrollbar" )
{
sendkeystoscrollbar(scrollbarx,txi)
}
else if( methodx=="office" )
{
Acc_ObjectFromWindow(ctrl,-16).SmallScroll(0,0,(txi>0?txi:0),(txi<0?-txi:0))
}
}
}
}
if( ty!=0 )
{
if( methody=="wheel" )
{
sendwheel("v",-ty)
}
else if( methody=="postwheel" )
{
postwheel("v",-ty)
}
else
{
tyi:=rtoz(ty)
ry:=ty-tyi
if( tyi!=0 )
{
if( methody=="wheelint" )
{
sendwheel("v",-tyi)
}
else if( methody=="wheelsingle" )
{
sendwheelsingle("v",-tyi)
}
else if( methody=="thumbpos" )
{
sendthumbpos("v",tyi)
}
else if( methody=="scroll" )
{
sendscroll("v",tyi)
}
else if( methody=="scrolltoscrollbar" )
{
sendscrolltoscrollbar(scrollbary,tyi)
}
else if( methody=="scrolltoscrollbarparent" )
{
sendscrolltoscrollbarparent(scrollbary,"v",tyi)
}
else if( methody=="keys" )
{
sendkeys("v",tyi)
}
else if( methody=="keystoscrollbar" )
{
sendkeystoscrollbar(scrollbary,tyi)
}
else if( methody=="office" )
{
Acc_ObjectFromWindow(ctrl,-16).SmallScroll((tyi>0?tyi:0),(tyi<0?-tyi:0))
}
}
}
}
comobjerror(true)
sx:=rx
sy:=ry
return
sendwheel(dir,amount)
{
t:=a_tickcount
msg:=( dir=="v" ? 0x20a : 0x20e )
flags:=getkeystate("Ctrl")<<3|getkeystate("Shift")<<2
amount*=120
while( amount>max16bit )
{
sendmessage msg,max16bit<<16|flags,mx|my<<16,,ahk_id %ctrl%,,,,timelimit
amount-=max16bit
if( a_tickcount-t>=timelimit )
{
return
}
}
while( amount<-max16bit )
{
sendmessage msg,-max16bit<<16|flags,mx|my<<16,,ahk_id %ctrl%,,,,timelimit
amount+=max16bit
if( a_tickcount-t>=timelimit )
{
return
}
}
sendmessage msg,round(amount)<<16|flags,mx|my<<16,,ahk_id %ctrl%,,,,timelimit
}
postwheel(dir,amount)
{
msg:=( dir=="v" ? 0x20a : 0x20e )
flags:=getkeystate("Ctrl")<<3|getkeystate("Shift")<<2
amount*=120
while( amount>max16bit )
{
postmessage msg,max16bit<<16|flags,mx|my<<16,,ahk_id %ctrl%
amount-=max16bit
}
while( amount<-max16bit )
{
postmessage msg,-max16bit<<16|flags,mx|my<<16,,ahk_id %ctrl%
amount+=max16bit
}
postmessage msg,round(amount)<<16|flags,mx|my<<16,,ahk_id %ctrl%
}
sendwheelsingle(dir,amount)
{
t:=a_tickcount
msg:=( dir=="v" ? 0x20a : 0x20e )
flags:=getkeystate("Ctrl")<<3|getkeystate("Shift")<<2
loop % abs(amount)
{
sendmessage msg,(amount<0?-120:120)<<16|flags,mx|my<<16,,ahk_id %ctrl%,,,,timelimit
if( a_tickcount-t>=timelimit )
{
return
}
}
}
sendthumbpos(dir,amount)
{
msg:=( dir=="v" ? 0x115 : 0x114 )
sb:=dllcall("GetScrollInfo","uint",ctrl,"int",(dir=="v"?1:0),"uint",&sbinfo)
if( sb )
{
sbmin:=numget(sbinfo,8,"int")
sbmax:=numget(sbinfo,12,"int")
sbpos:=numget(sbinfo,20,"int")
if( amount>max16bit )
{
amount=max16bit
}
if( amount<-max16bit )
{
amount=-max16bit
}
pos:=sbpos+amount
if( pos<sbmin )
{
pos:=sbmin
}
if( pos>sbmax )
{
pos:=sbmax
}
sendmessage msg,pos<<16|4,,,ahk_id %ctrl%,,,,timelimit
}
}
sendscroll(dir,amount)
{
t:=a_tickcount
msg:=( dir=="v" ? 0x115 : 0x114 )
flag:=( amount<0 ? 0 : 1 )
loop % abs(amount)
{
sb:=dllcall("GetScrollInfo","uint",ctrl,"int",(dir=="v"?1:0),"uint",&sbinfo)
if( sb )
{
sbmin:=numget(sbinfo,8,"int")
sbmax:=numget(sbinfo,12,"int")
sbpage:=numget(sbinfo,16,"uint")
sbpos:=numget(sbinfo,20,"int")
if( ( sbpos==sbmin and amount<0 ) or ( sbpos+sbpage==sbmax+1 and amount>0 ) )
{
return
}
}
sendmessage msg,flag,,,ahk_id %ctrl%,,,,timelimit
if( a_tickcount-t>=timelimit )
{
return
}
}
}
sendscrolltoscrollbar(name,amount)
{
t:=a_tickcount
flag:=( amount<0 ? 0 : 1 )
loop % abs(amount)
{
sendmessage 0x115,flag,,%name%,ahk_id %ctrl%,,,,timelimit
if( a_tickcount-t>=timelimit )
{
return
}
}
}
sendscrolltoscrollbarparent(name,dir,amount)
{
sb:=getdescendant(parent,name)
sbp:=getparent(sb)
t:=a_tickcount
msg:=( dir=="v" ? 0x115 : 0x114 )
flag:=( amount<0 ? 0 : 1 )
loop % abs(amount)
{
sendmessage msg,flag,sb,,ahk_id %sbp%,,,,timelimit
if( a_tickcount-t>=timelimit )
{
return
}
}
}
sendkeys(dir,amount)
{
t:=a_tickcount
key:=( dir=="v" ? ( amount<0 ? "{Up}" : "{Down}" ) : ( amount<0 ? "{Left}" : "{Right}" ) )
loop % abs(amount)
{
controlsend, ,%key%,ahk_id %ctrl%
if( a_tickcount-t>=timelimit )
{
return
}
}
}
sendkeystoscrollbar(name,amount)
{
t:=a_tickcount
key:=( amount<0 ? "{Up}" : "{Down}" )
controlget e,enabled,,%name%,ahk_id %parent%
if( e==1 )
{
loop % abs(amount)
{
controlsend %name%,%key%,ahk_id %parent%
if( a_tickcount-t>=timelimit )
{
break
}
}
}
}