Popup window when the cursor is at the edge of the screen (?)

Just starting out? Need help? Post your questions and find answers here.
AZJIO
Addict
Addict
Posts: 2143
Joined: Sun May 14, 2017 1:48 am

Popup window when the cursor is at the edge of the screen (?)

Post by AZJIO »

I have a working code on AutoIt3. I converted it to PureBasic and can't get the code to work.
The meaning is the following:
Creates a transparent window at the edge of the screen, 1 pixel wide at full length. The window can be created from any of the 4 sides. When I hover over this transparent window, the WM_NCHITTEST event comes. It creates a popup window and checks every 400 milliseconds that the cursor is within the popup window. As soon as the cursor leaves the window, then after 400 milliseconds, the code for smoothly increasing transparency is executed until it becomes invisible and then the window is hidden.
At the moment WM_NCHITTEST is called all the time and I don't understand why. If I take another example with WM_NCHITTEST, then it can be seen that events only come when the cursor is over the window.

Code: Select all

EnableExplicit

#Win_tr = 0
#Window = 1
#Timer = 0

Global Point.POINT
Global DesktopWidth, DesktopHeight
Global hGUI, hGUI_tr
Global ww, hh, i, ifTimer = 1

Declare WM_NCHITTEST(hWnd, Msg, wParam, lParam)
Declare DelayGui()


ExamineDesktops()
DesktopWidth = DesktopWidth(0)
DesktopHeight = DesktopHeight(0)


ww = 99
hh = 600

