Mouse move, click, and click/drag in two differently sized windows

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Grendahl
Posts: 170
Joined: 30 Sep 2013, 08:21

Mouse move, click, and click/drag in two differently sized windows

09 Mar 2018, 13:16

Thanks to Lexikos and his post at https://autohotkey.com/board/topic/4063 ... ntry254408 I'm at least able to get clicking and dragging working between windows. The hitch is that I need to do the same but on differently scaled windows.

EDIT: I got the scaling working. Still need help on the movement mirror with no mouse button held down.

I'd like a hotkey that just mirrors mouse updates between the two screens while it's held down, but without requiring a click. Below you can see my attempt at an Alt+X hotkey to do this, but it doesn't appear to be working.

Any takers?

Code: Select all

#NoEnv
#SingleInstance Force
SetWorkingDir %A_ScriptDir%
DetectHiddenWindows, On
SetTitleMatchMode, 2
SetBatchLines, -1

;Run two copies of Paint
;Run this script
;Hold "~" and use the left mouse button
;I'd like a hotkey that just mirrors mouse updates between the two screens while it's held down.

Hotkey, ^ESC, Close
OnExit, Close
windowstyle := 2
WinTitle = Untitled

WinGet, windowid, List, %WinTitle%
IfWinExist, ahk_id %windowid1% and winexist ahk_id %windowid2%
{	
	Gosub, RestoreWindows
	Gosub, AlwaysOnTopOff
	;WinSet, Style, -0xC00000, ahk_id %windowid1%
	;WinSet, Style, -0xC00000, ahk_id %windowid2%
	WinMaximize, ahk_id %windowid1%
	w1a := A_ScreenWidth * .75
	h1a := A_ScreenHeight * .75
	w2a := A_ScreenWidth * .25
	h2a := A_ScreenHeight * .25
	WinMove, ahk_id %windowid1%, ,0,0,%w1a%,%h1a%	
	WinGetPos, x1, y1, w1, h1, ahk_id %windowid1%
	Gosub, RestoreWindows
	WinMove, ahk_id %windowid2%, ,%w1%,%h1%,%w2a%,%h2a%
	windowstyle := 1
	WinMaximize, ahk_id %windowid1%
	WinSet, alwaysontop, on, ahk_id %windowid2%
	TrayTip , , %A_ScriptName% Loaded, 3, 1
	WinActivate, ahk_id %windowid1%
 }  Else  {
	MsgBox, 4112, W2B, Both %WinTitle% windows must be running before launching this script.
	ExitApp
 }
