feat: Janela sobre o relogio
This commit is contained in:
parent
1de5a60843
commit
879ae24ca6
@ -38,5 +38,6 @@ type InputHandler interface {
|
|||||||
IsMinimized(hwnd uintptr) bool
|
IsMinimized(hwnd uintptr) bool
|
||||||
RestoreWindow(hwnd uintptr)
|
RestoreWindow(hwnd uintptr)
|
||||||
MinimizeWindow(hwnd uintptr)
|
MinimizeWindow(hwnd uintptr)
|
||||||
|
GetRestoredRect() (x, y, w, h int32)
|
||||||
RegisterRawScrollSink(callback func(delta int16)) error
|
RegisterRawScrollSink(callback func(delta int16)) error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ var (
|
|||||||
procGetForegroundWindow = user32.NewProc("GetForegroundWindow")
|
procGetForegroundWindow = user32.NewProc("GetForegroundWindow")
|
||||||
procIsIconic = user32.NewProc("IsIconic")
|
procIsIconic = user32.NewProc("IsIconic")
|
||||||
procShowWindowAsync = user32.NewProc("ShowWindowAsync")
|
procShowWindowAsync = user32.NewProc("ShowWindowAsync")
|
||||||
|
procGetWindowPlacement = user32.NewProc("GetWindowPlacement")
|
||||||
procGetWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
|
procGetWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
|
||||||
procAttachThreadInput = user32.NewProc("AttachThreadInput")
|
procAttachThreadInput = user32.NewProc("AttachThreadInput")
|
||||||
procBringWindowToTop = user32.NewProc("BringWindowToTop")
|
procBringWindowToTop = user32.NewProc("BringWindowToTop")
|
||||||
@ -48,6 +49,16 @@ type RECT struct {
|
|||||||
Left, Top, Right, Bottom int32
|
Left, Top, Right, Bottom int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WINDOWPLACEMENT struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
ShowCmd uint32
|
||||||
|
PtMinPosition Point
|
||||||
|
PtMaxPosition Point
|
||||||
|
RcNormalPosition RECT
|
||||||
|
RcDevice RECT
|
||||||
|
}
|
||||||
|
|
||||||
type MONITORINFO struct {
|
type MONITORINFO struct {
|
||||||
CbSize uint32
|
CbSize uint32
|
||||||
RcMonitor RECT
|
RcMonitor RECT
|
||||||
@ -357,6 +368,19 @@ func (h *windowsInputHandler) GetAppHwnd() uintptr {
|
|||||||
return h.hwnd
|
return h.hwnd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRestoredRect retorna posição e tamanho do KVMote no estado restaurado,
|
||||||
|
// mesmo que a janela esteja minimizada (GetWindowRect falha nesse caso).
|
||||||
|
func (h *windowsInputHandler) GetRestoredRect() (x, y, w, ht int32) {
|
||||||
|
if h.hwnd == 0 {
|
||||||
|
return 0, 0, 800, 600
|
||||||
|
}
|
||||||
|
var wp WINDOWPLACEMENT
|
||||||
|
wp.Length = uint32(unsafe.Sizeof(wp))
|
||||||
|
procGetWindowPlacement.Call(h.hwnd, uintptr(unsafe.Pointer(&wp)))
|
||||||
|
r := wp.RcNormalPosition
|
||||||
|
return r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top
|
||||||
|
}
|
||||||
|
|
||||||
func (h *windowsInputHandler) IsMinimized(hwnd uintptr) bool {
|
func (h *windowsInputHandler) IsMinimized(hwnd uintptr) bool {
|
||||||
ret, _, _ := procIsIconic.Call(hwnd)
|
ret, _, _ := procIsIconic.Call(hwnd)
|
||||||
return ret != 0
|
return ret != 0
|
||||||
|
|||||||
@ -93,7 +93,7 @@ func (ov *OverlayWindow) run() {
|
|||||||
dtVCenter = 0x00000004
|
dtVCenter = 0x00000004
|
||||||
dtSingleLine = 0x00000020
|
dtSingleLine = 0x00000020
|
||||||
transparent = 1
|
transparent = 1
|
||||||
neonGreen = 0x0014FF39 // #39FF14 em COLORREF (0x00BBGGRR)
|
neonMagenta = 0x00FF00FF // #FF00FF em COLORREF (0x00BBGGRR)
|
||||||
defaultFont = 17 // DEFAULT_GUI_FONT
|
defaultFont = 17 // DEFAULT_GUI_FONT
|
||||||
)
|
)
|
||||||
switch msg {
|
switch msg {
|
||||||
@ -112,7 +112,7 @@ func (ov *OverlayWindow) run() {
|
|||||||
font, _, _ := procGetStockObject.Call(defaultFont)
|
font, _, _ := procGetStockObject.Call(defaultFont)
|
||||||
old, _, _ := procGdiSelectObject.Call(hdc, font)
|
old, _, _ := procGdiSelectObject.Call(hdc, font)
|
||||||
procSetBkMode.Call(hdc, transparent)
|
procSetBkMode.Call(hdc, transparent)
|
||||||
procSetTextColor.Call(hdc, neonGreen)
|
procSetTextColor.Call(hdc, neonMagenta)
|
||||||
text, _ := windows.UTF16PtrFromString("KVMote")
|
text, _ := windows.UTF16PtrFromString("KVMote")
|
||||||
procDrawTextW.Call(hdc, uintptr(unsafe.Pointer(text)), ^uintptr(0),
|
procDrawTextW.Call(hdc, uintptr(unsafe.Pointer(text)), ^uintptr(0),
|
||||||
uintptr(unsafe.Pointer(&rc)), dtCenter|dtVCenter|dtSingleLine)
|
uintptr(unsafe.Pointer(&rc)), dtCenter|dtVCenter|dtSingleLine)
|
||||||
|
|||||||
@ -76,6 +76,10 @@ type Engine struct {
|
|||||||
|
|
||||||
prevForegroundHwnd uintptr // janela que estava em foco antes de entrar em client mode
|
prevForegroundHwnd uintptr // janela que estava em foco antes de entrar em client mode
|
||||||
prevWasActive bool // true se salvamos uma janela diferente do KVMote
|
prevWasActive bool // true se salvamos uma janela diferente do KVMote
|
||||||
|
|
||||||
|
kvmoteOrigX, kvmoteOrigY int32 // posição original da janela KVMote
|
||||||
|
kvmoteOrigW, kvmoteOrigH int32 // tamanho original da janela KVMote
|
||||||
|
kvmoteWasMinimized bool // se estava minimizado ao entrar em client mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEngine(t transport.Transport, h input.InputHandler) *Engine {
|
func NewEngine(t transport.Transport, h input.InputHandler) *Engine {
|
||||||
@ -221,9 +225,9 @@ func (e *Engine) onMouse(ev input.MouseEvent) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Park no centro da tela (cursor oculto, só para manter delta consistente)
|
// Re-parka cursor no canto inferior direito (perto do relógio/bateria)
|
||||||
w, h := e.inputHandler.GetScreenResolution()
|
w, h := e.inputHandler.GetScreenResolution()
|
||||||
cx, cy := w/2, h/2
|
cx, cy := w-150, h-160
|
||||||
e.isWarping = true
|
e.isWarping = true
|
||||||
e.inputHandler.SetCursorPos(cx, cy)
|
e.inputHandler.SetCursorPos(cx, cy)
|
||||||
e.lastRawPos = input.Point{X: cx, Y: cy}
|
e.lastRawPos = input.Point{X: cx, Y: cy}
|
||||||
@ -270,15 +274,22 @@ func (e *Engine) enterClientMode(p input.Point) {
|
|||||||
e.wheelAccum = 0
|
e.wheelAccum = 0
|
||||||
e.mouseThrottle = time.Now()
|
e.mouseThrottle = time.Now()
|
||||||
|
|
||||||
// Salva janela em foco e traz KVMote pra frente, se necessário
|
// Salva estado original do KVMote (posição/tamanho/minimizado) e move pra direita
|
||||||
kvHwnd := e.inputHandler.GetAppHwnd()
|
kvHwnd := e.inputHandler.GetAppHwnd()
|
||||||
|
e.kvmoteWasMinimized = e.inputHandler.IsMinimized(kvHwnd)
|
||||||
|
e.kvmoteOrigX, e.kvmoteOrigY, e.kvmoteOrigW, e.kvmoteOrigH = e.inputHandler.GetRestoredRect()
|
||||||
|
if e.kvmoteWasMinimized {
|
||||||
|
e.inputHandler.RestoreWindow(kvHwnd)
|
||||||
|
}
|
||||||
|
sw, sh := e.inputHandler.GetScreenResolution()
|
||||||
|
e.inputHandler.MoveWindow(sw-e.kvmoteOrigW, sh-350, e.kvmoteOrigW, 280, false)
|
||||||
|
LogDebug(fmt.Sprintf("KVMote movido para direita: x=%d y=%d w=%d h=300", sw-e.kvmoteOrigW, sh-350, e.kvmoteOrigW))
|
||||||
|
|
||||||
|
// Salva janela em foco e traz KVMote pra frente, se necessário
|
||||||
fgHwnd := e.inputHandler.GetForegroundWindow()
|
fgHwnd := e.inputHandler.GetForegroundWindow()
|
||||||
if fgHwnd != kvHwnd {
|
if fgHwnd != kvHwnd {
|
||||||
e.prevForegroundHwnd = fgHwnd
|
e.prevForegroundHwnd = fgHwnd
|
||||||
e.prevWasActive = true
|
e.prevWasActive = true
|
||||||
if e.inputHandler.IsMinimized(kvHwnd) {
|
|
||||||
e.inputHandler.RestoreWindow(kvHwnd)
|
|
||||||
}
|
|
||||||
e.inputHandler.RequestFocus()
|
e.inputHandler.RequestFocus()
|
||||||
LogDebug(fmt.Sprintf("Janela anterior salva: 0x%X, KVMote trazido ao foco", fgHwnd))
|
LogDebug(fmt.Sprintf("Janela anterior salva: 0x%X, KVMote trazido ao foco", fgHwnd))
|
||||||
} else {
|
} else {
|
||||||
@ -291,9 +302,9 @@ func (e *Engine) enterClientMode(p input.Point) {
|
|||||||
e.winManager.SetMiniMode()
|
e.winManager.SetMiniMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parka cursor no centro — scroll via Raw Input, cursor pode ficar visível
|
// Parka cursor no canto inferior direito (perto do relógio/bateria)
|
||||||
w, h := e.inputHandler.GetScreenResolution()
|
w, h := e.inputHandler.GetScreenResolution()
|
||||||
cx, cy := w/2, h/2
|
cx, cy := w-150, h-160
|
||||||
e.isWarping = true
|
e.isWarping = true
|
||||||
e.inputHandler.SetCursorPos(cx, cy)
|
e.inputHandler.SetCursorPos(cx, cy)
|
||||||
e.lastRawPos = input.Point{X: cx, Y: cy}
|
e.lastRawPos = input.Point{X: cx, Y: cy}
|
||||||
@ -313,6 +324,16 @@ func (e *Engine) exitClientMode() {
|
|||||||
|
|
||||||
e.inputHandler.ShowCursor(true)
|
e.inputHandler.ShowCursor(true)
|
||||||
|
|
||||||
|
// Restaura posição/tamanho original do KVMote
|
||||||
|
if e.kvmoteOrigW > 0 {
|
||||||
|
e.inputHandler.MoveWindow(e.kvmoteOrigX, e.kvmoteOrigY, e.kvmoteOrigW, e.kvmoteOrigH, false)
|
||||||
|
LogDebug(fmt.Sprintf("KVMote restaurado: x=%d y=%d w=%d h=%d", e.kvmoteOrigX, e.kvmoteOrigY, e.kvmoteOrigW, e.kvmoteOrigH))
|
||||||
|
}
|
||||||
|
if e.kvmoteWasMinimized {
|
||||||
|
e.inputHandler.MinimizeWindow(e.inputHandler.GetAppHwnd())
|
||||||
|
e.kvmoteWasMinimized = false
|
||||||
|
}
|
||||||
|
|
||||||
// Restaura janela anterior ao foco
|
// Restaura janela anterior ao foco
|
||||||
if e.prevWasActive && e.prevForegroundHwnd != 0 {
|
if e.prevWasActive && e.prevForegroundHwnd != 0 {
|
||||||
e.inputHandler.SetForegroundTo(e.prevForegroundHwnd)
|
e.inputHandler.SetForegroundTo(e.prevForegroundHwnd)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user