![Image](https://s21.ax1x.com/2024/05/24/pkQLLMd.png)
![Image](https://s21.ax1x.com/2024/05/24/pkQLOsA.png)
Code: Select all
#Requires AutoHotkey v2
wnd := Gui()
wnd.OnEvent('Close', (*) => ExitApp())
wnd.SetFont('s12', 'Calibri')
lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)'])
Loop Files, A_MyDocuments . '\*.*' {
lv.Add(, A_LoopFileName, A_LoopFileSizeKB)
}
lv.ModifyCol(1, 'AutoHdr')
lv.ModifyCol(2, 'AutoHdr Integer')
wnd.Show()
OnMessage(0x201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wp, lp, msg, hwnd) {
static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E
res := true
if hwnd == lv.hwnd {
NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24))
res := SendMessage(LVM_HITTEST,, buf, lv) != -1
}
if res {
WinGetPos(&x, &y,,, lv)
lv.itemRects := []
Loop lv.GetCount() {
i := A_Index - 1
if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) {
lv.itemRects.Push('')
continue
}
SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv
NumPut('Int', x,
'Int', NumGet(RECT, 4, 'Int') + y,
'Int', NumGet(RECT, 8, 'Int') + x,
'Int', NumGet(RECT, 12, 'Int') + y, RECT)
lv.itemRects.Push(RECT)
}
lv.area := SelectArea(0x5A00AAEE, SelectItems)
}
}
SelectItems(p1, p2) {
static testRECT := Buffer(16)
NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16))
for i, itemRECT in lv.itemRects {
res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT)
lv.Modify(i, (res ? '' : '-') . 'Select')
}
}
~*LButton Up:: lv.area := ''
class SelectArea
{
WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200
__New(colorARGB, callback?) {
IsSet(callback) && this.callback := callback
this.CreateGui(colorARGB)
CoordMode 'Mouse'
MouseGetPos &x, &y
this.startX := x
this.startY := y
this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc)
ObjRelease(ObjPtr(this))
LowLevelMouseProc(nCode, wParam, lParam) {
if wParam == this.WM_MOUSEMOVE {
mouseX := NumGet(lParam + 0, 'Int')
mouseY := NumGet(lParam + 4, 'Int')
this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY))
}
return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr')
}
}
__Delete() {
ObjAddRef(ObjPtr(this))
this.hook := ''
this.gui.Destroy()
}
CreateGui(colorARGB) {
wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale')
wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF)
WinSetTransparent(colorARGB >> 24, wnd)
this.gui := wnd
}
ShowBetweenTwoPoints(p1, p2) {
p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x'])
p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y'])
this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1)
Loop 2 {
this.x%A_Index% := x%A_Index%
this.y%A_Index% := y%A_Index%
}
if this.HasOwnProp('callback') {
this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2))
}
}
}
class WindowsHook {
__New(type, callback, isGlobal := true) {
this.pCallback := CallbackCreate(callback, 'Fast', 3)
this.hHook := DllCall('SetWindowsHookEx', 'Int', type, 'Ptr', this.pCallback
, 'Ptr', !isGlobal ? 0 : DllCall('GetModuleHandle', 'UInt', 0, 'Ptr')
, 'UInt', isGlobal ? 0 : DllCall('GetCurrentThreadId'), 'Ptr')
}
__Delete() {
DllCall('UnhookWindowsHookEx', 'Ptr', this.hHook)
CallbackFree(this.pCallback)
}
}
Awesome... Thank you!
Thanks! but when Rubberband selecting, it will deselect the previous selected items. Is it possible not to do that when "Ctrl" is pressed? (Like File Explorer, when "Ctrl" is pressed, Rubberband selecting won't deselect the already selected items.teadrinker wrote: ↑24 May 2024, 14:20Try:Code: Select all
#Requires AutoHotkey v2 wnd := Gui() wnd.OnEvent('Close', (*) => ExitApp()) wnd.SetFont('s12', 'Calibri') lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)']) Loop Files, A_MyDocuments . '\*.*' { lv.Add(, A_LoopFileName, A_LoopFileSizeKB) } lv.ModifyCol(1, 'AutoHdr') lv.ModifyCol(2, 'AutoHdr Integer') wnd.Show() OnMessage(0x201, WM_LBUTTONDOWN) WM_LBUTTONDOWN(wp, lp, msg, hwnd) { static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E res := true if hwnd == lv.hwnd { NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24)) res := SendMessage(LVM_HITTEST,, buf, lv) != -1 } if res { WinGetPos(&x, &y,,, lv) lv.itemRects := [] Loop lv.GetCount() { i := A_Index - 1 if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) { lv.itemRects.Push('') continue } SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv NumPut('Int', x, 'Int', NumGet(RECT, 4, 'Int') + y, 'Int', NumGet(RECT, 8, 'Int') + x, 'Int', NumGet(RECT, 12, 'Int') + y, RECT) lv.itemRects.Push(RECT) } lv.area := SelectArea(0x5A00AAEE, SelectItems) } } SelectItems(p1, p2) { static testRECT := Buffer(16) NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16)) for i, itemRECT in lv.itemRects { res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT) lv.Modify(i, (res ? '' : '-') . 'Select') } } ~*LButton Up:: lv.area := '' class SelectArea { WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200 __New(colorARGB, callback?) { IsSet(callback) && this.callback := callback this.CreateGui(colorARGB) CoordMode 'Mouse' MouseGetPos &x, &y this.startX := x this.startY := y this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc) ObjRelease(ObjPtr(this)) LowLevelMouseProc(nCode, wParam, lParam) { if wParam == this.WM_MOUSEMOVE { mouseX := NumGet(lParam + 0, 'Int') mouseY := NumGet(lParam + 4, 'Int') this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY)) } return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr') } } __Delete() { ObjAddRef(ObjPtr(this)) this.hook := '' this.gui.Destroy() } CreateGui(colorARGB) { wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale') wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF) WinSetTransparent(colorARGB >> 24, wnd) this.gui := wnd } ShowBetweenTwoPoints(p1, p2) { p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x']) p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y']) this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1) Loop 2 { this.x%A_Index% := x%A_Index% this.y%A_Index% := y%A_Index% } if this.HasOwnProp('callback') { this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2)) } } } class WindowsHook { __New(type, callback, isGlobal := true) { this.pCallback := CallbackCreate(callback, 'Fast', 3) this.hHook := DllCall('SetWindowsHookEx', 'Int', type, 'Ptr', this.pCallback , 'Ptr', !isGlobal ? 0 : DllCall('GetModuleHandle', 'UInt', 0, 'Ptr') , 'UInt', isGlobal ? 0 : DllCall('GetCurrentThreadId'), 'Ptr') } __Delete() { DllCall('UnhookWindowsHookEx', 'Ptr', this.hHook) CallbackFree(this.pCallback) } }
Code: Select all
#Requires AutoHotkey v2
wnd := Gui()
wnd.OnEvent('Close', (*) => ExitApp())
wnd.SetFont('s12', 'Calibri')
lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)'])
Loop Files, A_MyDocuments . '\*.*' {
lv.Add(, A_LoopFileName, A_LoopFileSizeKB)
}
lv.ModifyCol(1, 'AutoHdr')
lv.ModifyCol(2, 'AutoHdr Integer')
wnd.Show()
OnMessage(0x201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wp, lp, msg, hwnd) {
static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E
res := true
lv.prevSelected := Map()
if GetKeyState('Ctrl', 'P') {
i := 0
while i := lv.GetNext(i) {
lv.prevSelected[i] := ''
}
}
if hwnd == lv.hwnd {
NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24))
res := SendMessage(LVM_HITTEST,, buf, lv) != -1
}
if res {
WinGetPos(&x, &y,,, lv)
lv.itemRects := []
Loop lv.GetCount() {
i := A_Index - 1
if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) {
lv.itemRects.Push('')
continue
}
SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv
NumPut('Int', x,
'Int', NumGet(RECT, 4, 'Int') + y,
'Int', NumGet(RECT, 8, 'Int') + x,
'Int', NumGet(RECT, 12, 'Int') + y, RECT)
lv.itemRects.Push(RECT)
}
lv.area := SelectArea(0x5A00AAEE, SelectItems)
}
}
SelectItems(p1, p2) {
static testRECT := Buffer(16)
NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16))
for i, itemRECT in lv.itemRects {
res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT)
lv.Modify(i, (res ^ lv.prevSelected.Has(i) ? '' : '-') . 'Select')
}
}
~*LButton Up:: lv.area := ''
class SelectArea
{
WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200
__New(colorARGB, callback?) {
IsSet(callback) && this.callback := callback
this.CreateGui(colorARGB)
CoordMode 'Mouse'
MouseGetPos &x, &y
this.startX := x
this.startY := y
this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc)
ObjRelease(ObjPtr(this))
LowLevelMouseProc(nCode, wParam, lParam) {
if wParam == this.WM_MOUSEMOVE {
mouseX := NumGet(lParam + 0, 'Int')
mouseY := NumGet(lParam + 4, 'Int')
this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY))
}
return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr')
}
}
__Delete() {
ObjAddRef(ObjPtr(this))
this.hook := ''
this.gui.Destroy()
}
CreateGui(colorARGB) {
wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale')
wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF)
WinSetTransparent(colorARGB >> 24, wnd)
this.gui := wnd
}
ShowBetweenTwoPoints(p1, p2) {
p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x'])
p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y'])
this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1)
Loop 2 {
this.x%A_Index% := x%A_Index%
this.y%A_Index% := y%A_Index%
}
if this.HasOwnProp('callback') {
this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2))
}
}
}
class WindowsHook {
__New(type, callback, isGlobal := true) {
this.pCallback := CallbackCreate(callback, 'Fast', 3)
this.hHook := DllCall('SetWindowsHookEx', 'Int', type, 'Ptr', this.pCallback
, 'Ptr', !isGlobal ? 0 : DllCall('GetModuleHandle', 'UInt', 0, 'Ptr')
, 'UInt', isGlobal ? 0 : DllCall('GetCurrentThreadId'), 'Ptr')
}
__Delete() {
DllCall('UnhookWindowsHookEx', 'Ptr', this.hHook)
CallbackFree(this.pCallback)
}
}
Fyi... the code seems to have a bug. As soon as I tried to click-drag, it locked my computer up so I am unable to provide any more details. But I did see, "expected a number but got an empty string" prior to forced POPO. The errors came so rapidly that it is probably related to mouse coords. I don't dare run it again. lol.
Code: Select all
#Requires AutoHotkey v2
wnd := Gui()
wnd.OnEvent('Close', (*) => ExitApp())
wnd.SetFont('s12', 'Calibri')
lv := wnd.Add('ListView', 'r10 w400', ['Name','Size (KB)'])
Loop Files, A_MyDocuments . '\*.*' {
lv.Add(, A_LoopFileName, A_LoopFileSizeKB)
}
lv.ModifyCol(1, 'AutoHdr')
lv.ModifyCol(2, 'AutoHdr Integer')
wnd.Show()
OnMessage(0x201, WM_LBUTTONDOWN)
WM_LBUTTONDOWN(wp, lp, msg, hwnd) {
static LVM_HITTEST := 0x1012, LVM_ISITEMVISIBLE := 0x10B6, LVM_GETITEMRECT := 0x100E
res := true
lv.prevSelected := Map()
if GetKeyState('Ctrl', 'P') {
i := 0
while i := lv.GetNext(i) {
lv.prevSelected[i] := ''
}
}
if hwnd == lv.hwnd {
NumPut('Int', lp & 0xFFFF, 'Int', lp >> 16, buf := Buffer(24))
res := SendMessage(LVM_HITTEST,, buf, lv) != -1
}
if res {
WinGetPos(&x, &y,,, lv)
lv.itemRects := []
Loop lv.GetCount() {
i := A_Index - 1
if !SendMessage(LVM_ISITEMVISIBLE, i,, lv) {
lv.itemRects.Push('')
continue
}
SendMessage LVM_GETITEMRECT, i, RECT := Buffer(16, 0), lv
NumPut('Int', x,
'Int', NumGet(RECT, 4, 'Int') + y,
'Int', NumGet(RECT, 8, 'Int') + x,
'Int', NumGet(RECT, 12, 'Int') + y, RECT)
lv.itemRects.Push(RECT)
}
lv.area := SelectArea(0x5A00AAEE, SelectItems)
}
}
SelectItems(p1, p2) {
static testRECT := Buffer(16)
NumPut('Int', p1['x'], 'Int', p1['y'], 'Int', p2['x'], 'Int', p2['y'], RECT := Buffer(16))
for i, itemRECT in lv.itemRects {
res := itemRECT && DllCall('IntersectRect', 'Ptr', testRECT, 'Ptr', RECT, 'Ptr', itemRECT)
lv.Modify(i, (!!res ^ lv.prevSelected.Has(i) ? '' : '-') . 'Select')
}
}
~*LButton Up:: lv.area := ''
class SelectArea
{
WH_MOUSE_LL := 14, WM_MOUSEMOVE := 0x200
__New(colorARGB, callback?) {
IsSet(callback) && this.callback := callback
this.CreateGui(colorARGB)
CoordMode 'Mouse'
MouseGetPos &x, &y
this.startX := x
this.startY := y
this.hook := WindowsHook(this.WH_MOUSE_LL, LowLevelMouseProc)
ObjRelease(ObjPtr(this))
LowLevelMouseProc(nCode, wParam, lParam) {
if wParam == this.WM_MOUSEMOVE {
mouseX := NumGet(lParam + 0, 'Int')
mouseY := NumGet(lParam + 4, 'Int')
this.ShowBetweenTwoPoints(Map('x', this.startX, 'y', this.startY), Map('x', mouseX, 'y', mouseY))
}
return DllCall('CallNextHookEx', 'Ptr', 0, 'Int', nCode, 'UInt', wParam, 'Ptr', lParam, 'Ptr')
}
}
__Delete() {
ObjAddRef(ObjPtr(this))
this.hook := ''
this.gui.Destroy()
}
CreateGui(colorARGB) {
wnd := Gui('-Caption ToolWindow AlwaysOnTop Border -DPIScale')
wnd.BackColor := Format('{:X}', colorARGB & 0xFFFFFF)
WinSetTransparent(colorARGB >> 24, wnd)
this.gui := wnd
}
ShowBetweenTwoPoints(p1, p2) {
p1['x'] < p2['x'] ? (x1 := p1['x'], x2 := p2['x']) : (x1 := p2['x'], x2 := p1['x'])
p1['y'] < p2['y'] ? (y1 := p1['y'], y2 := p2['y']) : (y1 := p2['y'], y2 := p1['y'])
this.gui.Show('NA x' . x1 . ' y' . y1 . ' w' . x2 - x1 . ' h' . y2 - y1)
Loop 2 {
this.x%A_Index% := x%A_Index%
this.y%A_Index% := y%A_Index%
}
if this.HasOwnProp('callback') {
this.callback.Call(Map('x', this.x1, 'y', this.y1), Map('x', this.x2, 'y', this.y2))
}
}
}
class WindowsHook {
__New(type, callback, isGlobal := true) {
this.pCallback := CallbackCreate(callback, 'Fast', 3)
this.hHook := DllCall('SetWindowsHookEx', 'Int', type, 'Ptr', this.pCallback
, 'Ptr', !isGlobal ? 0 : DllCall('GetModuleHandle', 'UInt', 0, 'Ptr')
, 'UInt', isGlobal ? 0 : DllCall('GetCurrentThreadId'), 'Ptr')
}
__Delete() {
DllCall('UnhookWindowsHookEx', 'Ptr', this.hHook)
CallbackFree(this.pCallback)
}
}
Yep... works... thanks! Need to study your code to see how this was done. I may look into how to get it to scroll when selecting as well. But have other priorities at the moment.