MsgBox, 4132, W2B, `nIs the large window the primary window?
IfMsgBox, Yes
	{
	}
IfMsgBox, No
{
	Gosub, AlwaysOnTopOff
	switch1 = %windowid1%
	switch2 = %windowid2%
	windowid1 := switch2
	windowid2 := switch1
	WinMaximize, ahk_id %windowid1%
	WinMove, ahk_id %windowid2%, ,%w1%,%h1%,%w2a%,%h2a%
	WinSet, alwaysontop, on, ahk_id %windowid2%
	TrayTip , , Picture In Picture, 3, 1
	WinActivate, ahk_id %windowid1%
}
Return

!X::
    CoordMode, Mouse, Relative
    MouseGetPos, x, y, win            ; get mouse pos,
    WinGetPos, wx, wy,,, ahk_id %win%
    x -= wx, y -= wy                      ; relative to mouse window
    ifWinNotExist, %WINTITLE% ahk_id %win%
        return
    WinGet, w, List, %WINTITLE%
    Loop { ; loop to simulate drag
        if !GetKeyState("X","P")
			break
        MouseGetPos, x, y   ; get mouse pos,
        WinGetPos, wx, wy,,, ahk_id %win%
        x -= wx, y -= wy    ; relative to mouse window
        Loop, %w%
        Loop, %w%
            if (w%A_Index% != win) {
                x := Floor(x*.25) ; Scale down for secondary window
                y := Floor(y*.25)
                c%A_Index% := ControlMouseMove(x, y, c%A_Index%, "ahk_id " w%A_Index%, "", "L K")
                ; c%A_Index% is used to simulate mouse capture.
            }
        Sleep, 10
    }
    ToolTip
Return

~SC029 & ~LButton:: ;SC029 is the "~" key (above TAB)
    CoordMode, Mouse, Relative
    MouseGetPos, x, y, win            ; get mouse pos,
    WinGetPos, wx, wy,,, ahk_id %win%
    x -= wx, y -= wy                      ; relative to mouse window
    ifWinNotExist, %WINTITLE% ahk_id %win%
        return
    WinGet, w, List, %WINTITLE%
    Loop, %w%
        if (w%A_Index% != win) {
            x := Floor(x*.25) ; Scale down for secondary window
            y := Floor(y*.25)
            ControlClick, X%x% Y%y%, % "ahk_id " w%A_Index%,,,, D
        }    
    Loop { ; loop to simulate drag
        if !GetKeyState("LButton","P")
			break
        MouseGetPos, x, y   ; get mouse pos,
        WinGetPos, wx, wy,,, ahk_id %win%
        x -= wx, y -= wy    ; relative to mouse window
        Loop, %w%
            if (w%A_Index% != win) {
                x := Floor(x*.25) ; Scale down for secondary window
                y := Floor(y*.25)
                c%A_Index% := ControlMouseMove(x, y, c%A_Index%, "ahk_id " w%A_Index%, "", "L K")
                ; c%A_Index% is used to simulate mouse capture.
            }
        Sleep, 10
    }
    Loop, %w%
        if (w%A_Index% != win)
        {
            if c%A_Index%
            {   ; window coords -> control coords
                ControlGetPos, cx, cy,,,, % "ahk_id " c%A_Index%
                x -= cx, y -= cy
                ; simulate mouse capture
                w%A_Index% := c%A_Index%
                c%A_Index% =
            }
            ControlClick, X%x% Y%y%, % "ahk_id " w%A_Index%,,,, U
        }
return

AlwaysOnTopOff:
	WinSet, alwaysontop, off, ahk_id %windowid1%
	WinSet, alwaysontop, off, ahk_id %windowid2%
Return 

Close:
	WinSet, alwaysontop, off, ahk_id %windowid1%
	WinSet, alwaysontop, off, ahk_id %windowid2%
	WinMove, ahk_id %windowid1%, ,0,0,720,450
	WinMove, ahk_id %windowid2%, ,50,50,720,450
ExitApp

RestoreWindows:
	WinRestore, ahk_id %windowid1%
	WinRestore, ahk_id %windowid2%
Return

; From Lexikos at https://autohotkey.com/board/topic/40638-controlclick-dragging/#entry254408
; Accepts coords relative to the specified window.
;   X and Y MUST be specified, since current actual mouse location is irrelevant.
;   Control:
;       This can be, ClassNN, the name/text of the control, or a control HWND
;       (which must be a child of the target window.)
;       If a control HWND is specified, X and Y will be relative to the target
;       window, not the child control.
;   Options:
;       a string of letters (spaces are optional) indicating which buttons("LMR X1 X2")/keys("S C"=shift,control) should be considered pressed.
;       K: use actual key state for Shift and Ctrl.
;   Return value:
;       The hwnd of the control which was sent the mousemove message.
;       Pass this to the Control parameter to simulate mouse capture.
; Based on AutoHotkey::script2.cpp::ControlClick()
ControlMouseMove(X, Y, Control="", WinTitle="", WinText="", Options="", ExcludeTitle="", ExcludeText="")
{
    static EnumChildFindPointProc=0
    if !EnumChildFindPointProc
        EnumChildFindPointProc := RegisterCallback("EnumChildFindPoint","Fast")
    
    if !(target_window := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText))
        return false
    if Control
    {
        if Control is integer
            Control_is_hwnd := IsWindowChildOf(Control, target_window)
        
        if Control_is_hwnd
        {
            ; If %Control% specifies a control hwnd, send it the mouse move,
            ; but use coords relative to the window specified by WinTitle.
            ; This can be used to more easily simulate mouse capture.
            control_window := Control
            VarSetCapacity(rect, 16)
            DllCall("GetWindowRect","uint",target_window,"uint",&rect)
            VarSetCapacity(child_rect, 16)
            DllCall("GetWindowRect","uint",control_window,"uint",&child_rect)
            X -= NumGet(child_rect,0,"int") - NumGet(rect,0,"int")
            Y -= NumGet(child_rect,4,"int") - NumGet(rect,4,"int")
        }
        else
            ControlGet, control_window, Hwnd,, %Control%, ahk_id %target_window%
    }
    if (!control_window)
    {
        VarSetCapacity(rect, 16)
        DllCall("GetWindowRect","uint",target_window,"uint",&rect)
        VarSetCapacity(pah, 36, 0)
        NumPut(X + NumGet(rect,0,"int"), pah,0,"int")
        NumPut(Y + NumGet(rect,4,"int"), pah,4,"int")
        DllCall("EnumChildWindows","uint",target_window,"uint",EnumChildFindPointProc,"uint",&pah)
        control_window := NumGet(pah,24) ? NumGet(pah,24) : target_window
        DllCall("ScreenToClient","uint",control_window,"uint",&pah)
        X:=NumGet(pah,0,"int"), Y:=NumGet(pah,4,"int")
    }
    wParam :=  (InStr(Options,"L") ? 0x1 : 0) || (InStr(Options,"M") ? 0x10 : 0) || (InStr(Options,"R") ? 0x2 : 0)
            || (InStr(Options,"X1") ? 0x20 : 0) || (InStr(Options,"X2") ? 0x40 : 0)
            || (InStr(Options,"S") ? 0x4 : 0) || (InStr(Options,"C") ? 0x8 : 0)
            || (InStr(Options,"K") ? (GetKeyState("Shift") ? 0x4:0)|(GetKeyState("Control") ? 0x8:0) : 0)
    PostMessage, 0x200, wParam, (x & 0xFFFF) | ((y & 0xFFFF)<<16),, ahk_id %control_window%
    return control_window
}

IsWindowChildOf(aChild, aParent)
{
    static EnumChildFindHwndProc=0
    if !EnumChildFindHwndProc
        EnumChildFindHwndProc := RegisterCallback("EnumChildFindHwnd","Fast")
    VarSetCapacity(lParam,8,0), NumPut(aChild,lParam,0)
    DllCall("EnumChildWindows","uint",aParent,"uint",EnumChildFindHwndProc,"uint",&lParam)
    return NumGet(lParam,4)
}
EnumChildFindHwnd(aWnd, lParam)
{
    if (aWnd = NumGet(lParam+0))
    {
        NumPut(1, lParam+4)
        return false
    }
    return true
}

; Ported from AutoHotkey::script2.cpp::EnumChildFindPoint()
EnumChildFindPoint(aWnd, lParam)
{
    if !DllCall("IsWindowVisible","uint",aWnd)
        return true
    VarSetCapacity(rect, 16)
    if !DllCall("GetWindowRect","uint",aWnd,"uint",&rect)
        return true
    pt_x:=NumGet(lParam+0,0,"int"), pt_y:=NumGet(lParam+0,4,"int")
    rect_left:=NumGet(rect,0,"int"), rect_right:=NumGet(rect,8,"int")
    rect_top:=NumGet(rect,4,"int"), rect_bottom:=NumGet(rect,12,"int")
    if (pt_x >= rect_left && pt_x <= rect_right && pt_y >= rect_top && pt_y <= rect_bottom)
    {
        center_x := rect_left + (rect_right - rect_left) / 2
        center_y := rect_top + (rect_bottom - rect_top) / 2
        distance := Sqrt((pt_x-center_x)**2 + (pt_y-center_y)**2)
        update_it := !NumGet(lParam+24)
        if (!update_it)
        {
            rect_found_left:=NumGet(lParam+8,0,"int"), rect_found_right:=NumGet(lParam+8,8,"int")
            rect_found_top:=NumGet(lParam+8,4,"int"), rect_found_bottom:=NumGet(lParam+8,12,"int")
            if (rect_left >= rect_found_left && rect_right <= rect_found_right
                && rect_top >= rect_found_top && rect_bottom <= rect_found_bottom)
                update_it := true
            else if (distance < NumGet(lParam+28,0,"double")
                && (rect_found_left < rect_left || rect_found_right > rect_right
                 || rect_found_top < rect_top || rect_found_bottom > rect_bottom))
                 update_it := true
        }
        if (update_it)
        {
            NumPut(aWnd, lParam+24)
            DllCall("RtlMoveMemory","uint",lParam+8,"uint",&rect,"uint",16)
            NumPut(distance, lParam+28, 0, "double")
        }
    }
    return true
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: mikeyww, peter_ahk and 355 guests