Lorenzo501

Unhide Taskbar in Specific Fullscreen Windows (redundant).ahk

May 24th, 2024 (edited)
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.     This script simulates native non-fullscreen taskbar functionality in specific fullscreen windows. Unforcefully allowing the taskbar to be shown when the cursor reaches the
  3.     deactivated taskbar line (it won't activate the taskbar, so the taskbar retains its slide animation). On top of that, it is very lightweight due to the mouse hook it uses.
  4.     Tested with Windows 10 Pro 64-bit version 19045.4170 (22H2)
  5.  */
  6. #Requires AutoHotkey 2.1-alpha.9
  7. #NoTrayIcon
  8. Persistent()
  9. A_CoordModePixel := "Screen"
  10. A_KeyDelay := -1 ; For Send b/c it reverts to the Event SendMode when another AHK script installs a low-level keyboard hook
  11. A_WinDelay := -1
  12. ;GroupAdd("ChromeAndExclusion", "ahk_exe chrome.exe",, "YouTube")
  13. ;GroupAdd("ChromeAndTwoExclusions", "ahk_group ChromeAndExclusion",, "Steam")
  14. ;GroupAdd("ChromeAndThreeExclusions", "ahk_group ChromeAndTwoExclusions",, "IMDb")
  15. affectedWindows :=
  16. [
  17.     ; Use an array with only the parameters that you need:
  18.     ; ["WinTitle", "WinText", "ExcludeTitle", "ExcludeText"],
  19.  
  20.     ["Sourcetree ahk_exe SourceTree.exe"],
  21.     ;["ahk_group ChromeAndThreeExclusions"] ; In-cognito needs to get excluded completely for this to be useful^^
  22. ]
  23. Initialize()
  24. #HotIf (WinActive("ahk_group AffectedWindows"))
  25. ~LButton::
  26. ~F11::
  27.     ManageUnhiderState(*)
  28.     {
  29.         static fullscreenState := 2
  30.  
  31.         Sleep(100)
  32.         DllCall("Shell32\SHQueryUserNotificationState", "UInt*", &monitorState := 0)
  33.  
  34.         if (SharedMouseHook.IsEnabled)
  35.         {
  36.             ; The helper-GUI might've become active after the delay if the cursor clicked something near the taskbar, in that case it shouldn't deactivate the unhider
  37.             if (WinActive("ahk_group AffectedWindows") && monitorState != fullscreenState)
  38.                 DeactivateUnhider()
  39.         }
  40.         else if (monitorState = fullscreenState)
  41.         {
  42.             SharedMouseHook.IsEnabled := true
  43.             HelperGui.SetProperties("DefaultsOpposite", "Transparency")
  44.             HotIf()
  45.             Hotkey("F1", (*) => Hotkey("F1", "Off"), "On")
  46.             Send("{F1}") ; Necessary to make the taskbar immediately responsive (modifier key[s] being pressed by the user are ignored, even when SendMode reverts to Event)
  47.             SharedMouseHook.Instance.Start()
  48.         }
  49.     }
  50. #HotIf (WinActive(A_ScriptName " ahk_class AutoHotkeyGUI") && SharedMouseHook.IsEnabled)
  51. $F11::HelperGui.SetProperties("Defaults"), WinActivate(SharedMouseHook.AffectedContextWnd), Send("{F11}")
  52. $!Esc::HelperGui.SetProperties("Defaults"), WinActivate(SharedMouseHook.AffectedContextWnd), Send("!{Esc}")
  53.  
  54. ;********** LIBRARY **********
  55.  
  56. Initialize()
  57. {
  58.     HelperGui() ; Has to be manually initialized early, so that it's rdy when any of its members get used
  59.  
  60.     for (iteratedAffectedWnd in affectedWindows)
  61.         GroupAdd("AffectedWindows", iteratedAffectedWnd*)
  62.  
  63.     EVENT_SYSTEM_FOREGROUND := 0x0003
  64.     DllCall("SetWinEventHook", "UInt", EVENT_SYSTEM_FOREGROUND, "UInt", EVENT_SYSTEM_FOREGROUND, "Ptr", 0, "Ptr", CallbackCreate(HandleAffectedWinEvent), "UInt", 0, "UInt", 0, "UInt", 0)
  65.  
  66.     HandleAffectedWinEvent(hWinEventHook, event, hWnd, *)
  67.     {
  68.         if (WinActive("ahk_group AffectedWindows"))
  69.             ManageUnhiderState()
  70.         else if (!(WinActive(HelperGui.Id) && DetermineIsAffectedWindowBehindActive()) && SharedMouseHook.IsEnabled)
  71.             DeactivateUnhider()
  72.  
  73.         DetermineIsAffectedWindowBehindActive()
  74.         {
  75.             WS_CAPTION := 0xC00000 ; title bar
  76.  
  77.             for (iteratedId in WinGetList())
  78.                 if (WinActive(iteratedId) && WinGetClass(iteratedId) != "Progman")
  79.                     continue
  80.                 else if (DetermineIsAffectedWnd(iteratedId))
  81.                     return true
  82.                 else if (WinGetClass(iteratedId) = "Progman" || WinGetMinMax(iteratedId) != -1 && WinGetStyle(iteratedId) & WS_CAPTION && WinGetTitle(iteratedId) != "")
  83.                     return false
  84.  
  85.             DetermineIsAffectedWnd(winId)
  86.             {
  87.                 for (iteratedAffectedWnd in affectedWindows)
  88.                     if (WinExist(iteratedAffectedWnd*) = winId)
  89.                         return true
  90.  
  91.                 return false
  92.             }
  93.         }
  94.     }
  95. }
  96.  
  97. DeactivateUnhider()
  98. {
  99.         SharedMouseHook.IsEnabled := false
  100.         HelperGui.SetProperties("Defaults", "Transparency")
  101.         SharedMouseHook.Instance.Stop()
  102. }
  103.  
  104. class HelperGui
  105. {
  106.     static __New()
  107.     {
  108.         ; Preparation to remove helper-GUI icon from taskbar and Alt+Tab window
  109.         iid_ITaskbarList := "{56FDF342-FD6D-11d0-958A-006097C9A090}" ; Interface id (iid)
  110.         clsid_TaskbarList := "{56FDF344-FD6D-11d0-958A-006097C9A090}" ; Class id (clsid)
  111.         tbl := ComObject(clsid_TaskbarList, iid_ITaskbarList) ; Creates the TaskbarList object
  112.         this.Id := -1
  113.         EVENT_OBJECT_CREATE := 0x8000
  114.         DllCall("SetWinEventHook", "UInt", EVENT_OBJECT_CREATE, "UInt", EVENT_OBJECT_CREATE, "Ptr", 0, "Ptr", CallbackCreate(HandleHelperGuiEvent), "UInt", 0, "UInt", 0, "UInt", 0)
  115.  
  116.         loop (10)
  117.         {
  118.             try ComCall(3, tbl) ; Calls tbl.HrInit(), which initializes the TaskbarList object
  119.             catch
  120.                 Sleep(50)
  121.             else
  122.                 break
  123.         }
  124.  
  125.         HandleHelperGuiEvent(hWinEventHook, event, hWnd, *)
  126.         {
  127.             if (hWnd = this.Id)
  128.             {
  129.                 ComCall(5, tbl, "Ptr", hWnd) ; Calls tbl.DeleteTab(winId), which deletes a tab from the TaskbarList
  130.                 DllCall("UnhookWinEvent", "Ptr", hWinEventHook)
  131.             }
  132.         }
  133.  
  134.         ; Creating a helper-GUI, which is used for two things:
  135.         ; Always-on-top deactivated taskbar line makes it seem as if doesn't disappear in affected window & not always-on-top but active to unhide the taskbar when necessary
  136.         this._Gui := Gui("-DPIScale")
  137.         this._Gui.BackColor := PixelGetColor(A_ScreenWidth - 10, A_ScreenHeight - 1) ; The color is retrieved from a taskbar area of which its color never changes
  138.         this.Id := WinExist(this._Gui)
  139.         this.SetProperties("Defaults", "Transparency") ; Initially invisible (it gets made visible when necessary) and always-on-top (it exits this state when necessary)
  140.         WinSetStyle("-0xC00000", this._Gui) ; Removing the title bar
  141.         this._Gui.Show("w" A_ScreenWidth " h2 y" A_ScreenHeight - 2) ; This will make it pretend to be the deactivated taskbar line (b/c the taskbar is hiding completely in fullscreen)
  142.         ComCall(5, tbl, "Ptr", this.Id) ; Calls tbl.DeleteTab(winId), which deletes a tab from the TaskbarList (is extra, in case if HandleHelperGuiEvent didn't succeed doing it early)
  143.     }
  144.  
  145.     static SetProperties(setMode, transparencyMode := "SkipTransparency")
  146.     {
  147.         if (setMode = "Defaults")
  148.         {
  149.             this.HasActivated := false
  150.             WinSetAlwaysOnTop(true, this._Gui)
  151.  
  152.             if (transparencyMode = "Transparency")
  153.                 WinSetTransparent(0, this._Gui)
  154.         }
  155.         else if (setMode = "DefaultsOpposite")
  156.         {
  157.             if (transparencyMode = "Transparency")
  158.                 WinSetTransparent("Off", this._Gui)
  159.             else
  160.             {
  161.                 this.HasActivated := true
  162.                 WinSetAlwaysOnTop(false, this._Gui)
  163.             }
  164.         }
  165.     }
  166.  
  167.     static MoveToRelevantMonitor()
  168.     {
  169.         if (MonitorGetCount() > 1)
  170.             this._Gui.Move(Monitor.ContextInfo.RcMonitor.LeftX, Taskbar.DeactivatedContextY, Taskbar.ContextWidth, 2)
  171.     }
  172. }
  173.  
  174. class Cursor
  175. {
  176.     static IsOnRelevantDeactivatedTaskbarLine
  177.     {
  178.         get
  179.         {
  180.             Monitor()
  181.  
  182.             return this.Y >= Taskbar.DeactivatedContextY && this.DetermineIsOnActiveWindowMonitor()
  183.         }
  184.     }
  185.  
  186.     static IsOffRelevantDeactivatedTaskbarFalseOnError
  187.     {
  188.         get
  189.         {
  190.             return DetermineIsOffRelevantTaskbarFalseOnError(&currentTaskbarY) && this.DetermineIsOnActiveWindowMonitor() && currentTaskbarY = Taskbar.DeactivatedContextY
  191.  
  192.             DetermineIsOffRelevantTaskbarFalseOnError(&currentTaskbarY)
  193.             {
  194.                 Monitor()
  195.  
  196.                 try WinGetPos(, &currentTaskbarY,,, Monitor.ContextInfo.DwFlags = this.MONITORINFOF_PRIMARY ? "ahk_class Shell_TrayWnd" : "ahk_class Shell_SecondaryTrayWnd")
  197.                 catch
  198.                     return false
  199.  
  200.                 return this.Y < currentTaskbarY
  201.             }
  202.         }
  203.     }
  204.  
  205.     static __New() => this.MONITORINFOF_PRIMARY := 1
  206.     __New(x, y) => (Cursor.X := x, Cursor.Y := y)
  207.     static DetermineIsOnActiveWindowMonitor() => this.X >= Monitor.ContextInfo.RcMonitor.LeftX && this.X <= Monitor.ContextInfo.RcMonitor.RightX
  208. }
  209.  
  210. class Monitor
  211. {
  212.     __New() => DllCall("GetMonitorInfo", "Ptr", DllCall("MonitorFromWindow", "UInt", WinExist("A"), "UInt", MONITOR_DEFAULTTOPRIMARY := 1), "Ptr", Monitor.ContextInfo := MonitorInfo())
  213. }
  214.  
  215. class Taskbar
  216. {
  217.     static DeactivatedContextY => Monitor.ContextInfo.RcMonitor.BottomY - 2
  218.     static ContextWidth => Monitor.ContextInfo.RcMonitor.RightX - Monitor.ContextInfo.RcMonitor.LeftX
  219.  
  220.     static __New() => this.ContextClass := 0
  221. }
  222.  
  223. class Rect
  224. {
  225.     LeftX: i32, TopY: i32, RightX: i32, BottomY: i32
  226. }
  227.  
  228. class MonitorInfo
  229. {
  230.     CbSize: i32 := ObjGetDataSize(this), RcMonitor: Rect, RcWork: Rect, DwFlags: i32
  231. }
  232.  
  233. class SharedMouseHook
  234. {
  235.     static __New()
  236.     {
  237.         this.Instance := PointerDeviceHook("Move", HandleMouseMoveEvent(eventInfo)
  238.         {
  239.             Cursor(eventInfo.Pt.X, eventInfo.Pt.Y)
  240.  
  241.             if (!HelperGui.HasActivated && Cursor.IsOnRelevantDeactivatedTaskbarLine)
  242.             {
  243.                 HelperGui.SetProperties("DefaultsOpposite")
  244.                 HelperGui.MoveToRelevantMonitor()
  245.                 SharedMouseHook.AffectedContextWnd := WinExist("A")
  246.                 WinActivate(HelperGui.Id)
  247.             }
  248.             else if (HelperGui.HasActivated && Cursor.IsOffRelevantDeactivatedTaskbarFalseOnError)
  249.             {
  250.                 HelperGui.SetProperties("Defaults")
  251.                 WinActivate(SharedMouseHook.AffectedContextWnd)
  252.             }
  253.         }, true)
  254.         this.IsEnabled := false
  255.         this.AffectedContextWnd := 0
  256.     }
  257. }
  258.  
  259. class Point
  260. {
  261.     X: i32, Y: i32
  262. }
  263.  
  264. /*
  265. Example usage: (hook := PointerDeviceHook("Move|LButton Down|LButton Up", HandlePointerDeviceEvent)).Start()
  266. /** @param {PointerDeviceHook.EventInfo} eventInfo Relevant event info */`
  267. HandlePointerDeviceEvent(eventInfo)
  268. {
  269.     ToolTip(Format("
  270.    (
  271.        x{1}, y{2}
  272.         EventAction : {3}
  273.         EventKey    : {4}
  274.         KeyUsageCount   : {5}
  275.         KeyUsageTime    : {6}
  276.         PressDuration   : {7}
  277.         IsPenAction : {8}
  278.    )", eventInfo.Pt.X, eventInfo.Pt.Y, eventInfo.Action, eventInfo.Key, eventInfo.KeyUsageCount, eventInfo.KeyUsageTime, eventInfo.KeyPressDuration, eventInfo.IsPenAction))
  279. }
  280. */
  281. class PointerDeviceHook
  282. {
  283.     class InternalEventInfo
  284.     {
  285.         Pt: Point
  286.         MouseData: i32 ; Necessary cast to "Int"
  287.         Flags: u32
  288.         Time: u32
  289.         ExtraInfo: uptr
  290.     }
  291.  
  292.     class EventInfo
  293.     {
  294.         Pt => PointerDeviceHook.EventInfo.IsKeyPressedDown && this._IsPtAdaptive ? PointerDeviceHook.EventInfo.LatestPt : this._Pt
  295.  
  296.         /** @prop {string} Action The event action */
  297.         Action => PointerDeviceHook.EventInfo.IsKeyPressedDown ? (PointerDeviceHook.EventInfo.LatestAction ?? this._Action) : this._Action
  298.         /** @prop {string} Key The event key */
  299.         Key => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.KeyToKeep : this._Key
  300.         /** @prop {integer} KeyUsageCount Count how many times a key gets pressed in a short time (`KeyUsageCountTimeThreshold`) */
  301.         KeyUsageCount => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.KeyUsageCountToKeep : this._KeyUsageCount
  302.         /** @prop {string} KeyUsageTime The time when the event key was pressed, scrolled, or used for a pen action */
  303.         KeyUsageTime => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.KeyUsageTimeToKeep : this._KeyUsageTime
  304.         /** @prop {integer} KeyPressDuration The time elapsed since this key was pressed */
  305.         KeyPressDuration => (this.KeyUsageTime ? A_TickCount - this.KeyUsageTime : 0)
  306.         /** @prop {integer} IsPenAction Whether or not the event is caused by a pen pointer device (not detected when using drawing tablet) */
  307.         IsPenAction => PointerDeviceHook.EventInfo.IsKeyPressedDown ? PointerDeviceHook.EventInfo.IsPenActionToKeep : this._IsPenAction
  308.         /** @prop {boolean} IsKeyPressedDown The hook does not repeatedly trigger the down event while a key is pressed down, so those `onEvent` callbacks use timer & keeps relevant info */
  309.         static IsKeyPressedDown := false
  310.         static __New() => this.LatestPt := Point()
  311.         __New() => this._Pt := Point()
  312.     }
  313.     /** @prop {Map} MsgList A list of actions and message codes */
  314.     MsgList := Map(
  315.         512, "Move",
  316.         513, "LButton Down",
  317.         514, "LButton Up",
  318.         516, "RButton Down",
  319.         517, "RButton Up",
  320.         519, "MButton Down",
  321.         520, "MButton Up",
  322.         522, "Wheel",
  323.         523, "XButton{:d} Down",
  324.         524, "XButton{:d} Up")
  325.     /** @prop {integer} ProcHandle SetWindowsHookEx */
  326.     ProcHandle := 0
  327.     /** @prop {Map} PriorKeyObjects The map logs the time of when keys were previously pressed, as well as the count (both saved inside an object which is associated with a key) */
  328.     PriorKeyObjects := Map()
  329.     /** @prop {integer} KeyUsageCountTimeThreshold The time in which the usage of the event key gets counted, or reset when the time threshold is reached (milliseconds) */
  330.     KeyUsageCountTimeThreshold := 500
  331.     /**
  332.      * @param {string} [action="All"] Move, LButton Down, MButton Up, etc (the `MsgList` property shows all of them)
  333.      * @param {(hookObj) => Integer} onEvent This callback gets called on the event (to block mouse actions the callback must return true w/ default value `shouldMaintainResponsiveness`)
  334.      * @param {integer} [shouldMaintainResponsiveness=false] Default is False, causing it to call `onEvent` in this thread in favor of mouse-action-blocking capability (consider using timer
  335.      * in `onEvent`). Specify True to call it in a different thread if the `onEvent` code causes considerable mouse lag, as a result the Proc becomes incapable of blocking mouse actions
  336.      * @param {integer} [criticalMode=0] Default is Disabled Mode. A (positive) Enabled Mode value is the message check interval. Specifying -1 turns on Critical but disables message checks
  337.      */
  338.     __New(action := "All", onEvent := (*) => 0, shouldMaintainResponsiveness := false, criticalMode := 0)
  339.     {
  340.         static WM_LBUTTONUP := 0x0202, WM_RBUTTONUP := 0x0205, WM_MBUTTONUP := 0x0208, WM_MOUSEWHEEL := 0x020A, WM_XBUTTONDOWN := 0x020B, WM_XBUTTONUP := 0x020C
  341.             , LLMHF_INJECTED := 0x00000001, MI_WP_SIGNATURE := 0xFF515700, SIGNATURE_MASK := 0xFFFFFF00
  342.  
  343.         ; This callback gets executed when a pointer-device hook event occurs. The fast mode should be used only when it is known exactly which thread(s) this callback will be called from
  344.         this.InternalCallback := CallbackCreate(PointerDeviceProc, (criticalMode && criticalMode != "Off") ? "F" : unset, 3)
  345.  
  346.         PointerDeviceProc(nCode, wParam, lParam)
  347.         {
  348.             if (criticalMode = -1 || criticalMode)
  349.                 Critical(criticalMode)
  350.  
  351.             internalEventInfo := StructFromPtr(PointerDeviceHook.InternalEventInfo, lParam)
  352.             eventInfo := PointerDeviceHook.EventInfo()
  353.             eventInfo._IsPtAdaptive := false
  354.             eventInfo._Key := 0
  355.  
  356.             switch (wParam)
  357.             {
  358.                 ; internalEventInfo.MouseData contains a reserved low-order word, which we don't need, and the high-order word is the leftmost 16 bits (bitshift removes the rest)
  359.                 case WM_MOUSEWHEEL: eventInfo._Action := (internalEventInfo.MouseData >> 16) > 0 ? "WheelUp" : "WheelDown"
  360.                 case WM_XBUTTONDOWN, WM_XBUTTONUP: eventInfo._Action := Format(this.MsgList[wParam], internalEventInfo.MouseData >> 16)
  361.                 default: eventInfo._Action := this.MsgList.Has(wParam) ? this.MsgList[wParam] : 0
  362.             }
  363.  
  364.             if (nCode < 0 || (action != "All" && !InStr(action, eventInfo._Action)))
  365.                 return CallNextHookEx(nCode, wParam, lParam)
  366.  
  367.             if (eventInfo._Action && eventInfo._Action != "Move")
  368.             {
  369.                 isKeyUpEvent := false
  370.  
  371.                 switch (wParam)
  372.                 {
  373.                     case WM_LBUTTONUP, WM_RBUTTONUP, WM_MBUTTONUP, WM_XBUTTONUP: isKeyUpEvent := true
  374.                 }
  375.  
  376.                 if (eventInfo._Key != eventInfo._Action)
  377.                     eventInfo._Key := eventInfo._Action
  378.  
  379.                 if (!this.PriorKeyObjects.Has(eventInfo._Action))
  380.                     this.PriorKeyObjects[eventInfo._Action] := {Time: internalEventInfo.Time, Count: 0}
  381.  
  382.                 priorKey := this.PriorKeyObjects[eventInfo._Action]
  383.                 eventInfo._KeyUsageCount := priorKey.Count += internalEventInfo.Time - priorKey.Time < this.KeyUsageCountTimeThreshold ? 1 : -priorKey.Count + 1 ; Resets to 1 if false
  384.                 eventInfo._KeyUsageTime := priorKey.Time := internalEventInfo.Time
  385.                 eventInfo._IsPenAction := DetermineIsPenAction(internalEventInfo.ExtraInfo)
  386.                
  387.                 if (isKeyUpEvent || wParam = WM_MOUSEWHEEL)
  388.                 {
  389.                     eventInfo._Pt.X := internalEventInfo.Pt.X
  390.                     eventInfo._Pt.Y := internalEventInfo.Pt.Y
  391.                     PointerDeviceHook.EventInfo.IsKeyPressedDown := false
  392.                 }
  393.                 else
  394.                 {
  395.                     eventInfo._IsPtAdaptive := true
  396.                     PointerDeviceHook.EventInfo.LatestPt.X := internalEventInfo.Pt.X
  397.                     PointerDeviceHook.EventInfo.LatestPt.Y := internalEventInfo.Pt.Y
  398.                     PointerDeviceHook.EventInfo.LatestAction := unset
  399.                     PointerDeviceHook.EventInfo.KeyToKeep := eventInfo._Key
  400.                     PointerDeviceHook.EventInfo.KeyUsageCountToKeep := eventInfo._KeyUsageCount
  401.                     PointerDeviceHook.EventInfo.KeyUsageTimeToKeep := internalEventInfo.Time
  402.                     PointerDeviceHook.EventInfo.IsPenActionToKeep := eventInfo._IsPenAction
  403.                     PointerDeviceHook.EventInfo.IsKeyPressedDown := true
  404.                     SetTimer(() => (this.ProcHandle && PointerDeviceHook.EventInfo.IsKeyPressedDown ? onEvent(eventInfo) : SetTimer(, 0)), 50)
  405.                 }
  406.             }
  407.             else if (PointerDeviceHook.EventInfo.IsKeyPressedDown)
  408.             {
  409.                 PointerDeviceHook.EventInfo.LatestPt.X := eventInfo._Pt.X := internalEventInfo.Pt.X
  410.                 PointerDeviceHook.EventInfo.LatestPt.Y := eventInfo._Pt.Y := internalEventInfo.Pt.Y
  411.                 PointerDeviceHook.EventInfo.LatestAction := eventInfo._Action
  412.             }
  413.             else
  414.             {
  415.                 eventInfo._Pt.X := internalEventInfo.Pt.X
  416.                 eventInfo._Pt.Y := internalEventInfo.Pt.Y
  417.                 eventInfo._KeyUsageTime := eventInfo._KeyUsageCount := eventInfo._Key := 0
  418.                 eventInfo._IsPenAction := DetermineIsPenAction(internalEventInfo.ExtraInfo)
  419.             }
  420.  
  421.             if (shouldMaintainResponsiveness)
  422.             {
  423.                 SetTimer(() => onEvent(eventInfo), -1)
  424.  
  425.                 return CallNextHookEx(nCode, wParam, lParam)
  426.             }
  427.             else
  428.                 return onEvent(eventInfo) && !(internalEventInfo.Flags & LLMHF_INJECTED) ? true : CallNextHookEx(nCode, wParam, lParam)
  429.         }
  430.  
  431.         DetermineIsPenAction(extraInfo) => ((extraInfo & SIGNATURE_MASK) = MI_WP_SIGNATURE)
  432.         CallNextHookEx(nCode, wParam, lParam) => DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "UPtr", wParam, "Ptr", lParam)
  433.     }
  434.  
  435.     /** Warning: Take caution when blocking mouse actions, you should not call this inside a mouse hotkey prefixed w/ the (~) tilde symbol (to make `Stop` unblock mouse actions properly) */
  436.     Start()
  437.     {
  438.         if (!this.ProcHandle)
  439.             this.ProcHandle := DllCall("SetWindowsHookEx", "Int", WH_MOUSE_LL := 14, "Ptr", this.InternalCallback, "Ptr", GetModuleHandle(), "UInt", 0)
  440.         GetModuleHandle() => DllCall("GetModuleHandle", "UInt", 0, "Ptr")
  441.     }
  442.    
  443.     Stop()
  444.     {
  445.         if (this.ProcHandle && DllCall("UnhookWindowsHookEx", "Ptr", this.ProcHandle))
  446.             this.ProcHandle := 0
  447.     }
  448.     __Delete() => (this.InternalCallback && (this.Stop(), CallbackFree(this.InternalCallback), this.InternalCallback := 0))
  449. }
Add Comment
Please, Sign In to add comment