AutoHotkey-Bildlauf, mittlerer Klick und Mausbeschleunigung

3344
user21820

Probleme

Angenommen, ein Windows 7-Computer, insbesondere ein Laptop.

  1. Kein Maustreiber erlaubt es, die rechte Maustaste gedrückt zu halten und die Maus zum Scrollen zu bewegen, wobei die Funktionalität der rechten Maustaste erhalten bleibt. Dies ist nützlich, wenn Sie keine mittlere Taste haben.
  2. Maustreiber funktionieren für einige Anwendungen nicht und einige wie UltraNav fühlen sich bei den meisten Anwendungen, in denen sie arbeiten, sehr ruckartig.
  3. Der UltraNav-Treiber für das ThinkPad lässt nicht zu, dass die mittlere Taste gleichzeitig als mittlerer Klick fungiert, während das Scrollen durch Gedrückthalten und Bewegen der Maus möglich ist.
  4. Der UltraNav-Treiber erlaubt auch kein Klicken und Ziehen gleichzeitig mit dem Bildlauf, was beim Bearbeiten von Dokumenten äußerst nützlich ist.
  5. Beschleunigtes Scrollen ist mit einer Radmaus nicht möglich und wird vom UltraNav-Treiber schlecht durchgeführt.
  6. Mit dem Standard-Maustreiber ist die schnellstmögliche Zeigergeschwindigkeit insbesondere für ThinkPad-Trackpoints möglicherweise noch viel zu langsam und anstrengend.

Was ich mir gewünscht habe, war ein AutoHotkey-Skript, um all diese Probleme zu lösen, aber nichts, was ich online gefunden habe, ist so gut wie nur ein paar von ihnen. Nach zwei Jahren habe ich unten eine Komplettlösung entwickelt. Natürlich wurden einige Techniken, die ich verwendet habe, von verschiedenen Stellen im Internet aus angepasst, aber oft hatte jeder Beitrag nur eine oder zwei der Methoden und funktioniert daher nicht für viele Anwendungen.

Kommentare sind willkommen! Bitte haben Sie jedoch Verständnis dafür, dass ich möglicherweise keine Zeit habe, Vorschläge zu implementieren oder Fehler zu beheben, falls dies für Sie nicht funktioniert. Vielen Dank!

