Always-On-Top Window, Keyboard- und Mouse-Hooks

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Always-On-Top Window, Keyboard- und Mouse-Hooks

Beitrag von NicTheQuick »

Hi Leute,

ich möchte mich für ein kleines nochmal an die Windows-Programmierung wagen. Dabei geht es um was ganz simples, was aber vermutlich wieder Windows-API notwendig macht und wo ich nicht weiß, ob das in Windows 10 überhaupt noch so gut geht.

Und zwar will ich ein ganz schmales randloses Fenster erstellen, dass sich von ganz links bis ganz rechts über den Bildschirm erstreckt, aber nur wenige Pixel hoch ist und einfach nur einfarbig ist. Das Fenster soll immer sichtbar, also always on top sein. Dann möchte ich z.B. durch das Drücken von STRG+ALT und gleichzeitigem Scrollen am Mausrad das Fenster nach oben und unten verschieben können, und zwar ohne dass das Fenster den Fokus haben muss.

Vermutlich sind das wenige Zeilen Code, aber gerade scheitert es bei mir an allem. Always On Top werde ich sicherlich noch irgendwo in der WinAPI-Sammlung von RSBasic finden oder in der Sammlung auf Github von Sicro. Aber die Sache mit dem Abfangen des Scrollrades und der Tasten wird mir vermutlich Probleme bereiten, da man da ja wahrscheinlich Hooks verwenden muss. Sind diese Hooks überhaupt noch erlaubt oder kommt dann gleich der Virenscanner oder sogar Windows selbst und meckert, weil das ja ein Keylogger sein könnte?
Bild
Benutzeravatar
bobobo
jaAdmin
Beiträge: 3857
Registriert: 13.09.2004 17:48
Kontaktdaten:

Re: Always-On-Top Window, Keyboard- und Mouse-Hooks

Beitrag von bobobo »

on top ist einfach dünkt mir

Code: Alles auswählen

Enumeration
  #win1
  #win2
  #bg
EndEnumeration

ExamineDesktops()
wx=DesktopWidth(0)