; создаём прозрачное окно шириной 1 писсель справа, чтобы реагировать при наведении выши на него
; hGUI_tr = OpenWindow(#Win_tr, DesktopWidth - 1, 0, 1, DesktopHeight, "", #PB_Window_BorderLess)
hGUI_tr = OpenWindow(#Win_tr, 0, 0, 1, DesktopHeight, "", #PB_Window_BorderLess)
SetWindowLongPtr_(hGUI_tr,#GWL_EXSTYLE,GetWindowLongPtr_(hGUI_tr,#GWL_EXSTYLE) | #WS_EX_TOOLWINDOW | #WS_EX_TOPMOST | #WS_EX_LAYERED)
StickyWindow(#Win_tr, #True)
SetWindowColor(#Win_tr, 0)
SetLayeredWindowAttributes_(hGUI_tr, 0, 1, 3)


; hGUI = OpenWindow(#Window, 0, 0, ww, hh, "", #PB_Window_SystemMenu | #WS_POPUP | #WS_THICKFRAME | #WS_SIZEBOX)
; всплывающее окно
hGUI = OpenWindow(#Window, DesktopWidth - 140, 80, 95, 400, "", #PB_Window_SystemMenu | #PB_Window_BorderLess | #PB_Window_SizeGadget)
SetWindowLongPtr_(hGUI,#GWL_EXSTYLE,GetWindowLongPtr_(hGUI,#GWL_EXSTYLE) | #WS_EX_TOOLWINDOW | #WS_EX_TOPMOST | #WS_EX_LAYERED)
SetLayeredWindowAttributes_(hGUI, 0, 255, 2)

; StickyWindow(#Window, #True) 
; Delay(200)
; For i = 245 To 1 Step -14
; 	SetLayeredWindowAttributes_(hGUI, 0, i, 2)
; 	Delay(10)
; Next
HideWindow(#Window, #True) 

SetWindowCallback(@WM_NCHITTEST(), #Win_tr)

Repeat
	Select WaitWindowEvent()
			Case #PB_Event_Timer
				If EventTimer() = #Timer
; 					ifTimer = 0
					DelayGui()
				EndIf
		Case #PB_Event_CloseWindow
			CloseWindow(#Window)
			CloseWindow(#Win_tr)
			End
	EndSelect
ForEver


; Эта функция должна выполнятся только если курсор в окне
Procedure WM_NCHITTEST(hWnd, Msg, wParam, lParam)
	Protected Result = #PB_ProcessPureBasicEvents, i, X, Y
	Protected yClient = lParam >> 16
	Protected xClient = lParam & $FFF
	If yClient
; 		If hWnd = hGui_tr
; 			If Not BitAnd(WinGetState(Gui$), 2) ; если окно не отображается, то
			If GetActiveWindow() <> #Window
				HideWindow(#Window, #False)
				For i = 1 To 255 Step 7
					SetLayeredWindowAttributes_(hGUI, 0, i, 3)
					Delay(10)
				Next
			Else
				HideWindow(#Window, #False)
			EndIf
; 			If ifTimer
				AddWindowTimer(#Window, #Timer, 400)
; 				ifTimer = 0
; 				Debug 1
; 			EndIf
; 				переместить прозрачное окно за пределы экрана
			ResizeWindow(#Win_tr , DesktopWidth + 2 , #PB_Ignore, #PB_Ignore , #PB_Ignore)
			; ProcedureReturn
		EndIf
; 	EndIf
	ProcedureReturn Result
EndProcedure

; Функция вызывается пока курсор находится в окне
Procedure DelayGui()
	Protected i
	GetCursorPos_(@Point)
; 	Debug Point\x
; 	Debug Point\y
	
; 	если Х-координата курсора больше ширины экрана, то
	If Point\x >= DesktopWidth - 1
		ProcedureReturn
	EndIf

; 	Protected WinW = WindowWidth(#Window)
; 	Protected WinH = WindowHeight(#Window)
	Protected WinX = WindowX(#Window)
	Protected WinY = WindowY(#Window)
; 	Если курсор внутри окна, то выпрыгиваем не разрегистрируя таймер
	If Point\x >= WinX And Point\x <= WinX + WindowWidth(#Window) And Point\y >= WinY And Point\y <= WinY + WindowHeight(#Window)
		ProcedureReturn
	EndIf
	
; 	скрываем окно разрегистрируя таймер
	Delay(600)
	For i = 245 To 1 Step -7
		SetLayeredWindowAttributes_(hGUI, 0, i, 3)
		Delay(10)
	Next
	HideWindow(#Window, #True)
; 	убираем окно за пределы экрана
	ResizeWindow(#Win_tr , DesktopWidth - 1, #PB_Ignore, #PB_Ignore , #PB_Ignore)
	RemoveWindowTimer(#Window, #Timer)
; 	ifTimer = 1
EndProcedure
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Popup window when the cursor is at the edge of the screen (?)

Post by netmaestro »

See if this appeals to you at all, it just takes a different approach from the AutoIT implementation. Buncha less code anyway:

Code: Select all

Global tme.TRACKMOUSEEVENT, tracking.i=0
ExamineDesktops()
OpenWindow(0, DesktopWidth(0) - 220, 80, 200, 400, "", #PB_Window_SystemMenu | #PB_Window_BorderLess| #PB_Window_SizeGadget | #PB_Window_Tool |#PB_Window_Invisible)
AddWindowTimer(0, 1, 10)

Repeat
  EventID = WaitWindowEvent()
  Select EventID
    Case #WM_MOUSEMOVE  
      If Not tracking
      With tme
        \cbSize = SizeOf(TRACKMOUSEEVENT)
        \dwflags = #TME_HOVER|#TME_LEAVE
        \dwHoverTime = #HOVER_DEFAULT
        \hwndTrack = WindowID(0)
      EndWith
      tracking = #True
      TrackMouseEvent_(tme)
     EndIf
     
    Case #WM_MOUSELEAVE
      tracking = #False
      AnimateWindow_(WindowID(0), 1000, #AW_CENTER|#AW_HIDE)
      AddWindowTimer(0, 1, 10)
      
    Case #PB_Event_Timer
      Select EventTimer()
        Case 1
          GetCursorPos_(@cp.POINT)
          If cp\x >= DesktopWidth(0)-2
            AnimateWindow_(WindowID(0), 1000, #AW_CENTER|#AW_ACTIVATE)
            RemoveWindowTimer(0,1)
          EndIf
      EndSelect
  EndSelect
Until EventID=#PB_Event_CloseWindow
BERESHEIT
AZJIO
Addict
Addict
Posts: 2143
Joined: Sun May 14, 2017 1:48 am

Re: Popup window when the cursor is at the edge of the screen (?)

Post by AZJIO »

Maybe in vain I clung to WM_NCHITTEST? I was hoping this would be more streamlined as it uses native mouse events.

Code: Select all

EnableExplicit

#Window = 1
#Timer = 0
#TimerHide = 1

Global Point.POINT
; Global DesktopWidth, DesktopHeight
Global hGUI
Global ww, hh, i

Declare WM_NCHITTEST(hWnd, Msg, wParam, lParam)
Declare DelayGui()


; ExamineDesktops()
; DesktopWidth = DesktopWidth(0)
; DesktopHeight = DesktopHeight(0)

; ww = 99
; hh = 600

; всплывающее окно
hGUI = OpenWindow(#Window, 2, 80, 95, 400, "", #PB_Window_SystemMenu | #PB_Window_BorderLess | #PB_Window_SizeGadget)
SetWindowLongPtr_(hGUI,#GWL_EXSTYLE,GetWindowLongPtr_(hGUI,#GWL_EXSTYLE) | #WS_EX_TOOLWINDOW | #WS_EX_TOPMOST | #WS_EX_LAYERED)
SetLayeredWindowAttributes_(hGUI, 0, 255, 2)

StickyWindow(#Window, #True) 
Delay(200)
For i = 245 To 1 Step -14
	SetLayeredWindowAttributes_(hGUI, 0, i, 2)
	Delay(10)
Next
HideWindow(#Window, #True) 

AddWindowTimer(#Window, #Timer, 40)

Repeat
	Select WaitWindowEvent()
		Case #PB_Event_Timer
			Select EventTimer()
			Case #PB_Event_Timer
				Case #TimerHide
					DelayGui()
				Case #Timer
					GetCursorPos_(@Point.POINT)
					If Point\x <= 2
							HideWindow(#Window, #False)
							For i = 1 To 255 Step 7
								SetLayeredWindowAttributes_(hGUI, 0, i, 3)
								Delay(10)
							Next
							RemoveWindowTimer(#Window, #Timer)
							AddWindowTimer(#Window, #TimerHide, 400)
					EndIf
			EndSelect
		Case #PB_Event_CloseWindow
			CloseWindow(#Window)
			End
	EndSelect
ForEver

; Функция вызывается пока курсор находится в окне
Procedure DelayGui()
	Protected i
	GetCursorPos_(@Point)
	
; 	если Х-координата курсора больше ширины экрана, то
	If Point\x <= 2
		ProcedureReturn
	EndIf

; 	Protected WinW = WindowWidth(#Window)
; 	Protected WinH = WindowHeight(#Window)
	Protected WinX = WindowX(#Window)
	Protected WinY = WindowY(#Window)
; 	Если курсор внутри окна, то выпрыгиваем не разрегистрируя таймер
	If Point\x >= WinX And Point\x <= WinX + WindowWidth(#Window) And Point\y >= WinY And Point\y <= WinY + WindowHeight(#Window)
		ProcedureReturn
	EndIf
	
; 	скрываем окно разрегистрируя таймер
	Delay(600)
	For i = 245 To 1 Step -7
		SetLayeredWindowAttributes_(hGUI, 0, i, 3)
		Delay(10)
	Next
	HideWindow(#Window, #True)
	RemoveWindowTimer(#Window, #TimerHide)
	AddWindowTimer(#Window, #Timer, 40)
EndProcedure
Happened

Code: Select all

EnableExplicit

#Win_tr = 0
#Window = 1
#Timer = 0

Global Point.POINT
Global DesktopWidth, DesktopHeight
Global hGUI, hGUI_tr
Global ww, hh, i, ifTimer = 1

Declare WM_NCHITTEST(hWnd, Msg, wParam, lParam)
Declare DelayGui()


ExamineDesktops()
DesktopWidth = DesktopWidth(0)
DesktopHeight = DesktopHeight(0)


ww = 99
hh = 600

; создаём прозрачное окно шириной 1 писсель справа, чтобы реагировать при наведении выши на него
hGUI_tr = OpenWindow(#Win_tr, DesktopWidth - 1, 0, 1, DesktopHeight, "", #PB_Window_BorderLess)
; hGUI_tr = OpenWindow(#Win_tr, 0, 0, 1, DesktopHeight, "", #PB_Window_BorderLess)
SetWindowLongPtr_(hGUI_tr,#GWL_EXSTYLE,GetWindowLongPtr_(hGUI_tr,#GWL_EXSTYLE) | #WS_EX_TOOLWINDOW | #WS_EX_TOPMOST | #WS_EX_LAYERED)
StickyWindow(#Win_tr, #True)
SetWindowColor(#Win_tr, 0)
SetLayeredWindowAttributes_(hGUI_tr, 0, 1, 0)


; hGUI = OpenWindow(#Window, 0, 0, ww, hh, "", #PB_Window_SystemMenu | #WS_POPUP | #WS_THICKFRAME | #WS_SIZEBOX)
; всплывающее окно
hGUI = OpenWindow(#Window, DesktopWidth - 140, 80, 95, 400, "", #PB_Window_SystemMenu | #PB_Window_BorderLess | #PB_Window_SizeGadget)
SetWindowLongPtr_(hGUI,#GWL_EXSTYLE,GetWindowLongPtr_(hGUI,#GWL_EXSTYLE) | #WS_EX_TOOLWINDOW | #WS_EX_TOPMOST | #WS_EX_LAYERED)
SetLayeredWindowAttributes_(hGUI, 0, 255, 2)

StickyWindow(#Window, #True) 
Delay(200)
For i = 245 To 1 Step -14
	SetLayeredWindowAttributes_(hGUI, 0, i, 2)
	Delay(10)
Next
HideWindow(#Window, #True) 

SetWindowCallback(@WM_NCHITTEST(), #Win_tr)

Repeat
	Select WaitWindowEvent()
			Case #PB_Event_Timer
				If EventTimer() = #Timer
; 					ifTimer = 0
					DelayGui()
				EndIf
		Case #PB_Event_CloseWindow
			CloseWindow(#Window)
			CloseWindow(#Win_tr)
			End
	EndSelect
ForEver


; Эта функция должна выполнятся только если курсор в окне
Procedure WM_NCHITTEST(hWnd, Msg, wParam, lParam)
	Protected Result = #PB_ProcessPureBasicEvents, i
; 	Protected yClient = lParam >> 16
; 	Protected xClient = lParam & $FFF
	Static k
	GetCursorPos_(@Point)
	
	Debug Point\x
; 	Debug xClient
	; 	если Х-координата курсора больше ширины экрана, то
	If Point\x >= DesktopWidth - 1
		k+1
		; Debug Point\x
		Debug k
		If Not IsWindowVisible_(hGUI)
			HideWindow(#Window, #False)
			For i = 1 To 255 Step 7
				SetLayeredWindowAttributes_(hGUI, 0, i, 3)
				Delay(10)
			Next
; 		Else
; 			HideWindow(#Window, #False)
		EndIf
		AddWindowTimer(#Window, #Timer, 400)
		; переместить прозрачное окно за пределы экрана
		ResizeWindow(#Win_tr , DesktopWidth + 2 , #PB_Ignore, #PB_Ignore , #PB_Ignore)
	EndIf
	ProcedureReturn Result
EndProcedure

; Функция вызывается пока курсор находится в окне
Procedure DelayGui()
	Protected i
	GetCursorPos_(@Point)
; 	Debug Point\x
; 	Debug Point\y
	
; 	если Х-координата курсора больше ширины экрана, то
	If Point\x >= DesktopWidth - 1
		ProcedureReturn
	EndIf

; 	Protected WinW = WindowWidth(#Window)
; 	Protected WinH = WindowHeight(#Window)
	Protected WinX = WindowX(#Window)
	Protected WinY = WindowY(#Window)
; 	Если курсор внутри окна, то выпрыгиваем не разрегистрируя таймер
; 	If Point\x >= WinX And Point\x <= WinX + WindowWidth(#Window) And Point\y >= WinY And Point\y <= WinY + WindowHeight(#Window)
	If Point\x >= WinX - 10 And Point\x <= WinX + WindowWidth(#Window) + 10 And Point\y >= WinY - 10 And Point\y <= WinY + WindowHeight(#Window) + 30
		ProcedureReturn
	EndIf
	
; 	скрываем окно разрегистрируя таймер
	Delay(600)
	For i = 245 To 1 Step -7
		SetLayeredWindowAttributes_(hGUI, 0, i, 3)
		Delay(10)
	Next
	HideWindow(#Window, #True)
; 	убираем окно за пределы экрана
	ResizeWindow(#Win_tr , DesktopWidth - 1, #PB_Ignore, #PB_Ignore , #PB_Ignore)
	RemoveWindowTimer(#Window, #Timer)
; 	ifTimer = 1
EndProcedure
Post Reply