1
Ich verwende [AutoHotkey] (https://autohotkey.com/download) v1.1.10.01, aber dieses Skript sollte auch in späteren Versionen funktionieren. user21820 vor 7 Jahren 0

3 Antworten auf die Frage

1
user21820

Ich habe mein eigenes AutoHotkey-Skript entworfen, das einen einfachen Maushaken verwendet, um alle oben genannten Probleme zu lösen. Der Code ist zu lang. Sehen Sie sich die andere Antwort für den Code an.

Wichtige Hinweise

Verwenden Sie die 32-Bit-Version von AutoHotkey, auch wenn Sie 64-Bit-Windows verwenden. Andernfalls funktioniert sie an manchen Stellen nicht! Führen Sie das Skript beim Anmelden mit den höchstmöglichen Berechtigungen für den Benutzer mithilfe des Taskplaners aus. Andernfalls funktioniert es nicht für einen Admin-Benutzer in Anwendungen, die mit vollständigen Administratorrechten ausgeführt werden. Wenn Sie UltraNav installiert haben, wählen Sie "Smooth" für die mittlere Maustaste. Andernfalls wird das Skript aus unbekannten Gründen beeinträchtigt, und das Scrollen funktioniert nicht.

In seltenen Fällen kann mit dem Maushaken ein Fehler auftreten, insbesondere wenn Sie versuchen, einen Bildlauf durchzuführen, während eine Anwendung ihre GUI ändert. Ich vermute, es liegt daran, dass ich es nicht mit Echtzeitpriorität betreibe, aber ich denke, es ist zu riskant, denn wenn es feststeckt, gibt es keine Möglichkeit, es zu stoppen. Zur Zeit läuft es mit hoher Priorität. Wenn etwas schief geht, probieren Sie die folgenden Hotkeys nacheinander aus.

LCtrl-RCtrl: Neu laden. RCtrl-LCtrl: Deaktivieren Sie den Maushaken. (Wenn Ihre Maus jetzt funktioniert, laden Sie sie erneut.) RCtrl-Esc: Deaktivieren Sie das gesamte Skript. (Sie müssen es erneut ausführen.)

Eigenschaften

  1. Standardmäßig wird ein Bildlauf ausgeführt, wenn die mittlere Maustaste gedrückt und die Maus bewegt wird. Sie können rightbuttonscroll:=1stattdessen die rechte Maustaste verwenden (insbesondere für Laptops, die keine mittlere Maustaste haben). In diesem Fall müssen Sie möglicherweise eine zusätzliche STRG / UMSCHALTTASTE / UMSCHALTTASTE drücken, um die ursprüngliche Rechtsklick / Ziehen-Funktion zu erhalten davor abhängig von der spezifischen Anwendung. (In den meisten Anwendungen entspricht mindestens eine dieser Kombinationen dem ursprünglichen Rechtsklick.)
  2. Wenn Sie keine mittlere Maustaste haben, können Sie auch festlegen leftrighttomiddle:=1, und wenn Sie dann sowohl die linke als auch die rechte Maustaste clicklimit(Millisekunden) drücken, wird die mittlere Taste gedrückt, und wenn Sie beide loslassen, wird die mittlere Taste losgelassen. Um die generierte mittlere Taste gedrückt zu halten, genügt es, nur eine der beiden echten Tasten gedrückt zu halten.
  3. Das Scrollen funktioniert unabhängig von anderen Maustasten. So können Sie zum Beispiel jederzeit scrollen, während Sie die linke Maustaste während eines Auswahlvorgangs gedrückt halten, sofern dies von der Anwendung unterstützt wird. (Bei einigen Anwendungen ist das Scrollen aus seltsamen Gründen nicht möglich.)
  4. Nach dem Drücken und Loslassen der Bildlaufschaltfläche (ob mittlere oder rechte Maustaste) wird standardmäßig clicklimitder ursprüngliche Bildlaufschaltflächen-Klick erzeugt. Wenn die Bildlaufschaltfläche länger gedrückt gehalten wird, ist der Bildlauf aktiviert und das Loslassen der Bildlaufschaltfläche erzeugt keinen Klick. Um das Scrollen auch während dieser anfänglichen Verzögerung zu aktivieren, legen Sie fest scrollbeforeclick:=1. Mit dieser Einstellung ist ein Klicken auch dann möglich, wenn bereits ein geringfügiger Bildlauf durchgeführt wurde, sofern dieser nicht überschritten wird scrolllimit.
  5. Das Scrollen ist etwas klebrig, was bedeutet, dass, wenn einer die Scroll-Taste versehentlich für weniger als loslässt resetdelay, sie so behandelt wird, als ob sie nicht aufgetreten wäre, und das Scrollen fortgesetzt wird. Dies bedeutet insbesondere, dass ein versehentliches Klicken am Ende des Bildlaufs nicht das ursprüngliche Klicken der Bildlaufschaltfläche erzeugt.
  6. Das Klicken ist auch etwas klebrig, was bedeutet, dass, wenn man eine Maustaste drückt, resetdelaynachdem eine Maustaste losgelassen wurde, diese angenommen wird
  7. Einige Anwendungen sind beim Scrollen sehr träge, so dass wir nicht zu viele Befehle für das Scrollen ausführen können. intervalist das Intervall zwischen Stapeln von an die Anwendung gesendeten bildlaufbezogenen Befehlen. In jedem Intervall werden alle Scroll-Aktionen des Benutzers zu einer Aktion zusammengefasst. Durch das Verringern des Intervalls reagiert der Benutzer schneller auf das Scrollen, kann jedoch schlecht konstruierte Anwendungen blockieren. Wenn eine Feinsteuerung gewünscht wird, kann man zu Beginn immer einen Standardwert festlegen gettargetund ihn je nach Anwendung anpassen.
  8. Einige Anwendungen benötigen wirklich zu lange für die Verarbeitung von Scrollbefehlen. Wenn also innerhalb eines Befehls kein Befehl verarbeitet wird timelimit, werden alle verbleibenden Befehle im Stapel für dieses Intervall abgebrochen.
  9. Sie können den Bildlauf durch Bearbeiten anpassen, um die Bildlaufgeschwindigkeit bei Mausgeschwindigkeit scrollamountzu ändern, oder durch Bearbeiten scrolladjust, um die Art und Weise des Bildlaufs zu ändern, wenn Sie die angesammelten Bildlaufmengen verwenden. Standardmäßig wird der Bildlauf in vertikaler oder horizontaler Richtung gefangen, wenn der Bildlaufwert in dieser Richtung mehr als fünfmal so groß ist wie in der anderen Richtung.
  10. Sie können auch die Mausgeschwindigkeit und -beschleunigung fein einstellen. Drücken Sie LCtrl-Ralt-D, um die aktuelle Mausgeschwindigkeit anzuzeigen, LCtrl-Ralt-Sdie Geschwindigkeit zu verringern und die Geschwindigkeit LCtrl-Ralt-Fzu erhöhen. Dadurch wird die Zeigergeschwindigkeit in den Mauseinstellungen geändert. Bearbeiten moveadjust, um die Art und Weise zu ändern, in der Zeigerbewegungen in Mausbewegungen umgewandelt werden. In der Standardeinstellung bleiben niedrige Geschwindigkeiten gleich und hohe Geschwindigkeiten werden mit 3 multipliziert, und es erfolgt ein fließender Übergang dazwischen. Außerdem wird jede Mausbewegung über die aktuelle und die nächste verteilt, da bei hohen Zeigergeschwindigkeiten die Hardware oder der Standardwert angezeigt wird Der Maustreiber erzeugt eine abgehackte Ausgabe. Stellen Sie sicher, dass moveadjustschnell läuft!

Methoden

Es gibt 11 verschiedene Bildlaufmethoden, die ich in verschiedenen Anwendungen entdeckt habe. Einige Anwendungen reagieren nur auf eine davon, was ziemlich ärgerlich ist. Die Methoden werden in den Kommentaren im Code selbst beschrieben. Es gibt jedoch keine zuverlässige Methode, um die richtige zu verwendende Methode zu bestimmen. Daher muss manuell angepasst werden gettarget, um die Methode für jede Anwendung auszuwählen, die nicht mit den Standard-Radnachrichten funktioniert. Versuchen Sie die Methoden in der Reihenfolge, in der sie vorkommen scroll. Für jede Methode müssen Sie möglicherweise mit dem Ändern der Ziele der Nachrichten experimentieren, und zwar ctrl,window,parententsprechend.

Um das Debugging umzuschalten, drücken Sie LCtrl-AppMenu. Es zeigt die rohen Bewegungen der Maus für die normale Bewegung und das Scrollen an. Wenn Sie die Scroll-Taste gedrückt halten, ohne die Maus zu bewegen, werden die Vorfahren sowohl des Ziels unter der Maus als auch der Steuerung mit angezeigt gettarget. Manchmal musste ich auch Spy ++ verwenden, um die Kontrollhierarchie zu sehen und zu raten, wohin die Nachrichten gesendet werden sollen.

Bemerkungen

Der 64-Bit-AutoHotkey führt dazu, dass mein Skript für den Editor von Programmer fehlschlägt, während der 32-Bit-AutoHotkey einwandfrei funktioniert, und ich weiß nicht warum. Andere Anwendungen scheinen kein solches Problem zu haben. Wenn es ein Fehler in meinem Skript ist, würde ich mich freuen zu wissen!

Das ist fantastisch! Bei Multi-Monitoren scheint es ein Problem zu geben. Wenn ich ihn mit 2 Monitoren (Win 10) betreibe, ist die Maus in der oberen linken Ecke "eingefangen", während sie auf einem einzelnen Monitor einwandfrei funktioniert. Haben Sie dafür ein Quell-Repo (scheint etwas in github oder dergleichen etwas schöner zu sein); Wenn Sie nicht interessiert sind, würden Sie sich freuen, wenn ich es in ein Repo stecke? askvictor vor 7 Jahren 0
Bei weiterer Betrachtung scheint es nicht so sehr um mehrere Monitore zu gehen, sondern um einen externen Monitor am Laptop - Wenn ich dieses Skript mit dem externen Monitor entweder als einzigen Monitor oder als erweiterter Monitor verwende, wird die Maus oben rechts eingeklemmt. Wenn ich das Skript nur mit dem Laptop-Monitor oder mit duplizierten Anzeigen verwende, funktioniert es einwandfrei. askvictor vor 7 Jahren 0
@askvictor: Ich habe kein Quell-Repository, da es nur ein persönliches Projekt war. Ich würde mich auf jeden Fall freuen, wenn Sie meinen Code unter der gleichen Lizenz wie unter SE veröffentlichen. Aber vorher wollen wir den seltsamen Fehler beheben. Könnten Sie "dbg" umschalten, indem Sie LCtrl + AppMenu drücken, oder diese Verknüpfung ändern (ganz oben) oder einfach "dbg: = true" einstellen und mir sagen, was im Meldungsfeld angezeigt wird, wenn Sie sich bewegen? user21820 vor 7 Jahren 0
Ich habe unter https://gist.github.com/askvictor/c4703ec76900542415e74a61057889a9 einen gist erstellt - aber wenn Sie sich lieber selbst (und mich selbst) einrichten möchten, lassen Sie es mich wissen und ich lösche es. Ich denke, diese Diskussion könnte auf github besser sein als hier? In jedem Fall zeigt das Debug-Meldungsfeld kleine positive Zahlen (normalerweise zwischen 0 und 20) für beide Dimensionen des Ursprungs und kleine negative (normalerweise zwischen -10 und 0) für beide Dimensionen beider Bewegungskoordinaten. askvictor vor 7 Jahren 0
@askvictor: Danke für die Einrichtung! Ich habe kein GitHub-Konto, aber wir können in einem Chatroom darüber diskutieren, wann die Option erscheint. Eine andere Person, die mein Skript verwendet, hat übrigens kein Problem, sowohl auf dem Laptop als auch auf einem externen Monitor, der an den Laptop angeschlossen ist (aber niemals mehrere Monitore ausprobiert hat). Die erste "Move" -Nummer ist der Rohwert und der zweite ist der vom Benutzer eingestellte Wert (für eine gleichmäßige Beschleunigung). Wenn der erste immer negativ ist, erklärt dies, warum die Maus nach links oben driftet. Dies kann jedoch ein Problem mit der WM_MOUSEMOVE-Meldung von AutoHotkey oder mousegetpos von Windows sein. user21820 vor 7 Jahren 0
@askvictor: Zuerst hatte ich den Verdacht, dass es sich um ein vorzeichenbehaftetes / vorzeichenloses Int-Problem oder ein 32/64-Bit-Problem handelt, aber ich gehe davon aus, dass die Diskrepanz in Positionen ein kleiner konstanter Vektor ist, wenn Sie sich überhaupt nicht bewegen. Wenn dies in Ihrem Fall der Fall ist, können Sie einen Fix hacken, indem Sie dies korrigieren und feststellen, ob dies auf beiden Monitoren funktioniert oder ob das Problem wieder auftritt, wenn Sie den Cursor auf den anderen Monitor bewegen. (Eine lustige Sache ist, wie dieser Beitrag 1400 mal angesehen wurde, aber die einzige positive Stellungnahme, die bisher von Ihnen kam, kam von Ihnen!) user21820 vor 7 Jahren 0
@askvictor: Ich habe einen separaten Fehler gefunden, der dazu führt, dass Feature 2 fehlschlägt. (Es hat in einer früheren Version funktioniert.) Ich werde in Kürze aktualisieren. Wie auch immer, lassen Sie uns [Ihre Diskussion im Chat fortsetzen] (http://chat.stackexchange.com/rooms/53900/discussion-between-user21820-and-askvictor). user21820 vor 7 Jahren 0
1
user21820

Der Code ist zu lang, so dass er in zwei Antworten aufgeteilt ist. In der dritten Antwort finden Sie die Anweisungen.

Code Teil 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 ? "" : "" ) : ( amount<0 ? "" : "" ) ) loop % abs(amount) { controlsend, ,%key%,ahk_id %ctrl% if( a_tickcount-t>=timelimit ) { return } } } sendkeystoscrollbar(name,amount) { t:=a_tickcount key:=( amount<0 ? "" : "" ) 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 } } } } 
1
user21820

