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
}