Select fenster
  Case 1  ; zeigt in der Taskleiste ein Fenster
    OpenWindow(#win2,0,0,wx,10,"finster",#PB_Window_BorderLess)
    
  Case 0 ; zeigt in der Taskleiste kein Fenster
    OpenWindow(#win1,0,0,0,0,"Parent",#PB_Window_Invisible)
    OpenWindow(#win2,0,0,wx,10,"finster",#PB_Window_BorderLess,WindowID(#win1))
EndSelect

StickyWindow(#win2,1)
CanvasGadget(#bg,0,0,WindowWidth(#win2),WindowHeight(#win2))
StartDrawing (CanvasOutput(#bg))
  Box(0,0,WindowWidth(#win2),WindowHeight(#win2),#Red)
StopDrawing()

Repeat
Until WaitWindowEvent()=#PB_Event_CloseWindow
Zur Hookerei fällt mir erstmal nichts ein.
ausser

https://www.rsbasic.de/aktualisierung/w ... se-Hook.pb
‮pb aktuell5.7 - windoof aktuell und sowas von 10
Ich hab Tinnitus im Auge. Ich seh nur Pfeifen.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Always-On-Top Window, Keyboard- und Mouse-Hooks

Beitrag von NicTheQuick »

Bin gut voran gekommen. Noch eine weitere Frage zu diesem Code:

Code: Alles auswählen

If OpenWindow(0,0,0,500,250,"Window",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
Repeat
EventID=WaitWindowEvent()
Select EventID
   Case #WM_LBUTTONDOWN
     SendMessage_(WindowID(0),#WM_NCLBUTTONDOWN, #HTCAPTION,0)
  EndSelect
Until EventID = #PB_Event_CloseWindow
EndIf
Wie kann ich es verhindern, dass man Fenster nach links oder rechts verschieben kann? Ich möchte, dass man es nur hoch und runter schieben kann.
Bild
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Always-On-Top Window, Keyboard- und Mouse-Hooks

Beitrag von Kiffi »

hier ganz ohne API:

Code: Alles auswählen

Enumeration
	#Window
	#Button
	#Canvas
EndEnumeration

Procedure Exit()
	End
EndProcedure

Procedure LeftMouseDown()
	Shared MouseDown, OffsetX, OffsetY
	MouseDown = #True
	OffsetX = WindowMouseX(#Window)
	OffsetY = WindowMouseY(#Window)
EndProcedure

Procedure LeftMouseUp()
	Shared MouseDown
	MouseDown = #False
EndProcedure

Procedure MouseMove()
	Shared MouseDown, OffsetX, OffsetY
	If MouseDown And GetGadgetAttribute(#Canvas, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton
		ResizeWindow(#Window, 0, DesktopMouseY() - OffsetY, #PB_Ignore, #PB_Ignore)
	EndIf
EndProcedure

ExamineDesktops()

If OpenWindow(#Window, 0, 0, DesktopWidth(0),20, "Moveable window", #PB_Window_BorderLess)
	
	ButtonGadget(#Button, 0, 0, 20, 20, "X")
	BindEvent(#PB_Event_Gadget, @Exit(), #Window, #Button, #PB_EventType_LeftClick)
	
	CanvasGadget(#Canvas, 20, 0, DesktopWidth(0) - 20, 20)
	BindEvent(#PB_Event_Gadget, @LeftMouseDown(), #Window, #Canvas, #PB_EventType_LeftButtonDown)
	BindEvent(#PB_Event_Gadget, @LeftMouseUp()  , #Window, #Canvas, #PB_EventType_LeftButtonUp)
	BindEvent(#PB_Event_Gadget, @MouseMove()    , #Window, #Canvas, #PB_EventType_MouseMove)
	
	If StartDrawing(CanvasOutput(#Canvas))
		Box(0, 0, OutputWidth(), OutputHeight(), RGB(255, 0, 0))
		StopDrawing()
	EndIf
	
	StickyWindow(#Window, #True)
	
	Repeat
		WaitWindowEvent()
	ForEver
	
EndIf
(geklaut von Danilo (https://www.purebasic.fr/english/viewto ... 66#p429066) und ein wenig angepasst)

Grüße ... Peter
Hygge
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Always-On-Top Window, Keyboard- und Mouse-Hooks

Beitrag von NicTheQuick »

Ich hab mir das jetzt wie folgt so zusammengehackt. Aber zuerst die Bedienung:
STRG+ALT 500ms gedrückt halten und das Fenster wird sichtbar bzw. unsichtbar.
Drückt man STRG+ALT nur kurz während es sichtbar ist, springt das Fenster zur aktuellen Mausposition. Das geht auch mit mehreren Desktops.
Hält man STRG+ALT gedrückt und bewegt die Maus, dann folgt ihr das Fenster. Solange man die Maus bewegt, wird das Fenster nicht nach 500ms unsichtbar.
Gibt man dem Fenster den Fokus, wird es grün und so kann man es auch per Drag&Drop verschieben oder mit dem Mausrad die Höhe ändern.
Beenden geht nur, wenn das Fenster grün ist und man Alt+F4 drückt.

Und noch was zur Qualität des Codes ansich: Er ist definitiv noch nicht ausgereift. Einige Dinge gehen bestimmt eleganter und ohne WindowTimer, sondern mit BindGadget oder ähnlichem. Mal sehen, ob ich das noch ändern will. ;-)

Code: Alles auswählen

EnableExplicit

Global lineHeight = 10
#toggleTime = 500

Define.i normalColor = RGB(255, 0, 0)
Define.i activatedColor = RGB(0, 127, 0)

Enumeration Windows
	#parentWindow
	#mainWindow
EndEnumeration

Global ctrlPressed.i = #False
Global altPressed.i = #False
Define windowDrag.i = #False
Define visible.i = #False
Define singleRefresh.i = #True

Procedure.l KeyboardHook(nCode, wParam, *p.KBDLLHOOKSTRUCT)
	Protected pressed.i, used = #True
	
	If wParam = #WM_KEYDOWN Or wParam = #WM_SYSKEYDOWN
		pressed = #True
	EndIf
	If wParam = #WM_KEYUP Or wParam = #WM_SYSKEYUP
	EndIf
	
	Select *p\vkCode
		Case %10100010:
			ctrlPressed = pressed
		Case %10100100:
			altPressed = pressed
		Default
			used = #False
	EndSelect
	
	If used
		ProcedureReturn 1
		PostEvent(#PB_Event_MoveWindow, #mainWindow, 0)
	Else
		ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
	EndIf
EndProcedure

Procedure.w MouseWheelDelta() 
	Protected x.w
	
	x.w = ((EventwParam() >> 16) & $FFFF) 
	ProcedureReturn (x / 120) 
EndProcedure 


ExamineDesktops()
Define.i windowWidth = DesktopWidth(0)

If Not OpenWindow(#parentWindow, 0, 0, 0, 0, "Parent", #PB_Window_Invisible)
	End
EndIf
If Not OpenWindow(#mainWindow, 0, 0, windowWidth, lineHeight, "Lesehilfe", #PB_Window_BorderLess | #PB_Window_Invisible, WindowID(#parentWindow))
	End
EndIf

SetWindowsHookEx_(#WH_KEYBOARD_LL, @KeyboardHook(), GetModuleHandle_(0), 0)

SetWindowColor(#mainWindow, normalColor)
SetWindowLongPtr_(WindowID(#mainWindow), #GWL_EXSTYLE, GetWindowLongPtr_(WindowID(#mainWindow), #GWL_EXSTYLE) | #WS_EX_LAYERED)
SetLayeredWindowAttributes_(WindowID(#mainWindow), 0, 127, #LWA_ALPHA)

StickyWindow(#mainWindow, #True)

Define.i toggleTimer.i = ElapsedMilliseconds()
Define.i oldY.i = WindowY(#mainWindow), newY.i
Define.i oldX.i = WindowX(#mainWindow), newX.i

AddWindowTimer(#mainWindow, 0, 50)

Repeat
	Define eventId.i = WaitWindowEvent()
	
	If (ctrlPressed And altPressed) Or windowDrag Or singleRefresh :
		If visible :
			newY = DesktopMouseY()
			newX = DesktopMouseX()
			Define cDesktop.i = ExamineDesktops()
			Define desktop
			For desktop = 0 To cDesktop - 1
				If newY >= DesktopY(desktop) And newY < DesktopY(desktop) + DesktopHeight(desktop) And newX >= DesktopX(desktop) And newX < DesktopX(desktop) + DesktopWidth(desktop)
					ResizeWindow(#mainWindow, DesktopX(desktop), newY - lineHeight / 2, DesktopWidth(desktop), lineHeight)
					Break
				EndIf
			Next
			
			If newY <> oldY
				toggleTimer = ElapsedMilliseconds()
			EndIf
			oldY = newY
		EndIf
		If ElapsedMilliseconds() - #toggleTime > toggleTimer
			HideWindow(#mainWindow, visible, #PB_Window_NoActivate)
			visible = Bool(Not visible)
			toggleTimer = ElapsedMilliseconds()
		EndIf
		singleRefresh = #False
	Else
		toggleTimer = ElapsedMilliseconds()
	EndIf
	If GetActiveWindow() = #mainWindow
		SetWindowColor(#mainWindow, activatedColor)
	Else
		SetWindowColor(#mainWindow, normalColor)
	EndIf
	Select eventId
		Case #WM_LBUTTONDOWN:
			windowDrag = #True
		Case #WM_LBUTTONUP
			windowDrag = #False
		Case #WM_MOUSEWHEEL
			lineHeight + MouseWheelDelta()
			If lineHeight < 4
				lineHeight = 4
			EndIf
			singleRefresh = #True
		Case #PB_Event_CloseWindow
			Break
	EndSelect
ForEver
Bild
Antworten