Der Code ist zu lang, so dass er in zwei Antworten aufgeteilt ist. In der dritten Antwort finden Sie die Anweisungen.

Code Teil 2

scrollbuttonreset: scrollsticky:=0 return  scrollbuttoncannotclick: scrolldrag:=1 righttopress:=0 return  clickreset: clicksticky:=0 return  scrollbuttondown: critical on mousegetpos mx,my gettarget() sx:=0 sy:=0 totalx:=0 totaly:=0 settimer scroll,-%interval% settimer scrollbuttonreset,off return  scrollbuttonup: critical on if( scrolldrag==0 and scrollsticky==0 ) { handling++ sendevent {%buttonoriginal% down} sendevent {%buttonoriginal% up} handling-- scrolling:=0 } scrolldrag:=0 righttopress:=0 settimer scrollbuttondown,off settimer scrollbuttoncannotclick,off scrollsticky:=1 settimer scrollbuttonreset,-%resetdelay% return  leftdown: critical on lefttopress:=0 handling++ sendevent  handling-- return  rightdown: critical on righttopress:=0 handling++ sendevent  handling-- return  middledown: critical on scrolling:=0 scrolldrag:=0 middlepressed:=1 settimer scrollbuttondown,off settimer scrollbuttoncannotclick,off handling++ sendevent  handling-- return  leftup: critical on handling++ sendevent  handling-- clicksticky:=1 settimer clickreset,-%resetdelay% return  rightup: critical on handling++ sendevent  handling-- clicksticky:=1 settimer clickreset,-%resetdelay% return  middleup: critical on middlepressed:=0 handling++ sendevent  handling-- clicksticky:=1 settimer clickreset,-%resetdelay% return  leftclick: critical on gosub leftdown gosub leftup return  rightclick: critical on gosub rightdown gosub rightup return  // Mouse handler //  handlemouse(nCode,wParam,lParam) { critical on if( a_ispaused==1 ) { exitapp // something goes wrong if it remains paused } o:=0 if( handling==0 && nCode>=0 ) { if( wParam==0x201 ) { leftphysical:=1 } else if( wParam==0x204 ) { rightphysical:=1 } else if( wParam==0x202 ) { leftphysical:=0 } else if( wParam==0x205 ) { rightphysical:=0 } if( wParam==0x200 ) { // Handle mouse move // mousegetpos mx,my x:=numget(lParam+0,0,"int") // the "+0" is necessary! y:=numget(lParam+0,4,"int") // the "+0" is necessary! dx:=x-mx dy:=y-my if( scrolling==0 ) { // Click immediately on mouse drag // if( leftrighttomiddle==1 ) { if( lefttopress==1 ) { settimer leftdown,-0 } if( righttopress==1 ) { settimer rightdown,-0 } } // Adjust mouse movement // moveadjust(dx,dy) handling++ mousemove dx,dy,0,R handling-- if( dbg ) { message( "Origin = " mx " " my "`nMove = " x-mx " " y-my "`n -> " dx " " dy ) } // Release mouse buttons if out of sync with physical state // if( getkeystate("LButton")>leftphysical ) { settimer leftup,-0 } if( getkeystate("RButton")>rightphysical ) { settimer rightup,-0 } o:=1 } else { // Handle mouse move when scrolling // if( dx!=0 or dy!=0 ) { sx+=( dx>0 ? scrollamount(dx) : -scrollamount(-dx) ) sy+=( dy>0 ? scrollamount(dy) : -scrollamount(-dy) ) if( dbg ) { message( "Origin = " mx " " my "`nMove = " dx " " dy "`n -> " round(sx,2) " " round(sy,2) ) } } o:=1 } } else if( scrolling==0 ) { if( wParam==buttondown and middlepressed==0 and lefttopress==0 ) { // Handle scroll button down // if( getkeystate("Ctrl")==0 and getkeystate("Shift")==0 and getkeystate("Alt")==0 ) { // Handle scroll start // scrolling:=1 scrolldrag:=0 if( buttondown==0x204 ) { righttopress:=1 } settimer scrollbuttondown,-0 settimer scrollbuttoncannotclick,-%clicklimit% o:=1 } } } else if( scrolling==1 ) { if( wParam==buttonup ) { // Handle scroll button up // scrolling:=0 settimer scrollbuttonup,-0 o:=1 } } if( leftrighttomiddle==1 and o==0 ) { if( middlepressed==1 ) { // Release middle button only when both left and right buttons are released // if( leftphysical==0 and rightphysical==0 ) { settimer middleup,-0 } o:=1 } else if( scrolldrag==0 ) { // Process left+right=middle // if( wParam==0x201 and scrollsticky==0 ) { // Handle left button down // if( righttopress==0 ) { if( clicksticky==1 ) { settimer leftdown,-0 } else { lefttopress:=1 settimer leftdown,-%clicklimit% } } else { righttopress:=0 settimer rightdown,off settimer middledown,-0 } o:=1 } else if( wParam==0x204 and scrollsticky==0 ) { // Handle right button down // if( lefttopress==0 ) { if( clicksticky==1 ) { settimer rightdown,-0 } else { righttopress:=1 settimer rightdown,-%clicklimit% } } else { lefttopress:=0 settimer leftdown,off settimer middledown,-0 } o:=1 } else if( wParam==0x202 ) { // Handle left button up // if( lefttopress==1 ) { settimer leftdown,off settimer leftclick,-0 } else { settimer leftup,-0 } o:=1 } else if( wParam==0x205 ) { // Handle right button up // if( righttopress==1 ) { settimer rightdown,off settimer rightclick,-0 } else { settimer rightup,-0 } o:=1 } } } } // Pass on any other mouse events // if( o==0 ) { o:=dllcall("CallNextHookEx","uint",mousehook,"int",nCode,"uint",wParam,"uint",lParam) } return o }  // Utilities //  rtoz(r) { return ( r>0 ? floor(r) : ceil(r) ) } getparent(handle) { return dllcall("GetParent","uint",handle) } getancestor(handle,steps) { if( steps==0 ) { return handle } if( steps>0 ) { return getancestor(getparent(handle),steps-1) } return "" } getname(root,handle) { local CH,CN,S,P WinGet, CH, ControlListHwnd, ahk_id %root% WinGet, CN, ControlList, ahk_id %root% setformat integerfast,h handle+=0 handle.="" setformat integerfast,d LF:= "`n", CH:= LF CH LF, CN:= LF CN LF, S:= SubStr( CH, 1, InStr( CH, LF handle LF ) ) StringReplace, S, S,`n,`n, UseErrorLevel StringGetPos, P, CN, `n, L%ErrorLevel% Return SubStr( CN, P+2, InStr( CN, LF, 0, P+2 ) -P-2 ) } getdescendant(handle,name) { local CH,CN,S,P WinGet, CH, ControlListHwnd, ahk_id %handle% WinGet, CN, ControlList, ahk_id %handle% setformat integerfast,h handle+=0 handle.="" setformat integerfast,d LF:= "`n", CH:= LF CH LF, CN:= LF CN LF, S:= SubStr( CN, 1, InStr( CN, LF name LF ) ) StringReplace, S, S,`n,`n, UseErrorLevel StringGetPos, P, CH, `n, L%ErrorLevel% Return SubStr( CH, P+2, InStr( CH, LF, 0, P+2 ) -P-2 )*1 } getnameatroot(handle) { return getname(dllcall("GetAncestor","uint",handle,"uint",2),handle) } getnameaschild(handle) { return getname(getparent(handle),handle) } getclass(handle) { local class wingetclass class,ahk_id %handle% return class } gettitle(handle) { local title wingettitle title,ahk_id %handle% return title } getposition(handle,byref left,byref top,byref right,byref bottom) { local rect varsetcapacity(rect,16) dllcall("GetWindowRect","uint",handle,"uint",&rect) left:=numget(rect,0,"int") top:=numget(rect,4,"int") right:=numget(rect,8,"int") bottom:=numget(rect,12,"int") } getctrlat2(x,y,first,current) { /* Pushes the following invisible container controls to the back because they are in front of their contents for no reason SysTabControl32 : The usual class that contains tabbed panes ( Mouse properties, ... ) Static : A class occasionally used to contain tabbed panes ( Programmer's Notepad Options > Fonts and Colours > Advanced, ... ) Button : A typical class used to contain a List Box ( Outlook Contact > Properties > General > Members, ... ) Executes WindowFromPoint again to access the contents of such container controls */ local handle,class,style class:=getclass(current) winget style,style,ahk_id %current% if( class=="SysTabControl32" or class=="Static" or ( class=="Button" and (style&0x7)==0x7 ) ) { dllcall("SetWindowPos","uint",current,"uint",1,"int",0,"int",0,"int",0,"int",0,"uint",0x3) // push it to the back where it belongs handle:=dllcall("WindowFromPoint","int",x,"int",y) //handle:=DllCall( "WindowFromPoint", "int64", (y << 32) | (x & 0xFFFFFFFF), "Ptr") // for negative 64-bit if( handle==first ) { return first } return getctrlat2(x,y,first,handle) } return current } getctrlat(x,y) { local handle handle:=dllcall("WindowFromPoint","int",x,"int",y) //handle:=DllCall( "WindowFromPoint", "int64", (y << 32) | (x & 0xFFFFFFFF), "Ptr") // for negative 64-bit return getctrlat2(x,y,handle,handle) } getwindow(handle) { return dllcall("GetAncestor","uint",handle,"uint",2) }  Acc_Init() { Static h If Not h h:=DllCall("LoadLibrary","Str","oleacc","Ptr") } Acc_ObjectFromWindow(hWnd, idObject = -4) { local o Acc_Init() o:=DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81 ,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64") ,"Int64")  ,"Ptr*", pacc) if( o==0 ) Return ComObjEnwrap(9,pacc,1) }