jaberwacky Posted September 14, 2014 Share Posted September 14, 2014 (edited) This is my first working example of a script that I've been wanting for a while. I like the Windows Snap feature but I dislike that I have to switch from my mouse to my keyboard to use the feature for where my two monitors meet. So, I have hacked up this first impression. Please do try it out and tell me what you think! Yes, requires one of the latest AutoIt3 betas that supports the latest syntax additions. expandcollapse popup#AutoIt3Wrapper_Run_AU3Check=n #AutoIt3Wrapper_AU3Check_Parameters=-w 1 -w 2 -w 3 -w 4 -w 6 -w 7 -d -q #region ; Multi Monitor Window Snap #region ; Includes #include <APISysConstants.au3> #include <GUIMenu.au3> #include <Array.au3> #include <GDIPlus.au3> #include <WinAPIProc.au3> #include <WinAPIGdi.au3> #include <WinAPISys.au3> #include <WindowsConstants.au3> #include <BorderConstants.au3> #include <WinAPIsysinfoConstants.au3> #include <WindowsConstants.au3> #EndRegion #region ; Globals Const $monitor_count = _WinAPI_GetSystemMetrics($SM_CMONITORS) Const $monitor_height = _get_monitor_heights($monitor_count) Const $monitor_width = _get_monitor_widths($monitor_count) Const $desktop_width = _WinAPI_GetSystemMetrics($SM_CXVIRTUALSCREEN) Const $tallest_monitor = _ArrayMax($monitor_height) Const $desktop_left = _get_desktop_rect()[0] Const $half_desktop_width = $desktop_width / 2 Const $hEventProc = DllCallbackRegister(_event_proc, "none", "ptr;dword;hwnd;long;long;dword;dword") Const $hEventHook = _WinAPI_SetWinEventHook($EVENT_SYSTEM_MOVESIZESTART, $EVENT_SYSTEM_MOVESIZEEND, DllCallbackGetPtr($hEventProc)) Const $user32_dll = DllOpen("User32.dll") Const $marker_board = GUICreate('', $desktop_width, $tallest_monitor, 0, 0, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST, $WS_EX_TRANSPARENT)) GUISetState(@SW_SHOWNORMAL, $marker_board) Global $DesktopDC = _WinAPI_GetDC($marker_board) Global $DC = _WinAPI_CreateCompatibleDC($DesktopDC) Global $Bitmap = _WinAPI_CreateCompatibleBitmap($DesktopDC, $desktop_width, $tallest_monitor) _WinAPI_SelectObject($DC, $Bitmap) _GDIPlus_Startup() Global $Graphics = _GDIPlus_GraphicsCreateFromHDC($DC) Global $Pen = _GDIPlus_PenCreate(0xFFFFFFFF, 3) Const $mouse_proc_callback = DllCallbackRegister(_ll_mouse_proc, "long", "int;wparam;lparam") Const $hook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($mouse_proc_callback), _WinAPI_GetModuleHandle(0)) OnAutoItExitRegister(_on_exit) Const $range = 10 Global $window_focus, $left_snap, $right_snap, $active = False #EndRegion Do Sleep(1000) Until False #region ; Functions Volatile Func _ll_mouse_proc($code, $w_param, $l_param) Switch $code >= 0 Case True Switch $w_param Case $wm_mousemove If $active Then Local Const $mouse_pos = MouseGetPos() Select Case __WinAPI_PtInRectEx($mouse_pos, ($monitor_width[1] - $range), 0, $range, $monitor_height[1]) Local Const $left = ($monitor_width[1] + $desktop_left) / 2 Local Const $top = 0 Local Const $width = ($monitor_width[1] - $desktop_left) / 2 Local Const $height = $monitor_height[1] DrawRectangle($left, $top, $width, $height) $left_snap = True Case __WinAPI_PtInRectEx($mouse_pos, $monitor_width[1], 0, $range, $monitor_height[2]) Local Const $left = $monitor_width[1] Local Const $top = 0 Local Const $width = $monitor_width[2] / 2 Local Const $height = $monitor_height[2] DrawRectangle($left, $top, $width, $height) ConsoleWrite("Left: " & $left & @CRLF & _ "Top: " & $top & @CRLF & _ "Width: " & $width & @CRLF & _ "Height: " & $height & @CRLF & @CRLF) $right_snap = True Case Else Select Case $left_snap Or $right_snap ClearRectangle() $left_snap = False $right_snap = False EndSelect EndSelect EndIf Case $wm_lbuttondown $window_focus = _WinAPI_GetForegroundWindow() EndSwitch EndSwitch Return _WinAPI_CallNextHookEx($hook, $code, $w_param, $l_param) EndFunc Volatile Func _event_proc($hEventHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iThreadId, $iEventTime) Switch $iEvent Case $EVENT_SYSTEM_MOVESIZESTART $active = True Case $EVENT_SYSTEM_MOVESIZEEND If $active Then Select Case $left_snap ClearRectangle() Local Const $left = ($monitor_width[1] + $desktop_left) / 2 Local Const $top = 0 Local Const $width = ($monitor_width[1] - $desktop_left) / 2 Local Const $height = $monitor_height[1] WinMove($window_focus, "", $left, $top, $width, $height) Case $right_snap ClearRectangle() Local Const $left = $monitor_width[1] Local Const $top = 0 Local Const $width = $monitor_width[2] / 2 Local Const $height = $monitor_height[2] WinMove($window_focus, "", $left, $top, $width, $height) EndSelect $left_snap = False $right_snap = False $window_focus = Null $active = False EndIf EndSwitch EndFunc Func __WinAPI_PtInRectEx(Const $pos, Const $left, Const $top, Const $width, Const $height) Local Static $rect = DllStructCreate($tagRECT) With $rect .Left = $left .Top = $top .Right = $left + $width .Bottom = $top + $height EndWith Local Static $point = DllStructCreate($tagPOINT) With $point .X = $pos[0] .Y = $pos[1] EndWith Return DllCall($user32_dll, "bool", "PtInRect", "struct*", $rect, "struct", $point)[0] EndFunc Func _get_desktop_rect() Local Const $tWorkArea = DllStructCreate($tagRECT) _WinAPI_SystemParametersInfo($SPI_GETWORKAREA, 0, DllStructGetPtr($tWorkArea)) Local $rect[4] $rect[0] = DllStructGetData($tWorkArea, "Left") $rect[1] = DllStructGetData($tWorkArea, "Top") $rect[2] = DllStructGetData($tWorkArea, "Right") - $rect[0] $rect[3] = DllStructGetData($tWorkArea, "Bottom") - $rect[1] Return $rect EndFunc Func _get_real_parent(Const $hwnd) ; http://stackoverflow.com/questions/16872126/the-correct-way-of-getting-the-parent-window Local Const $hParent = _WinAPI_GetAncestor($hwnd, $GA_PARENT) If (Not $hParent) Or ($hParent = _WinAPI_GetDesktopWindow()) Then Return True EndIf Return False EndFunc Func _get_monitor_heights(Const $count) Local $height[($count + 1)] $height[0] = $count For $i = 1 To $height[0] $height[$i] = _get_monitor_info($i).Bottom Next Return $height EndFunc Func _get_monitor_widths(Const $count) Local $width[($count + 1)] $width[0] = $count For $i = 1 To $width[0] $width[$i] = _get_monitor_info($i).Right - _get_monitor_info($i).Left Next Return $width EndFunc Func _get_monitor_info(Const $monitor_number) If $monitor_number <= 0 Then Return SetError(1, 0, False) EndIf Local Const $monitor = _WinAPI_EnumDisplayMonitors()[$monitor_number][0] Return _WinAPI_GetMonitorInfo($monitor)[0] EndFunc Func DrawRectangle(Const $left, Const $top, Const $right, Const $bottom) _GDIPlus_GraphicsDrawRect($Graphics, $left, $top, $right, $bottom, $Pen) UpdateLayeredWindow() EndFunc Func ClearRectangle() _GDIPlus_GraphicsClear($Graphics, 0xFF000000) UpdateLayeredWindow() EndFunc Func UpdateLayeredWindow() Local Static $tSource = DllStructCreate($tagPOINT) Local Static $tSize = DllStructCreate($tagSIZE) DllStructSetData($tSize, 1, $desktop_width) DllStructSetData($tSize, 2, $tallest_monitor) Local Static $tBlend = DllStructCreate($tagBLENDFUNCTION) DllStructSetData($tBlend, "Alpha", 255) DllStructSetData($tBlend, "Format", 1) DllCall($user32_dll, "bool", "UpdateLayeredWindow", _ "hwnd", $marker_board, _ "handle", $DesktopDC, _ "ptr", 0, _ "struct*", $tSize, _ "handle", $DC, _ "struct*", $tSource, _ "dword", 0, _ "struct*", $tBlend, _ "dword", $ULW_ALPHA) EndFunc Volatile Func _on_exit() _WinAPI_UnhookWinEvent($hEventHook) _GDIPlus_PenDispose($Pen) _GDIPlus_GraphicsDispose($Graphics) _WinAPI_DeleteObject($Bitmap) _WinAPI_DeleteDC($DC) _GDIPlus_Shutdown() DllClose($user32_dll) DllCallbackFree($hEventProc) DllCallbackFree($mouse_proc_callback) EndFunc #EndRegion Edited September 16, 2014 by jaberwacky Helpful Posts and Websites: AutoIt3 Variables and Function Parameters MHz | AutoIt Wiki | Using the GUIToolTip UDF BrewManNH | Can't find what you're looking for on the Forum? Link to comment Share on other sites More sharing options...
UEZ Posted September 14, 2014 Share Posted September 14, 2014 (edited) I don't know yet how to test the code but I like the "style of coding" you have done here! I'm an oo noob and this code gives me some knowledge how to create objects. Maybe you can describe what to do to test it. Might be also nice to have some comments on the oo functions why you did it that way. Br, UEZ Edited September 14, 2014 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
jaberwacky Posted September 14, 2014 Author Share Posted September 14, 2014 (edited) To test this, first only two monitors are supported so far. Also, only the left monitor has the snap feature with a sensible snap behavior. But to test this, just take a window and hover it about ten pixels from the right edge of your first monitor. You should see a white rectangle outlining the area where that window would snap to if you were to release the mouse. So, gosh, these compliments mean a lot to me especially coming from you! Thank you. So, the way I use objects, and pretty much the best way to use them in AutoIt as far as I can tell though AutoItObject does support inheriting behaviors from other objects but not on the same level as c++ etc. I use them to make black boxes. The official UDFs have functions which are not meant to be called by ordinary users. These are denoted by two leading underscores. In an object, these functions could be declared "private" which autoitobject would then not allow the user to call, though you still could if you really wanted to. So, I think of a car as a black box. There are variables and functions that the car needs to operate but the driver only needs to have access to a few of them: steering wheel, accelerator pedal, and brake pedal. The private functions would be how much fuel each fuel injector receives based on how much air the engine is given. Or how many times per second to actuate the brake calipers by the ABS system in the event that the brake pedal were slammed by the driver. I could go on. Any questions, ask though I'm no expert. Edit: in my experience, GDI does not always lend itself well to autoitobject. Though you're far more knowledgeable about GDI so you might see ways that I haven't. Edited September 14, 2014 by jaberwacky Helpful Posts and Websites: AutoIt3 Variables and Function Parameters MHz | AutoIt Wiki | Using the GUIToolTip UDF BrewManNH | Can't find what you're looking for on the Forum? Link to comment Share on other sites More sharing options...
jaberwacky Posted September 14, 2014 Author Share Posted September 14, 2014 (edited) UEZ, I decided to autoitobjectify one of your scripts. This may not be the best example ever but it should give you a basic idea to go on. expandcollapse popup;coded by UEZ 2009-01-09 - thanks to smashly for _GDIPlus_BrushSetSolidColor() function :-) #AutoIt3Wrapper_Run_Obfuscator=y #Obfuscator_Parameters=/sf /sv /om /cs=0 /cn=0 #AutoIt3Wrapper_UseUpx=n ;~ #AutoIt3Wrapper_Run_After=upx.exe --best "%out%" #AutoIt3Wrapper_Run_After=upx.exe --ultra-brute "%out%" #AutoIt3Wrapper_Run_After=del "Flying Pearl Necklaces_Obfuscated.au3" #include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include "AutoItObject.au3" Opt('MustDeclareVars', 1) Opt("GUIOnEventMode", 1) _main() Func _main() Local Const $Pi = 4 * ATan(1) Local Const $pi_div_90 = $Pi / 90 Local Const $pi_div_120 = $Pi / 120 Local Const $pi_div_75 = $Pi / 75 Local Const $width = 400 Local Const $height = $width Local $k, $xcoord1, $ycoord1, $xcoord2, $ycoord2, $size, $red, $green, $blue Local $GUI = GUICreate("GDI+: Flying Pearl Necklaces by UEZ 2009", $width, $height) GUISetOnEvent($GUI_EVENT_CLOSE, _close) GUISetState(@SW_SHOW) _AutoItObject_Startup() Local $oGDI = _oGDI() $oGDI.Init($GUI, $width, $height) Local $i = -650 Local $l = $i Local $starting_point = 0 Local $min_size = 13 Local $i_p_j, $i_m_j, $h2, $w2, $sin_sp, $cos_sp Do $oGDI.GraphicsClear() ; clear buffer $k = 4096 ; 2^12 $starting_point -= 0.05 For $j = 0 To $k Step 32 $i_p_j = $i + $j $red = ((Sin($i_p_j * 0.001953125) + 1) * 0.5) * 256 ; 2/1024=0.001953125 $green = ((Sin($i_p_j * 0.0078125) + 1) * 0.5) * 256 ; 4/512=0.0078125 $blue = ((Sin($i_p_j * 0.03125) + 1) * 0.5) * 256 ; 8/256=0.03125 $oGDI.Brush1SetSolidColor($red, $green, $blue) $oGDI.Brush2SetSolidColor($red, $green, $blue) $size = $i - $j If $size > -$min_size And $size < $min_size Then $size = $min_size EndIf $i_m_j = $i - $j $sin_sp = Sin($starting_point) $cos_sp = Cos($starting_point) $h2 = $height / 2 $w2 = $width / 2 $xcoord1 = $w2 - ($i_m_j * 0.5) + $sin_sp * -Sin($i_m_j * $pi_div_90) * 64 $ycoord1 = $h2 - ($i_m_j * 0.5) + -$cos_sp * Cos($i_m_j * $pi_div_90) * 32 $oGDI.GraphicsFillEllipse1($xcoord1, $ycoord1, $size) $xcoord2 = $w2 - (-$i_m_j / -1.75) - $sin_sp * Sin($i_m_j * $pi_div_120) * 32 $ycoord2 = $h2 - ($i_m_j / -1.75) - $cos_sp * Cos($i_m_j * $pi_div_75) * 16 $oGDI.GraphicsFillEllipse2($xcoord2, $ycoord2, $size) Next $oGDI.GraphicsDrawImageRect(0, 0, $width, $height) ; copy to bitmap $i += 3 If $i > $k + Abs($l) Then $i = $l EndIf Until Not Sleep(30) EndFunc Func _close() Exit EndFunc #region ; GDI Object Func _oGDI() Local $this = _AutoItObject_Class() $this.AddMethod("Init", "_oGDI_Init") $this.AddMethod("GraphicsClear", "_oGDI_GraphicsClear") $this.AddMethod("Brush1SetSolidColor", "_oGDI_Brush1SetSolidColor") $this.AddMethod("Brush2SetSolidColor", "_oGDI_Brush2SetSolidColor") $this.AddMethod("GraphicsFillEllipse1", "_oGDI_GraphicsFillEllipse1") $this.AddMethod("GraphicsFillEllipse2", "_oGDI_GraphicsFillEllipse2") $this.AddMethod("GraphicsDrawImageRect", "_oGDI_GraphicsDrawImageRect") $this.AddProperty("Graphic", $elscope_private, "") $this.AddProperty("ParticleBitmap", $elscope_private, "") $this.AddProperty("ParticleBuffer", $elscope_private, "") $this.AddProperty("Brush1", $elscope_private, "") $this.AddProperty("Brush2", $elscope_private, "") $this.AddDestructor("dtor", "_oGDI_dtor") Return $this.Object EndFunc Func _oGDI_Init($this, $gui, $width, $height) _GDIPlus_Startup() $this.Graphic = _GDIPlus_GraphicsCreateFromHWND($gui) ; create graphic $this.ParticleBitmap = _GDIPlus_BitmapCreateFromGraphics($width, $height, $this.Graphic) ; create bitmap $this.ParticleBuffer = _GDIPlus_ImageGetGraphicsContext($this.ParticleBitmap) ; create buffer _GDIPlus_GraphicsSetSmoothingMode($this.ParticleBuffer, 4) ; Antialiasing _GDIPlus_GraphicsClear($this.ParticleBuffer) ; clear buffer $this.Brush1 = _GDIPlus_BrushCreateSolid(0) $this.Brush2 = _GDIPlus_BrushCreateSolid(0) EndFunc Func _oGDI_GraphicsDrawImageRect($this, $x, $y, $w, $h) _GDIPlus_GraphicsDrawImageRect($this.Graphic, $this.ParticleBitmap, $x, $y, $w, $h) EndFunc Func _oGDI_GraphicsFillEllipse1($this, $x, $y, $s) _GDIPlus_GraphicsFillEllipse($this.ParticleBuffer, $x, $y, $s * 0.166666666, $s * 0.166666666, $this.Brush1) EndFunc Func _oGDI_GraphicsFillEllipse2($this, $x, $y, $s) _GDIPlus_GraphicsFillEllipse($this.ParticleBuffer, $x, $y, $s * 0.125, $s * 0.125, $this.Brush2) EndFunc Func _oGDI_Brush1SetSolidColor($this, $r, $g, $b) _GDIPlus_BrushSetSolidColor($this.Brush1, "0xCF" & Hex($r, 2) & Hex($g, 2) & Hex($b, 2)) EndFunc Func _oGDI_Brush2SetSolidColor($this, $r, $g, $b) _GDIPlus_BrushSetSolidColor($this.Brush2, "0xCF" & Hex($b, 2) & Hex($r, 2) & Hex($g, 2)) EndFunc Func _oGDI_GraphicsClear($this) _GDIPlus_GraphicsClear($this.ParticleBuffer, 0xFFFFFFFF) EndFunc Func _oGDI_dtor($this) ; Clean up resources _GDIPlus_BrushDispose($this.Brush1) _GDIPlus_BrushDispose($this.Brush2) _GDIPlus_GraphicsDispose ($this.Graphic) _GDIPlus_BitmapDispose($this.ParticleBitmap) _GDIPlus_GraphicsDispose($this.ParticleBuffer) _GDIPlus_Shutdown() EndFunc #EndRegion edit: overlooked something, fixed now Edited September 14, 2014 by jaberwacky UEZ 1 Helpful Posts and Websites: AutoIt3 Variables and Function Parameters MHz | AutoIt Wiki | Using the GUIToolTip UDF BrewManNH | Can't find what you're looking for on the Forum? Link to comment Share on other sites More sharing options...
UEZ Posted September 14, 2014 Share Posted September 14, 2014 I will test your script from post #1 at my office where I work with 3 screens. Thank you very much for your oo GDI+ example and explanations. I will check out what you did and revert if I have questions. Br, UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
jaberwacky Posted September 14, 2014 Author Share Posted September 14, 2014 It won't work on three monitors so far. I will get back to it when I wake up. I updated the autoitobject example to be more clear and straight forward, I hope. Helpful Posts and Websites: AutoIt3 Variables and Function Parameters MHz | AutoIt Wiki | Using the GUIToolTip UDF BrewManNH | Can't find what you're looking for on the Forum? Link to comment Share on other sites More sharing options...
UEZ Posted September 14, 2014 Share Posted September 14, 2014 (edited) The GDI+ examples is much slower than the original code but for me it is important to learn oo programming using AutoIt (first). Thx again. Edit: the example doesn't work with 3.3.13.19 -> $this.AddDestructor("dtor", "_oGDI_dtor") <- The requested action with this object has failed. Br, UEZ Edited September 14, 2014 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
jaberwacky Posted September 16, 2014 Author Share Posted September 16, 2014 (edited) Latest version. Bumped up to beta. Still only works for two monitors currently. No longer requires AutoItObject. Edited September 16, 2014 by jaberwacky Helpful Posts and Websites: AutoIt3 Variables and Function Parameters MHz | AutoIt Wiki | Using the GUIToolTip UDF BrewManNH | Can't find what you're looking for on the Forum? Link to comment Share on other sites More sharing options...
UEZ Posted September 16, 2014 Share Posted September 16, 2014 Can you explain please why you used Volatile functions? It seems not to clear for me and others what the purpose of Volatile is and when you should use it! I disabled one of my 3 monitors to test your script but I it is not working - no snapping. I'm using Win8.1. Why did you change your style and switched to non oo? Br, UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
jaberwacky Posted September 16, 2014 Author Share Posted September 16, 2014 (edited) Volatile wouldn't be of any use in this script. I put them there at the start of my scripting but now I can remove them. But um, I understand that volatile is for functions that are callback functions so that they will be called and run in a separate "thread" so to speak and not interfere with a gui message pump. I may be wrong on this. Edit: I may not benefit by removing them. Seeing as to how there are two functions I think I can and should keep them volatile. Shouldn't need to disable your 3rd monitor. But that is distressing to hear that it doesn't work on Win 8.1. I went from OO because you're right, the GDI is faster outside of the object. I only just used it at the beginning because I wanted to drop in a rectangle object and call it and just have a rectangle on the screen. Now that I'm getting something more along the lines of what I want I went ahead and took the object syntax out so that it will run faster. Edited September 16, 2014 by jaberwacky Helpful Posts and Websites: AutoIt3 Variables and Function Parameters MHz | AutoIt Wiki | Using the GUIToolTip UDF BrewManNH | Can't find what you're looking for on the Forum? Link to comment Share on other sites More sharing options...
UEZ Posted September 16, 2014 Share Posted September 16, 2014 Thx for the explanation. Br, UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now