October 26, 2020, 01:36:00 AM

Author Topic: [Win] Enable / Disable hotkeys on the fly?  (Read 635 times)

Offline Grisu

  • Jr. Member
  • **
  • Posts: 40
    • Pocket Radio Player
[Win] Enable / Disable hotkeys on the fly?
« on: March 28, 2020, 01:15:00 PM »
Hi everyone,

I'm using the following old code for setting up hotkeys in my app.
It uses a global var "ini_dis_hotkeys" to set the usage of hotkeys at the start of the app,"0" or "1".
In the example óode the key "ALT+X" is registered. But I have more than one to deal with.

Code: [Select]
' Hotkey example code
Import maxgui.drivers

Global ini_dis_hotkeys:Int=0 '<- disable all hotkeys?

?Win32 ' HOTKEY STUFF -------------------------------------------------------------------------------------
Extern "win32"
Function GetLastError:Int ()
End Extern

Const MOD_ALT:Int = $0001
'Const MOD_CONTROL:Int = $0002
'Const MOD_NOREPEAT:Int = $4000
'Const MOD_SHIFT:Int = $0004
'Const MOD_WIN:Int = $0008
'Const VK_LWIN: Int

Global mainwindow:TGadget = CreateWindow ("Hotkey Example Code", 320, 200, 320, 200)

Global OldWindowFunc:Int = SetWindowFunc( MainWindow, WindowFunc)

If ini_dis_hotkeys  = 0 Then

Local RegisterHotkey:Int (hWnd:Int, id:Int, fsModifiers:Int, vk:Int) "win32"
Local user32:Int = LoadLibraryA ("user32.dll")

If user32 Then
RegisterHotkey = GetProcAddress (user32, "RegisterHotKey")
EndIf

' Hotkeylist: http://msdn.microsoft.com/en-us/library/windows/Desktop/dd375731(v=VS.85).aspx
' https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes

Print ""
Print ""
Print ""
Print "Registering ALT+X as Hotkey: "+ RegisterHotkey (QueryGadget (MainWindow , QUERY_HWND) , 1 , MOD_ALT , $58) ' = "X"
Print ""
Print "PRESS ALT+X TO EXIT APP!"
EndIf ' disablehotkeys  = 0
?

' VKEY CODES:
' <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=VS.85).aspx" target="_blank">http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=VS.85).aspx</a>

' MODIFIER CONSTANTS HERE:
' <a href="http://msdn.microsoft.com/en-us/library/windows/Desktop/ms646309(v=VS.85).aspx" target="_blank">http://msdn.microsoft.com/en-us/library/windows/Desktop/ms646309(v=VS.85).aspx</a>

' HOTKEY STUFF --------------------------------------------------------------------------------------------------------

Repeat
Select WaitEvent ()
Case EVENT_WINDOWCLOSE
Exit
End Select
Forever

End ' of world

' HOTKEY FUNCS -----------------------------------------------------------------------------------------
Function WindowFunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int) "Win32"
Local hdr:Int Ptr = Int Ptr(lparam)

Select msg

Case WM_HOTKEY

      If ini_dis_hotkeys=0 Then ' Disable Hotkeys?

        If Int(lparam) = "5767169" Then PostEvent(CreateEvent(EVENT_WINDOWCLOSE, MainWindow))
        Print "ALT + X pressed"

Notify "OK "+lparam ' HANDLE HOTKEY HERE!
  Print Int(lparam)

      EndIf

Case WM_DESTROY
SetWindowLong( hwnd , GWL_WNDPROC , OldWindowFunc)

End Select


Return CallWindowProc( OldWindowFunc, hwnd, msg, wparam, Int(lparam))
EndFunction

' setting window function
Const GWL_WNDPROC:Int = -4

Extern "Win32"
Function SetWindowLong:Int(HWND:Int,nIndex:Int,dwNewLong:Int) = "SetWindowLongA@12"
Function GetWindowLong:Int(HWND:Int,nIndex:Int) = "GetWindowLongA@8"
Function CallWindowProc:Int( prevwndproc:Int, hwnd:Int, msg:Int, wparam:Int, lparam:Int) = "CallWindowProcA@20"
EndExtern

Function SetWindowFunc:Int( window:TGadget, newfunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int))
Local hwnd:Int = QueryGadget( window, QUERY_HWND)
Local oldfunc:Int = GetWindowLong( hwnd, GWL_WNDPROC)
SetWindowLong( hwnd, GWL_WNDPROC, Int(Byte Ptr newfunc))
Return oldfunc
EndFunction
?
'------------------------------------------------------------------------------------------------------

My issue is, that I want to unregister and register the hotkeys during runtime. That means without the need of an app restart.
Currently, I just "set ini_dis_hotkeys" to 1 it will just leave out some code, but the keys themself will be still registered by Windows.

So far I can't move the register commands to an extra function, it won't let me compile.
Also I don't have an unregister function for the keys.

Does anyone have a working code for this?
Or a way to get around this problem?

Cheers
Grisu
Pocket Radio Player     Cardwar

Offline wombats

  • Jr. Member
  • **
  • Posts: 51
Re: [Win] Enable / Disable hotkeys on the fly?
« Reply #1 on: March 28, 2020, 11:34:09 PM »
Can you not use SetHotKeyEvent and RemoveHotKey?

Offline Grisu

  • Jr. Member
  • **
  • Posts: 40
    • Pocket Radio Player
Re: [Win] Enable / Disable hotkeys on the fly?
« Reply #2 on: March 29, 2020, 10:38:41 AM »
Does it also support the "media keys" of a keyboard (volume up/down, Play, Stop, Mute...)? From the magui docs (BRL.KeyCodes), it doesn't look like it.

If so, is there a small example of how to handle/detect the key events properly?
Pocket Radio Player     Cardwar

Offline Henri

  • Sr. Member
  • ****
  • Posts: 263
Re: [Win] Enable / Disable hotkeys on the fly?
« Reply #3 on: March 29, 2020, 02:13:37 PM »
Hi Grisu,

I modified your example a bit to add some hotkey handling functions (see at the bottom):

Code: BlitzMax
  1. Strict
  2.  
  3. ' Hotkey example code
  4. Import maxgui.drivers
  5.  
  6. 'GUI
  7. Global mainwindow:TGadget = CreateWindow ("Hotkey Example Code", 320, 200, 320, 200)
  8. Global OldWindowFunc:Int = SetWindowFunc( MainWindow, WindowFunc)
  9. Global button:TGadget = CreateButton("DisableHotkeys", 95, 50, 100, 40, mainwindow)
  10.  
  11. 'RegisterHotkey on startup
  12. AddHotkey (QueryGadget (MainWindow, QUERY_HWND), 1, MOD_ALT, $58)
  13.  
  14. Print "~n~n~n"
  15. Print "Registering ALT + X as Hotkey:~n"
  16. Print "PRESS ALT + X TO SEE A POPUP!"
  17.  
  18.  
  19. ' HOTKEY STUFF --------------------------------------------------------------------------------------------------------
  20. Repeat
  21.         Select WaitEvent ()
  22.         Case EVENT_WINDOWCLOSE
  23.                 Exit
  24.                
  25.         Case EVENT_GADGETACTION
  26.                 Select EventSource()
  27.                 Case button
  28.                        
  29.                         Print "Button pressed"
  30.                        
  31.                         Select GadgetText(button).ToUpper()
  32.                         Case "DISABLEHOTKEYS"
  33.                                
  34.                                 DebugLog "DisableHotkeys"
  35.                                
  36.                                 SetGadgetText(button, "EnableHotkeys")
  37.                                 DisableHotkeys()       
  38.                         Case "ENABLEHOTKEYS"
  39.                                
  40.                                 DebugLog "EnableHotkeys"
  41.                                
  42.                                 SetGadgetText(button, "DisableHotkeys")
  43.                                 EnableHotkeys()
  44.                         EndSelect
  45.                 EndSelect
  46.         End Select
  47. Forever
  48.  
  49. End ' of world
  50.  
  51. ' HOTKEY FUNCS -----------------------------------------------------------------------------------------
  52.  
  53. ' setting window function
  54. Const GWL_WNDPROC:Int = -4
  55. Const MOD_ALT:Int = $0001
  56.  
  57. Function WindowFunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int) "Win32"
  58.         Local hdr:Int Ptr = Int Ptr(lparam)
  59.  
  60.         Select msg
  61.  
  62.                 Case WM_HOTKEY
  63.                        
  64.                         Local h:THotkey = GetHotKeyFromID(wparam)
  65.                         If h Then
  66.                                 Notify "Hotkey pressed (id = " + h.id + ")! Key = " + h.key + " | modifier = " + h.modifier
  67.                         EndIf
  68.                        
  69.                 Case WM_DESTROY
  70.                         SetWindowLong( hwnd , GWL_WNDPROC , OldWindowFunc)
  71.  
  72.         End Select
  73.  
  74.  
  75.         Return CallWindowProc( OldWindowFunc, hwnd, msg, wparam, Int(lparam))
  76. EndFunction
  77.  
  78. Extern "Win32"
  79.         Function RegisterHotkey:Int (hWnd:Int, id:Int, fsModifiers:Int, vk:Int) = "RegisterHotKey@16"
  80.         Function UnRegisterHotkey:Int (hWnd:Int, id:Int) = "UnregisterHotKey@8"
  81.         Function SetWindowLong:Int(HWND:Int,nIndex:Int,dwNewLong:Int) = "SetWindowLongA@12"
  82.         Function GetWindowLong:Int(HWND:Int,nIndex:Int) = "GetWindowLongA@8"   
  83.         Function CallWindowProc:Int( prevwndproc:Int, hwnd:Int, msg:Int, wparam:Int, lparam:Int) = "CallWindowProcA@20"
  84. EndExtern
  85.  
  86. Function SetWindowFunc:Int( window:TGadget, newfunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int))
  87.         Local hwnd:Int = QueryGadget( window, QUERY_HWND)
  88.         Local oldfunc:Int = GetWindowLong( hwnd, GWL_WNDPROC)
  89.         SetWindowLong( hwnd, GWL_WNDPROC, Int(Byte Ptr newfunc))
  90.         Return oldfunc
  91. EndFunction
  92. ?
  93. '------------------------------------------------------------------------------------------------------
  94.  
  95. 'New stuff
  96. '---------
  97. Type THotkey
  98.        
  99.         Global hotkeys:TList = New TList
  100.        
  101.         Field hwnd:Int
  102.         Field id:Int
  103.         Field key:Int
  104.         Field modifier:Int
  105.        
  106.         Function Create(hwnd:Int, id:Int, modifier:Int, key:Int)
  107.                
  108.                 Local h:THotkey, found:Int
  109.                
  110.                 'Check if already exists and overwrite
  111.                 For h = EachIn hotkeys
  112.                         If h.id = id Then
  113.                                 h.hwnd = hwnd
  114.                                 h.id = id
  115.                                 h.key = key
  116.                                 h.modifier = modifier
  117.                                
  118.                                 found = True; Exit
  119.                         EndIf
  120.                 Next
  121.                
  122.                 If Not found Then
  123.                         h = New THotkey
  124.                         h.hwnd = hwnd
  125.                         h.id = id
  126.                         h.key = key
  127.                         h.modifier = modifier
  128.                        
  129.                         hotkeys.addlast(h)
  130.                 EndIf
  131.                
  132.                 DebugLog "Registering hot key: " + RegisterHotkey(hwnd, id, modifier, key)
  133.         EndFunction
  134.        
  135. EndType
  136.  
  137. Function AddHotkey(hwnd:Int, id:Int, modifier:Int, key:Int)
  138.         THotkey.Create(hwnd, id, modifier, key)
  139. EndFunction
  140.  
  141. Function ClearHotkeys()
  142.         For Local h:THotkey = EachIn THotkey.hotkeys
  143.                 If h.id Then UnRegisterHotkey(h.hwnd, h.id)
  144.         Next
  145.         THotkey.hotkeys.Clear()
  146. EndFunction
  147.  
  148. Function DisableHotkeys()
  149.         For Local h:THotkey = EachIn THotkey.hotkeys
  150.                 If h.id Then UnRegisterHotkey(h.hwnd, h.id)
  151.         Next
  152. EndFunction
  153.  
  154. Function EnableHotkeys()
  155.         For Local h:THotkey = EachIn THotkey.hotkeys
  156.                 If h.id Then RegisterHotkey(h.hwnd, h.id, h.modifier, h.key)
  157.         Next
  158. EndFunction
  159.  
  160. Function GetHotKeyFromID:THotkey(id:Int)
  161.         For Local h:THotkey = EachIn THotkey.hotkeys
  162.                 If h.id = id Then Return h
  163.         Next
  164.        
  165.         Return Null
  166. EndFunction
  167.  


-Henri
- Got 01100011 problems, but the bit ain't 00000001

Offline Grisu

  • Jr. Member
  • **
  • Posts: 40
    • Pocket Radio Player
Re: [Win] Enable / Disable hotkeys on the fly?
« Reply #4 on: March 29, 2020, 08:10:56 PM »
Good evening Henri,

you are a lifesaver in coding terms!  ^-^

I spent the afternoon fiddling around with your code. Somehow, it still didn't detect the hotkeys in my über-long code.
In the end, I moved all AddHotkey() commands to your EnableHotkeys() function.
Not so elegant, but this way, it works fine on my Windows 10 PC.  8)

I have put up a test build, if you want to give it a try. I want to make sure, it didn't break anything else.
Full distro: http://www.mediafire.com/file/shmdcqkkhycm0p4/prp_win32.zip/file
+ fixed exe: http://www.mediafire.com/file/u2y91rbi3eayp8k/prp_nightly.zip/file

Grisu

P.S. Is your e-mail (*.inet.fi) still valid?
Pocket Radio Player     Cardwar

Offline Henri

  • Sr. Member
  • ****
  • Posts: 263
Re: [Win] Enable / Disable hotkeys on the fly?
« Reply #5 on: March 29, 2020, 08:45:49 PM »
Evening -> Night here :-)

Disable hotkeys-option seems to work on the fly at least, so that's progress. I noticed in the example that because events are processed in their own Windowproc function for the main window, that proc function needs to be registered before AddHotkey is called.

Yep, email is still the same.

-Henri
- Got 01100011 problems, but the bit ain't 00000001

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal