Use hotkeys to activate buttons... (Windows)

Share your advanced PureBasic knowledge/code with the community.
User avatar
Michael Vogel
Addict
Addict
Posts: 2680
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Use hotkeys to activate buttons... (Windows)

Post by Michael Vogel »

I am using some nice programs (for example the cool PDFXChange Viewer or the Purebasic IDE) which don't support shortcuts for all dialogs. Therefore I've written the following tool which simplifies controlling these programs by using the keyboard.

As soon a Win+Alt+Character hotkey is pressed, the tool scans the active window if there's a matching name for any object and tries to activate it.

Don't forget to add some keywords in the data section as you like.

Have fun!

Code: Select all

; Define

	EnableExplicit

	#SysTray=1
	#ApplicationTitle="·:H:·"

	Global WinID
	Global HotKey
	Global Scan
	Global Quit
	Global Active=#True

	Structure ObjectType
		Handle.i
		Title.s
		Class.s
	EndStructure

	#CharByte=SizeOf(Character)
	#CharShift=#CharByte>>1

	#ObjectTextLength=256
	#Hotkeys=26
	#Window=0

	Enumeration
		#PopupMenu
		#PopupState
		#PopupQuit
	EndEnumeration

	DataSection
		Keywords:
		Data.s "|abort|apply|abbrechen|enable inline asm syntax coloring"; a
		Data.s ""; b
		Data.s "|cancel|close"; c
		Data.s ""; d
		Data.s ""; e
		Data.s "|find next"; f
		Data.s ""; g
		Data.s ""; h
		Data.s "|search inside selection only"; i
		Data.s ""; j
		Data.s ""; k
		Data.s "|replace all"; l
		Data.s "|don't search in comments|enable modern theme support (for windows xp and above)"; m
		Data.s ""; n
		Data.s "|ok|okay"; o
		Data.s ""; p
		Data.s ""; q
		Data.s "|replace"; r
		Data.s "|case sensitive"; s
		Data.s "|create threadsafe executable"; t
		Data.s "|create unicode executable"; u
		Data.s ""; v
		Data.s "|whole words only"; w
		Data.s ""; x
		Data.s ""; y
		Data.s ""; z
	EndDataSection
	
	
	Global Dim mem.i(#Hotkeys)


	CompilerIf #SysTray

		#IconSize=1150;		RGB/A 16x16
		DataSection
			Icon:
			Data.q $1010000100010000,$468002000010000,$28000000160000,$20000000100000,$2000010000,$4400000,0,$19B2000000000000,$4CFF15004CFF00,$4CFF15004CFF15,$4CFF15004CFF15,$4CFF15004CFF15,$4CFF15004CFF15,$4CFF15004CFF15,$4CFF15004CFF15,$66B2FF15004CFF15,$127FFF00127FFF00,$127FFF00127FFF00
			Data.q $127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00
			Data.q $83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00
			Data.q $127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00
			Data.q $66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$83E5FF0083E5FF00,$83E5FF0083E5FF00,$83E5FF0083E5FF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$83E5FF0083E5FF00,$83E5FF0083E5FF00,$83E5FF0083E5FF00,$19B2FF0083E5FF00
			Data.q $127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$83E5FF00127FFF00
			Data.q $19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00
			Data.q $83E5FF00127FFF00,$19B2FF0083E5FF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$66B2FF15004CFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00
			Data.q $127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$127FFF00127FFF00,$66B2FF15004CFF00,$66B2FF0066B2FF00,$66B2FF0066B2FF00,$66B2FF0066B2FF00,$66B2FF0066B2FF00,$66B2FF0066B2FF00,$66B2FF0066B2FF00,$66B2FF0066B2FF00,$FF0019B2FF00,0,0,0,0,0,0,0,0
		EndDataSection

	CompilerEndIf

; EndDefine

Procedure GetObjectInfo_(*Object.ObjectType,Set=#False)

	#MaxTextLength=256

	With *Object

		If Set
			\Handle=Set
		EndIf

		If \Handle
			\Title=Space(#MaxTextLength)
			\Class=Space(#MaxTextLength)
			GetWindowText_(\Handle,\Title,#MaxTextLength)
			GetClassName_(\Handle,\Class,#MaxTextLength)
			ProcedureReturn #True

		Else
			ProcedureReturn #False
		EndIf

	EndWith

EndProcedure
Procedure.s ActivateObject(handle)

	Protected Class.s

	Class=Space(#ObjectTextLength)
	GetClassName_(Handle,@Class,#ObjectTextLength)

	class=LCase(class)
	Select class

	Case "static"
		PostMessage_(GetWindow_(Handle,#GW_HWNDNEXT),#WM_ACTIVATE,#WA_ACTIVE,0)

	Case "button"
		;PostMessage_(handle,#WM_LBUTTONDOWN,#MK_LBUTTON,0)
		;Delay(100)
		;PostMessage_(handle,#WM_LBUTTONUP,#MK_LBUTTON,0)
		PostMessage_(handle,#BM_CLICK,#MK_LBUTTON,0)

	Default
		PostMessage_(handle,#WM_ACTIVATE,#WA_ACTIVE,0)

	EndSelect
	Scan=#False

EndProcedure
Procedure.s GetObjectInfo(handle)

	Protected n,c,*mem
	Protected Title.s
	Protected s.s

	Title=Space(#ObjectTextLength)
	GetWindowText_(Handle,@Title,#MaxTextLength)

	If Title
		n=FindString(title,"&")
		If n
			n=PeekA(@Title+n<<#CharShift)&$DF-'@'
			If n=hotkey
				ActivateObject(handle)
				;PostMessage_(handle,#BM_CLICK,#MK_LBUTTON,0)
			EndIf

		Else
			title=Trim(LCase(Title))
			*mem=mem(HotKey)
			If *mem
				Repeat
					c=PeekA(*mem)
					If c
						If title=PeekS(*mem+1,c)
							ActivateObject(handle)
						EndIf
						*mem+c+1
					EndIf
				Until c=0
			EndIf

		EndIf
	EndIf

EndProcedure
Procedure GetObjectTree(handle)

	Protected child

	Repeat
		GetObjectInfo(handle)
		child=GetWindow_(Handle,#GW_CHILD)
		If child
			GetObjectTree(child)
		EndIf
		handle=GetWindow_(Handle,#GW_HWNDNEXT)
	Until handle=0 Or Scan=0

EndProcedure
Procedure ScanNow()

	Protected handle
	Protected s.s

	handle=GetForegroundWindow_()
	If handle
		handle=GetWindow_(Handle,#GW_CHILD)
		If handle
			Scan=#True
			GetObjectTree(handle)
		EndIf
	EndIf

EndProcedure
Procedure ActivateHotkeys(mode)

	Protected n

	If mode
		RegisterHotKey_(WinID,600,#MOD_ALT|#MOD_SHIFT|#MOD_WIN,#VK_Q)
		For n=0 To #Hotkeys-1
			RegisterHotKey_(WinID,601+n,#MOD_ALT|#MOD_WIN,#VK_A+n)
		Next n

	Else
		For n=0 To #Hotkeys
			UnregisterHotKey_(WinID,600+n)
		Next n

	EndIf

EndProcedure

Procedure Main()

	Protected c,i,n
	Protected *mem
	Protected *pipe

	WinID=OpenWindow(#Window,8,8,8,8,#ApplicationTitle,#PB_Window_Invisible|#PB_Window_BorderLess)

	CompilerIf #SysTray
		AddSysTrayIcon(#SysTray,WinID,CatchImage(#SysTray,?Icon))
		SysTrayIconToolTip(#SysTray,"Hotkey by Michael Vogel")

		CreatePopupMenu(#PopupMenu)
		MenuItem(#PopupState,"Toggle Hotkey State")
		MenuItem(#PopupQuit,"Quit Hotkeys…")

	CompilerElse
		AddKeyboardShortcut(0,#PB_Shortcut_Escape,#PopupQuit)
		SetWindowColor(0,#Yellow)
		HideWindow(0,0)

	CompilerEndIf


	; Initialize Keywords...
	*mem=?Keywords
	For i=1 To #Hotkeys
		n=0
		*pipe=0
		mem(i)=*mem
		Repeat
			c=PeekA(*mem)
			Select c
			Case #Null
				If *pipe
					PokeA(*pipe,n)
				EndIf
			Case '|'
				If *pipe
					PokeA(*pipe,n)
				EndIf
				*pipe=*mem
			Default
				CompilerIf #PB_Compiler_Debugger
					If *pipe=0
						Debug "Illegal Data - "+PeekS(*mem)+" pipe symbol missing."
						End
					EndIf
				CompilerEndIf
				n+1
			EndSelect
			*mem+#CharByte
		Until c=#Null
	Next i


	ActivateHotkeys(#True)

	Repeat
		Select WaitWindowEvent()

		Case #WM_HOTKEY
			n=EventwParam()
			Select n
			Case 600
				PostEvent(#PB_Event_CloseWindow)
			Case 601 To 626
				If Active
				HotKey=n-600
				ScanNow()
				EndIf
			EndSelect

		Case #PB_Event_CloseWindow
			quit=#True

			CompilerIf #SysTray
			Case #PB_Event_SysTray
				Select EventType()
				Case #PB_EventType_LeftClick
					DisplayPopupMenu(#PopupMenu,WinID)
				Case #PB_EventType_RightClick
					quit=#True
				Case #PB_EventType_LeftDoubleClick
					PostEvent(#PB_Event_Menu,#Window,#PopupState)
				EndSelect
			CompilerEndIf


		Case #PB_Event_Menu;#PB_Event_Gadget
			Select EventGadget()
			Case #PopupQuit
				quit=#True
				CompilerIf #SysTray
				Case #PopupState
					For n=0 To 15
						For i=0 To 15
							*mem=?Icon+62+(n+i<<4)<<2
							PokeL(*mem,PeekL(*mem)!$00FF00FF)
						Next i
					Next n
					ChangeSysTrayIcon(#SysTray,CatchImage(#SysTray,?Icon))
					Active!1
				CompilerEndIf
			EndSelect
		EndSelect
	Until quit

	ActivateHotkeys(#False)
	End

EndProcedure

If FindWindow_(0,#ApplicationTitle)=0
	Main()
EndIf
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Use hotkeys to activate buttons... (Windows)

Post by Lord »

Please add spaces after commas in your data lines.
Right now it's horrible to look at your code.
Image
User avatar
C87
Enthusiast
Enthusiast
Posts: 176
Joined: Mon Jul 17, 2017 7:22 am
Location: Cotswolds England

Re: Use hotkeys to activate buttons... (Windows)

Post by C87 »

Please add spaces after commas in your data lines.
Right now it's horrible to look at your code.
If MV prefers to write his code in this way, what business is it of anyone else?
If it's falling over......just remember the computer is never wrong!
BarryG
Addict
Addict
Posts: 3330
Joined: Thu Apr 18, 2019 8:17 am

Re: Use hotkeys to activate buttons... (Windows)

Post by BarryG »

Lord wrote:Right now it's horrible to look at your code.
Ctrl+A then Ctrl+I in the IDE. Code formatted to your personal prefs. Done.

Thanks for the code too, Michael. It looks interesting and something I may need.
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Use hotkeys to activate buttons... (Windows)

Post by Lord »

BarryG wrote:
Lord wrote:Right now it's horrible to look at your code.
Ctrl+A then Ctrl+I in the IDE. Code formatted to your personal prefs. Done.

Thanks for the code too, Michael. It looks interesting and something I may need.
What does the PB IDE have to do with the code displayed in the forum?
Nothing!
Take the advice: Switch on your brain before sending a reply.
Image
User avatar
Michael Vogel
Addict
Addict
Posts: 2680
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Use hotkeys to activate buttons... (Windows)

Post by Michael Vogel »

:idea: Emergency replacement kit for our Lord...

Code: Select all

Macro ss : 0,0,0,0 : EndMacro : Macro uu : 0,128 : EndMacro : Macro xx : 0,$80 : EndMacro
#IconSize=1150
DataSection
	Icon:
	Data.w 0,1,1,4112,0,1,32,1128,0,22,0,40,0,16,0,32,0,1,32,0,0,1088,ss,ss,ss,ss,ss,ss,ss,ss,ss
	Data.w ss,ss,ss,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu
	Data.w uu,xx,xx,uu,uu,xx,uu,xx,uu,xx,uu,uu,uu,uu,xx,xx,uu,uu,xx,xx,xx,uu,uu,xx,xx,uu,uu
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx,uu,xx,uu,xx,uu
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx
	Data.w xx,uu,uu,xx,uu,xx,xx,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,xx,xx,uu,uu,xx,uu,uu,xx
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,xx,uu,uu,xx,uu,uu,xx
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx,uu,xx,uu,xx,uu
	Data.w uu,xx,xx,uu,uu,xx,uu,xx,uu,xx,xx,xx,uu,uu,xx,xx,uu,uu,xx,uu,uu,xx,uu,xx,xx,uu,uu
	Data.w uu,uu,uu,uu,uu,uu,uu,uu,uu,0,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,ss,ss,ss,ss,ss,ss,ss
	Data.q ss
EndDataSection
User avatar
C87
Enthusiast
Enthusiast
Posts: 176
Joined: Mon Jul 17, 2017 7:22 am
Location: Cotswolds England

Re: Use hotkeys to activate buttons... (Windows)

Post by C87 »

Quite frankly Lordy I do not see that criticising a fellow forum user is of benefit to anyone. Let's face it MV spent a great deal of time writing, checking and issuing the program. MV and many others may well now think twice before issuing their software. Then we will all be the poorer for it. Criticising anything on this forum is not acceptable, let alone over such a trivial matter or personal opinion. This is after all not a social media site. The PureB forum is somewhere where help is freely given and asked for without any judgement expected. By the way, are you a paid up member of the code police? :lol: :lol:
If it's falling over......just remember the computer is never wrong!
User avatar
Lord
Addict
Addict
Posts: 849
Joined: Tue May 26, 2009 2:11 pm

Re: Use hotkeys to activate buttons... (Windows)

Post by Lord »

Michael Vogel wrote::idea: Emergency replacement kit for our Lord...

Code: Select all

Macro ss : 0,0,0,0 : EndMacro : Macro uu : 0,128 : EndMacro : Macro xx : 0,$80 : EndMacro
#IconSize=1150
DataSection
	Icon:
	Data.w 0,1,1,4112,0,1,32,1128,0,22,0,40,0,16,0,32,0,1,32,0,0,1088,ss,ss,ss,ss,ss,ss,ss,ss,ss
	Data.w ss,ss,ss,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu
	Data.w uu,xx,xx,uu,uu,xx,uu,xx,uu,xx,uu,uu,uu,uu,xx,xx,uu,uu,xx,xx,xx,uu,uu,xx,xx,uu,uu
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx,uu,xx,uu,xx,uu
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx
	Data.w xx,uu,uu,xx,uu,xx,xx,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,xx,xx,uu,uu,xx,uu,uu,xx
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,xx,uu,uu,xx,uu,uu,xx
	Data.w xx,uu,uu,xx,uu,xx,uu,xx,uu,xx,uu,uu,uu,xx,uu,uu,xx,uu,xx,uu,uu,xx,uu,xx,uu,xx,uu
	Data.w uu,xx,xx,uu,uu,xx,uu,xx,uu,xx,xx,xx,uu,uu,xx,xx,uu,uu,xx,uu,uu,xx,uu,xx,xx,uu,uu
	Data.w uu,uu,uu,uu,uu,uu,uu,uu,uu,0,uu,uu,uu,uu,uu,uu,uu,uu,uu,uu,ss,ss,ss,ss,ss,ss,ss
	Data.q ss
EndDataSection
Very funny and a very mature reaction.
Image
User avatar
HeX0R
Addict
Addict
Posts: 992
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: Use hotkeys to activate buttons... (Windows)

Post by HeX0R »

I second Lords request!
No one thinks of people using tablets to browse the forum??
C87 wrote:Quite frankly Lordy I do not see that criticising {bla}{bla}{bla}
You don't seem to have a single idea what Lords request was all about, right?
Post Reply