Franky_FR hat geschrieben: 26.07.2022 13:56
... Hast Du für WM_KEYDOWN, Hotkey, KeyboardHooks kleine Beispiele ? ...
Weil du so nett gefragt hast.
Zum Thema KeyboardHooks hatte ich mal im englischen Forum was gepostet.
LowLevelKeyboardHook.pb
Ein etwas größeres Beispiel, dafür ist alles drin! (außer console)
Je nachdem ob du Windows Nachrichten mit WM_HOTKEY, WM_KEYDOWN in der Mainloop, Callback oder in Subclass Proceduren abfragen möchtest.
Hinweis: Nicht alle WM_* Nachrichten werden in der Mainloop bereitgestellt. So etwas ändert sich schonmal von einer PB-Version zur nächsten. (Beispiel: WM_Close) Es gibt unzählige alte Beispiele (für alte PB-Versionen) wo das mal funktioniert hatte....
Ach so, der Unterschied zwischen Callback und Subclass: Callback geht pro window nur eine, subclass gehen viele.
Okay, hier der Code.
Fragen? Fragen!
Code: Alles auswählen
;:: FILE : <New>
;:: Target OS : Windows
;:: License : Free, unrestricted, no warranty whatsoever
;:: Use at your own risk
;::
;:: Copyright (c) 2022 by AHa
CompilerIf #PB_Compiler_IsMainFile ;/--- Template for Testing
EnableExplicit
Enumeration EWindow 1
#WINDOW_Main
EndEnumeration
Enumeration EGadget 1
#GADGET_btnClick
#GADGET_edtOutput
EndEnumeration
#HotKey = 1
#MOD_NOREPEAT = $4000 ; not defined by default
; --- constants
#PB_Window_MainFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget
; --- global variables
Global Hotkey_Registered = #False
; --- windows API (windows only)
Procedure.s GetKeyNameText(lParam)
Protected string.s{80}
If GetKeyNameText_(lParam, @string, 80)
ProcedureReturn string
EndIf
ProcedureReturn ""
EndProcedure
; --- Hotkey Helpers
Procedure AddHotKey(Window, Hotkey, Modifier, VirtKey)
If IsWindow(Window) And Hotkey_Registered = #False
If Modifier <> 0 And VirtKey <> 0
RegisterHotKey_(WindowID(Window), Hotkey, Modifier, VirtKey)
Hotkey_Registered = #True
EndIf
EndIf
EndProcedure
Procedure RemoveHotKey(Window, Hotkey)
If IsWindow(Window) And Hotkey_Registered
UnregisterHotKey_(WindowID(Window), Hotkey)
Hotkey_Registered = #False
EndIf
EndProcedure
Procedure.i KeyPressed(VirtualKey) ; returns #False or #True -- #VK_SHIFT, #VK_CONTROL, etc.
If GetAsyncKeyState_(VirtualKey) & $8000
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure ;()
; --- procedures
Procedure Output(Message.s)
AddGadgetItem(#GADGET_edtOutput, -1, Message.s)
EndProcedure
Procedure OnEvent_SizeWindow()
Protected wndw, wndh
wndw = WindowWidth(#WINDOW_Main) : wndh = WindowHeight(#WINDOW_Main)
ResizeGadget(#GADGET_edtOutput, #PB_Ignore, #PB_Ignore, wndw - 8, wndh - 36)
EndProcedure ;()
Procedure MainWindow_CallbackProc(hWnd, uMsg, wParam, lParam)
; the PB way of doing callbacks
Select uMsg
Case #WM_HOTKEY
Output("callback: My Hotkey ")
Case #WM_KEYDOWN ;:Debug "callback: KEYDOWN"
Output("callback: Key is down key = " + wParam + ", Name = " + GetKeyNameText(lParam))
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure MainWindow_SubclassProc(hWnd, uMsg, wParam, lParam) ; standard windows interface for message events
Static s_hPrevWndProc = 0
Protected hPrevWndProc, state
hPrevWndProc = s_hPrevWndProc
Select uMsg ;
Case -1 :Debug "subclass: INTERNAL: init "
If wParam = ('I' << 24) | ('N' << 16) | ('I' << 8) | 'T'
hPrevWndProc = GetWindowLongPtr_(hWnd, #GWLP_WNDPROC) ; keep the window procedure address
SetWindowLongPtr_(hWnd, #GWLP_WNDPROC, @MainWindow_SubclassProc()) ; set window procedure to my callback procedure
s_hPrevWndProc = hPrevWndProc
;s_<Something to keep> = lParam ;' init by lParam
ProcedureReturn 0 ; system can give up on this message
EndIf
Case #WM_HOTKEY
Output("subclass: My Hotkey ")
Case #WM_KEYDOWN ;:Debug "subclass: KEYDOWN"
Output("subclass: Key is down key = " + wParam + ", Name = " + GetKeyNameText(lParam))
Case #WM_NCDESTROY :Debug "subclass: WM_NCDESTROY "
SetWindowLongPtr_(hWnd, #GWLP_WNDPROC, hPrevWndProc) ; necessary ?
s_hPrevWndProc = 0
EndSelect ; uMsg
ProcedureReturn CallWindowProc_(hPrevWndProc, hWnd, uMsg, wParam, lParam) ; use stored window procedure address
EndProcedure
; --- main window and loop ---
Procedure CreateMainWindow(WndW = 440, WndH = 400)
If OpenWindow(#WINDOW_Main, 0, 0, WndW, WndH, "__Caption__", #PB_Window_MainFlags)
StickyWindow(#WINDOW_Main, 1)
ButtonGadget(#GADGET_btnClick, 4, 4, 76, 20, "__Click_me__")
EditorGadget(#GADGET_edtOutput, 4, 32, WndW - 8, WndH - 36)
BindEvent(#PB_Event_SizeWindow, @OnEvent_SizeWindow(), #WINDOW_Main)
SetWindowCallback(@MainWindow_CallbackProc(), #WINDOW_Main)
MainWindow_SubclassProc(WindowID(#WINDOW_Main), -1, ('I' << 24) | ('N' << 16) | ('I' << 8) | 'T', 0) ; wParam = 'INIT'
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndProcedure
Procedure main()
Protected state, key
If CreateMainWindow()
AddHotKey(#WINDOW_Main, #Hotkey, #MOD_ALT | #MOD_NOREPEAT, #VK_X)
Output("Press any Key on your keyboard. ")
Repeat ; main loop
Select WaitWindowEvent(250)
Case #WM_HOTKEY
Output("mainloop: My Hotkey ")
Case #WM_KEYDOWN
key = EventwParam() ; virtual-key codes !
Output("mainloop: Key is down key = " + key + ", Name = " + GetKeyNameText(EventlParam()))
Case #PB_Event_None
If KeyPressed(#VK_SHIFT) Or KeyPressed(#VK_CONTROL)
Output("mainloop: Don't hold the SHIFT or CNTRL Keys down") ; <-- this message depends on Timeout in waitwindowevent() !!!
EndIf
Case #PB_Event_CloseWindow
If EventWindow() = #WINDOW_Main : Break : EndIf ; close button on main window --> close application
Case #PB_Event_SizeWindow
Output("mainloop: Size Window New W = " + WindowWidth(#WINDOW_Main) + ", H = " + WindowHeight(#WINDOW_Main))
Case #PB_Event_MinimizeWindow, #PB_Event_MaximizeWindow
Output("mainloop: Minimize or Maximize Window")
Case #PB_Event_Gadget
Select EventGadget()
Case #GADGET_btnClick
Output("mainloop: Click on Button")
EndSelect
EndSelect
ForEver ; main loop
RemoveHotKey(#WINDOW_Main, #Hotkey)
EndIf ; OpenWindow
EndProcedure
End main()
CompilerEndIf ; #PB_Compiler_IsMainFile ;\--- End of Template for Testing