B4J Library [ABMaterial]: MashKeyPress (Capture Keyboard Input e.g. Shift+a)

Discussion in 'B4J Libraries & Classes' started by Mashiane, Aug 21, 2018.

  1. Mashiane

    Mashiane Expert Licensed User

    Hi there

    This is in response to CableGuy's PM for this functionality here. So far the preliminary results are indicating that its working...at page level.

    The original js is here. Download the js files and add the necessary link to this js in BuildPage.

    KeyPress.png

    I must admit this is some nifty piece of work, its very impressive actually.

    Capturing keyboard input with this lib can happen at html page level and within an element. So far Ive managed to get this to work at page level. I will continue the rest later, bushed.

    Step 1: Create the ABMComponent
    Project > Add New Module > Class Module > ABM Custom Component
    Type in the class name in the prompt and continue.

    We want to be able to add the combinations that we will capture and return an event in b4j. To do that we will use b4j_raiseevent. We define a list to store all our combo definitions, call this javacalls.

    We want to trap the shift control key, so we define this as a constant, it will help us to refer back to it later..

    Code:
    Public const MashKeyPressShift As String = "shift"
    This component is not a page element, what we can do is create a hidden div and then add it to R1C1 on our page. This is just fishing anyway.

    Code:
    'build the component, lets just add an empty div that we hide
    Sub ABMComp_Build(InternalPage As ABMPage, internalID As StringAs String
        
    Return $"<div id="${compid}" style="display:none"></div>"$
    End Sub
    We want to be able to trap a couple of combination keys so, rather lets define a simple method to do so.

    Code:
    'add a simple combo like shift+a
    private Sub AddSimple(ctlKey As String, key As String)
        
    Dim strComb As String = $"${ctlKey} ${key}"$
        
    Dim script As String = $"${compid}listener.simple_combo("${strComb}", function() {
        b4j_raiseEvent('${
    compid}_keypress', {'value':'${strComb}'});
        });"$

        JavaCalls.Add(script)
    End Sub
    This we later, define it as a self referencing sub so that we can chain our calls to it.

    Code:
    'add a combination that uses shift
    Sub AddShiftPlus(key As StringAs MashKeyPress
        AddSimple(MashKeyPressShift,key)
        
    Return Me
    End Sub
    Code:
    'add a combination that uses shift
    Sub AddShiftPlus(key As StringAs MashKeyPress
        AddSimple(MashKeyPressShift,key)
        
    Return Me
    End Sub
    So when calling this method, you just specify the key to trap e.g. a. In our connect page for example, we have initialized this as...

    Code:
    mashkpress.Initialize(page,"mashkpress")
        mashkpress.AddShiftPlus(
    "a").AddShiftPlus("b").AddShiftPlus("z")
        
    page.Cell(1,1).AddComponent(mashkpress.ABMComp)
    After having defined mashkpress in Class_Globals as

    Code:
    Public mashkpress As MashKeyPress
    This is defined in Class_Globals because we want to trap the events from it within the scope of the page, remember above, when each combo key press is done, the control must return what was pressed. This is done with..

    Code:
    b4j_raiseEvent('${compid}_keypress', {'value':'${strComb}'});
    so if 'shift a' is pressed, the returned key combination should be ...

    As a demo, we want to show the returned combinations in a label of our page, so a label is defined in class_globals as

    Code:
    Private lblKeyPress As ABMLabel
    In ConnectPage we also add this label.

    Code:
    lblKeyPress.Initialize(page,"lblKeyPress","Key Press Values",ABM.SIZE_PARAGRAPH,False,"")
        
    page.Cell(2,1).AddComponent(lblKeyPress)
    This basically means that when we press shift+a, shift+b and shift+z, these should be trapped and something should be done. To do this, we define the event trapper in the page.

    Code:
    'a keypress has been done
    Sub mashkpress_keypress(value As Map)
        
    'read the keypress done
        Dim kp As String = value.Get("value")
        lblKeyPress.Text = kp
        lblKeyPress.refresh
        
    select case kp
        
    case "shift a"
           
    do this
        
    case "shift b"
          
    do that
        
    case "shift z"
         back 
    to then
        
    end select

    End Sub
    Remember: In BuildPage add

    Code:
    page.AddExtraJavaScriptFile("custom/keypress-2.1.5.min.js")
    Ta!

    Upcoming: Linking keyboard input to an html element.
     

    Attached Files:

    Last edited: Aug 21, 2018
  2. Cableguy

    Cableguy Expert Licensed User

    Mashy, you've done it again!

    I cannot thank you enough!
     
  3. Cableguy

    Cableguy Expert Licensed User

    I know I have asked a LOT from you already, but, what do I need to change in order to trap a 3-key combo, like "Shift+a+z" or "ctrl+shift+a"?

    Btw, regarding the conflict you mentioned in our PM exchange, trigering key combo detection at component level would it not cause the conflict we talked about?
    I will try to setup a proper test page with a Text input field and see if, with the Page level working, the input gets afected or not.
     
    Mashiane likes this.
  4. Cableguy

    Cableguy Expert Licensed User

    Done!

    Just replaced the label declaration by an input filed, initialized it as text area set to false, and, VERY IMPORTANT, deleted the 2 code lines from the mashkpress_keypress sub, so that the input does not get overwriten.

    lblKeyPress.Text = kp
    lblKeyPress.refresh

    This way the page is still listening for the key combos, and the text input works properly, as long as we dont try to enter one of the combos... like "Shift+a" to get a capital A
     
    Mashiane and amaxco like this.
  5. Mashiane

    Mashiane Expert Licensed User

    I will add the count and combination calls later on and upload an update.
     
    Cableguy likes this.
  6. Mashiane

    Mashiane Expert Licensed User

    Due to load shedding been off for a while. This is what we suffer in RSA, electricity shutdowns. Anyway to close this off, a few things.

    1. Added two extra events and two methods to add counters and sequence.
    2. Added some key constants for ease of reference
    3. Changed a few things to make this easier e.g. consistent key names
    4. For ease of use, your key combination can just be passed as an array / list


    5. Combination Sequence: Shift+a+z for example

    This is called a sequence. To add the sequence use
    Code:
    mashkpress.AddSequence(Array As String(mashkpress.KeyShift,"a","z"))
    Please note that the 'simple' will receive priority. For example YOU CANNOT have this sequence crtl+a+c and also have a simple crtl+a, the latter will be trapped and your sequence NOT.

    To trap this use

    Code:
    'a keypress has been done
    Sub mashkpress_sequence(value As Map)
        
    Dim kp As String = value.Get("value")
        lblKeyPress.Text = kp
        lblKeyPress.refresh
    End Sub
    6. Counters: How many times a combination has been pressed. Should you pause, the counters start from 1 again

    Code:
    mashkpress.AddCount(Array As String(mashkpress.KeyShift,mashkpress.KeySpace))
    In this example, we want to know each time a shift+space has been pressed. This returns a JSON string that you can parse to a map to read the values.

    To trap this use

    Code:
    'a count combination
    Sub mashkpress_count(value As Map)
        
    Dim kp As String = value.Get("value")
        
    Log(kp)
        lblKeyPress.Text = kp
        lblKeyPress.refresh
    End Sub
    The returned JSON, will have this structure:
    Code:
    {"sequence":"shift space","count":5}
    7. Defined Keys (check & test these THOROUGHY during development)

    Code:
    Public const KeyShift As String = "shift"
        
    Public const KeyTab As String = "tab"
        
    Public const KeySpace As String = "space"
        
    Public const KeyUp As String = "up"
        
    Public const KeyDown As String = "down"
        
    Public const KeyLeft As String = "left"
        
    Public const KeyRight As String = "right"
        
    Public const KeyEnter As String = "enter"
        
    Public const KeyAlt As String = "alt"
        
    Public const KeyMeta As String = "meta"
        
    Public const KeyOption As String = "option"
        
    Public const KeyCmd As String = "cmd"
        
    Public const KeyCtrl As String = "ctrl"
        
    Public const KeyScroll As String = "scroll"
        
    Public const KeyPause As String = "pause"
        
    Public const KeyCaps As String = "caps"
        
    Public const KeyNum As String = "num"
        
    Public const KeyPrint As String = "print"
        
    Public const KeyF1 As String = "f1"
        
    Public const KeyF2 As String = "f2"
        
    Public const KeyF3 As String = "f3"
        
    Public const KeyF4 As String = "f4"
        
    Public const KeyF5 As String = "f5"
        
    Public const KeyF6 As String = "f6"
        
    Public const KeyF7 As String = "f7"
        
    Public const KeyF8 As String = "f8"
        
    Public const KeyF9 As String = "f9"
        
    Public const KeyF10 As String = "f10"
        
    Public const KeyF11 As String = "f11"
        
    Public const KeyF12 As String = "f12"
        
    Public const KeyBackSpace As String = "backspace"
        
    Public const KeyCaps As String = "caps"
        
    Public const KeyEsc As String = "esc"
        
    Public const KeyPageUp As String = "pageup"
        
    Public const KeyPageDown As String = "pagedown"
        
    Public const KeyEnd As String = "end"
        
    Public const KeyHome As String = "home"
        
    Public const KeyInsert As String = "insert"
        
    Public const KeyDelete As String = "delete"
    8. Updated Examples

    Code:
    mashkpress.Initialize(page,"mashkpress")
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,"a","z"))
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyCtrl, mashkpress.keyshift,"a"))
      
        
    'mashkpress.AddShiftPlus("a").AddShiftPlus("b").AddShiftPlus("z")
        mashkpress.AddCount(Array As String(mashkpress.KeyShift,mashkpress.KeySpace))
      
        mashkpress.AddControlPlus(
    "c").AddControlPlus("v").AddControlPlus("x")
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,mashkpress.KeyUp))
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,mashkpress.KeyDown))
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,mashkpress.KeyLeft))
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,mashkpress.KeyRight))
      
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,"a"))
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,"b"))
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyShift,"c"))
      
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyCtrl,mashkpress.KeyF1))
        mashkpress.AddSequence(
    Array As String(mashkpress.KeyCtrl,mashkpress.KeyDelete))
      
        
    page.Cell(1,1).AddComponent(mashkpress.ABMComp)
    That's all folks!!

    Final Updated ABM Custom Component in Post #1.

    Thanks @Cableguy for this reference, this js has opened my eyes hey..;)
     
    ellpopeb4a, Cableguy, amaxco and 2 others like this.
  7. Cableguy

    Cableguy Expert Licensed User

    This is why I joined this community about 10 years ago...
    I asked for Something, You responded...
    It is I who should Thank YOU, instead you end up thanking me (?)
    B4X Rocks, and this community is just amazing
     
    Mashiane and amaxco like this.
  8. Cableguy

    Cableguy Expert Licensed User

    So, I've been playing around with this great piece of code, and found a few things I'd like to share with you.

    First, a few subs can be deleted as they are not needed and redundant, being them the "AddSimple", "AddShift" and "AddCtrl".
    The "AddSequence can efectively handle all of those.
    Secondly, most of the time I am getting a double-fire, but from time to time, I get a normal single-fire
     
    Last edited: Aug 24, 2018
    Mashiane likes this.
  9. Mashiane

    Mashiane Expert Licensed User

    Great, I was also asking myself the same questions because if I add simple Crt+a and add a sequence Crt+a+c the sequence won’t fire but the simple call would. I didn’t look at the provided js to see what they were doing differently about the calls though they call different methods in their js. As long as you are happy with the result all the better. The heads up is good...
     
    joulongleu likes this.
  10. Cableguy

    Cableguy Expert Licensed User

    So, been playing a bit more...

    Since I will be setting a few Key Seequences for several different pages, I decided to try and integrate the needed code into the Shared Module...

    This is what I've got working:

    After declaring the mashkpress component as public in the Shared module Class Globals I added...
    Code:
    'Register a ComboKey Listener component onto Page.cell(1,1)
    Public Sub RegisterComboKeyListener(Page As ABMPage,ComboKeySetName As String)
     mashkpress.Initialize(
    Page,"mashkpress")
     
    Select ComboKeySetName
      
    Case "KeyCombo1"
       
    Dim KeyCombo(2As List
       KeyCombo(
    0) = Array As String(mashkpress.KeyCtrl, mashkpress.KeyAlt)
       KeyCombo(
    1) = Array As String(mashkpress.KeyCtrl, mashkpress.KeySpace)   
     
    End Select
     
     
    For a = 0 To KeyCombo.Length -1
     mashkpress.AddSequence(KeyCombo(a))
     
    Next
     
    Page.Cell(1,1).AddComponent(mashkpress.ABMComp)
    End Sub
    Of course, the js still has to be referenced in each page that will use it...

    So to create the page listenner, I just call...
    Code:
    ABMShared.RegisterComboKeyListener(AppPage,"KeyCombo1")
    With this approach we only need the event sub in each page, and the call to the Shared module.

    Code:
    Case "KeyCombo1"
       
    Dim KeyCombo(2As List
       KeyCombo(
    0) = Array As String(mashkpress.KeyCtrl, mashkpress.KeyAlt)
       KeyCombo(
    1) = Array As String(mashkpress.KeyCtrl, mashkpress.KeySpace)   
     
    End Select
    With this part, we can create as much KeyCombos as we want, even 1 keyCombo set per page if we want to, so that its easier to maintain.

    Well, these were my two cents for now...
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice