B4J Library [class] KeyComboListener

I noticed that some people were using the jNativeHookB4J library to allow their programs to listen for key combos (ex: control_shift_f). I thought I'd make your lives a little easier and more flexible with the attached class. The KeyComboListener allows you to listen for key combos using the jNativeHookB4J library and is better than the old method (creating Global Booleans to track when certain keys are in the down position) because you can create and watch for new key combos at run-time. This means that your users can create their own key combos without you having to hard-code each one in. Furthermore, this class raises its event sub in the Main Thread, which will be more intuitive.

Example:
B4X:
Sub Process_Globals
    Dim nh As NativeHook
    Dim kcl As KeyComboListener
End Sub

Sub AppStart (Args() As String)
    kcl.Initialize(Me,"kcl", Array("control", "shift", "f")).StartListening
    'You can use "control" to trigger on any ctrl press or "left control" to trigger on the left one, only.
    'Same for "shift", etc...

    kcl.RaiseEvent    'We can programmatically raise the event if we want

    nh.Initialize("nh", Me).startNativeKeyListener    
    'In real code, don't forget to unregister your NativeHook when you're done with it!!!

    StartMessageLoop
End Sub

Sub nh_NativeKeyPressed(nke As NativeKeyEvent) As Boolean
    kcl.KeyPressed(nke)    '  <----You MUST call this inside nh_NativeKeyPressed!!!!!!!
    Return False
End Sub

Sub nh_NativeKeyReleased(nke As NativeKeyEvent) As Boolean
    kcl.KeyReleased(nke)    '  <----You MUST call this inside nh_NativeKeyReleased!!!!!!!
    Return False
End Sub

'This will be executed when we call kcl.RaiseEvent or when the user presses the control_shift_f key combo
Sub kcl_KeyComboPressed
    Log(kcl.GetKeyComboStringRepresentation & " pressed.")
    Log(" ")
End Sub

While you should only create one NativeHook Object per program, you can create as many KeyComboListeners as you like.

As usual, if you make any interesting modifications to the KeyComboListener code, feel free to share them in this thread.
 

Attachments

  • KeyComboListener.bas
    3.2 KB · Views: 354

ThRuST

Well-Known Member
Licensed User
@Roycefer Which keys are supported? I need to make my project compatible on Mac and need to use the Windows key in combination (Command key on Mac) perhaps others. Also, on Windows hotkey triggers an event once (as it should) but on Mac the events keep triggering over and over so for example to cycle a value back and forth with the mouse causes a rapid fire effect. Just wanted to let you know this in case it can be handled inside the library because everything I tried to prevent this on Mac had no effect. I would like to have a list of keys that your excellent library supports. Thanks
 
Last edited:

Roycefer

Well-Known Member
Licensed User
The keys supported by the KeyComboListener are the keys supported by the jNativeHookB4J library. It's a simple matter to try out your keyboard on a jNativeHookB4J sample app to see what is supported and what the key names are.

Please post your code that is causing the cycling problem on Mac and the Logs for that code.
 

ThRuST

Well-Known Member
Licensed User
I have tried to access keybombo with Windows key by using "Win" and "Cmd" without luck. A chellenge is also to find a free hotkey combo for the Macintosh.
On Windows I use Shift Alt 1-8 and that works fine. Two configs for keyboard layout can be changed in settings. I might want to use the Cmd (Windows) key on Mac.
Here's the sub for the cycling between floating menus (Floating menu module by Steve 'Steve05' Laming). He baked in the jNativeHook.
This is my code which works well on PC but causes a rapid trigger effect on my Macbook.

B4X:
' ####################################################################################
'                         FloatingMenu MouseClick Detection
' ####################################################################################

' ########## Mouse_Clicked Event #############

'#### Functionality Moved to NativeHook_Static.Mouse_Clicked, sub will still be called if it exists
'Mouse button 2 has been detected by the native hook
Sub Mouse_Clicked(nme As NativeMouseEvent,Pressed As Boolean)
    Log("Main mouse Pressed " & nme.MouseButton)
    ' nme.X,Y changed to x,y
   
   
    If WhichBank = 1 Then
         If nme.MouseButton = 2 And Pressed Then
            If FMCurrent.IsInitialized Then FMCurrent.Hide
            FMCurrent = FMArr(0)
            NativeHook_Static.SetFloatingMenu(FMCurrent)
            MainForm.Show
            FMCurrent.Show(x,y)
        End If
    End If
   
    If WhichBank = 2 Then
         If nme.MouseButton = 2 And Pressed Then
            If FMCurrent.IsInitialized Then FMCurrent.Hide
            FMCurrent = FMArr(1)
            NativeHook_Static.SetFloatingMenu(FMCurrent)
            MainForm.Show
            FMCurrent.Show(x,y)
        End If
    End If
   
    If WhichBank = 3 Then
         If nme.MouseButton = 2 And Pressed Then
            If FMCurrent.IsInitialized Then FMCurrent.Hide
            FMCurrent = FMArr(2)
            NativeHook_Static.SetFloatingMenu(FMCurrent)
            MainForm.Show
            FMCurrent.Show(x,y)
        End If
    End If
   
    If WhichBank = 4 Then
         If nme.MouseButton = 2 And Pressed Then
            If FMCurrent.IsInitialized Then FMCurrent.Hide
            FMCurrent = FMArr(3)
            NativeHook_Static.SetFloatingMenu(FMCurrent)
            MainForm.Show
            FMCurrent.Show(x,y)
        End If
    End If
   



  
   ' Middle mouse button
    If nme.MouseButton = 3 And Pressed Then

        WhichBank = WhichBank + 1
       
        If WhichBank = 0 Or WhichBank >= 5 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #1 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu1
        End If
       
        If WhichBank = 2 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #2 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu2
        End If
       
        If WhichBank = 3 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #3 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu3
        End If
       
        If WhichBank = 4 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #4 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu4
        End If
       
        If WhichBank >=5 Then
            WhichBank = 1
        End If
       
    End If



    ' Mouse button #4 Count upwards
    If nme.MouseButton = 4 And Pressed Then

        WhichBank = WhichBank + 1
       
        If WhichBank = 0 Or WhichBank >= 5 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #1 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu1
        End If
       
        If WhichBank = 2 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #2 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu2
        End If
       
        If WhichBank = 3 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #3 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu3
        End If
       
        If WhichBank = 4 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #4 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu4
        End If
       
        If WhichBank >=5 Then
            WhichBank = 1
           
        End If
       
    End If
   

    ' Mouse button #5 Count downwards
    If nme.MouseButton = 5 And Pressed Then

        WhichBank = WhichBank - 1
       
        If WhichBank <= 0 Or WhichBank > 4 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #4 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu4
        End If
       
        If WhichBank = 1 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #1 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu1
        End If
       
        If WhichBank = 2 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #2 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu2
        End If
       
        If WhichBank = 3 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #3 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu3
        End If
       
        If WhichBank = 4 Then
            FXnotify.ShowNotification4("Mindcraft", "Menu #4 selected.", NotifyIcon, "CENTER", 2000)
            Speech.Menu4
        End If
       
        If WhichBank <=0 Then
            WhichBank = 4
        End If
           
       
    End If
   

End Sub

I hope my code makes sense. It's part of my Mindcraft project, which is a knowledge manager that installs into the O/S environment (scrollable panel on left sideborder).
Any clues how to access the Window key (Cmd on Mac) and prevent the rapid firing triggering on Mac is highly appreciated. I want to get on with my project.
It's becoming really good after all the contributions from experts in this forum. I will add direct access to the floating menys from mouse buttons, so this is just one of the mouse configurations that will be available so one way or another this will work for Mac users, even though cycling between menus is useful through tests.
But direct access to the floating menus from hotkeys is there as an alternative, just to make workflow streamlined. The nativehook comes in as a saviour, indeed :)
 

ThRuST

Well-Known Member
Licensed User
This example works for Config #1 (Windows)

B4X:
' Hotkey 1
        Main.kcl1.Initialize(Main,"kcl1", Array("shift", "alt", "1")).StartListening
        Main.nh1.Initialize("nh1", Main).startNativeKeyListener
 

ThRuST

Well-Known Member
Licensed User
Somehow Shift and Control together does not seem to be supported. How can I get a list of supported keys to know which combos work in jNativeHook?
 

Roycefer

Well-Known Member
Licensed User
I use control and shift in my KeyComboListener programs and they work fine together (eg control_shift_f). To know which keys are supported and what their proper names are (namely how to identify them with the KeyComboListener), write a short program with jNativeHookB4J and press every key on your keyboard. If you are logging the nh_NativeKeyPressed events, you'll see what is supported and what the NativeHook library calls each key.

If my memory serves me, the Command and Window keys are called Meta. Then your combos in message #6 can be implemented with
B4X:
Main.kcl1.Initialize(Main, "kcl1", Array("control", "meta", "1")).StartListening  'Both Windows and Mac
 

ThRuST

Well-Known Member
Licensed User
Works like a charm so Mac users can feel blessed. Attaching a screendump, thanks @Roycefer

Screendump 2017-06-15 MacBook.jpg
 
Top