Announcement

Collapse
No announcement yet.

KEY statement and predefined function key traps

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • KEY statement and predefined function key traps

    In the late stages of my current project with PB/DOS 3.5, I support eight function keys (F1-F8) using the
    predefined KEY values for function keys. I was intending to add support for an additional eight hot keys
    using the user defined KEY traps 15-22. The new hotkeys were to be Ctrl-F1 to Ctrl-F8, but when I tried to
    add them with the KEY statement, I found that the new hotkey routines were never called - the predefined
    F1-F8 keys seem to take priority. I tried redefining the predefined KEY statements so they wouldn't be called
    if the CTRL key was also pressed, to no avail (the compiler appears to ignore that approach), and I also tried
    moving the order of my KEY statements around to see if the order they were defined in made any difference.
    No difference that I could find. It appears that using the predefined function key traps trumps user defined
    function key traps using the same keys.

    I'm trying to decide my next step here. Because I have 16 keys to trap and only ten user definable key traps,
    I can't just define them all as user definable keys. I could throw away the traps and trap the keys myself
    with INKEY$, but I have polling events that might keep an INKEY$ statement from being executed for several
    seconds, which would be an irritation my user base. Changing the hot keys would also irritate the users, as
    they are already used to using these keys from earlier applications. I could write a keyboard interrupt handler
    to take care of all this, but that would require a larger investment of time than I have available.

    I couldn't find anything about this contention in the manuals or through a forum search.

    I'm hoping somebody here has a workaround, but even a few "nope, sorry, you're toast" comments from users
    more experienced with key traps than I am would at least let me know that I've exhausted this approach and it's
    time to move on.

    Thanks in Advance,
    Jerry


    ------------------

  • #2
    Okay, this will be lenghy, even for me:

    First, what PB/DOS 3.5 has to say about KEY:
    ============================================================================
    KEY statement
    ____________________________________________________________________________
    Purpose: Sets and displays function key definitions, defines key trap
    values, and turns trapping on or off for a specific key.

    Syntax: KEY {ON|OFF|LIST}
    KEY n, string expression
    KEY n, CHR$(shiftstatus, scancode [,any])
    KEY (n) ON|OFF|STOP

    KEY ON and KEY OFF turn on and off the function key display at the bottom
    of the screen. KEY LIST displays a list of function key definitions on
    the screen, one per line.
    ____________________________________________________________________________

    KEY n, string expression assigns string expression to function key n.
    ____________________________________________________________________________
    KEY n, CHR$(shiftstatus, scancode [,any]) associates a key or a
    combination of keys with a number from 15 to 25 for key trapping
    with subsequent ON KEY and KEY (n) ON statements.

    shiftstatus is an integer expression that controls the response of the
    trap to the state of the Ctrl, Caps Lock, ALT, and both Shift keys.
    See the POPUP statement for a discussion of shift values.

    scancode is a numeric value from 1 to 83 that defines the key to
    trap, according to the scancode table.

    bits that are set in any will be ignored in the shift parameter. For ?
    example, if you don't care if numlock is on, set that bit in any. ?

    KEY (n) ON|OFF|STOP turns trapping on or off for a specific key:

    n = 1..10 : traps function key F1..F10
    n = 11..14 : traps up arrow, left arrow, right arrow, down arrow
    n = 15..25 : traps key defined by the KEY statement
    n = 30..31 : traps function key F11..F12

    KEY (n) ON turns on trapping of key n. Before the execution of every
    statement, a check is made to see if key n has been pressed; if it has,
    program execution is diverted to the routine specified in an ON KEY
    statement for that key. KEY (n) OFF disables trapping of key n. KEY (n)
    STOP also disables key trapping but remembers whether KEY (n) is pressed
    in the meantime; if a KEY (n) ON statement is subsequently executed, a
    trap occurs immediately.

    So, from reading the above, you can see that KEY(n) ON|OFF|STOP
    will trap for a function key if n = 1 to 10, 30, or 31, but it
    does not check for shiftstate (Ctrl, Alt, or shift key) in
    conjunction with a function key.

    To check for shiftstate, you have to use this version of Key:

    KEY n, CHR$(shiftstatus, scancode [,any]) associates a key or a
    combination of keys with a number from 15 to 25 for key trapping
    with subsequent ON KEY and KEY (n) ON statements.

    shiftstatus is an integer expression that controls the response of the
    trap to the state of the Ctrl, Caps Lock, ALT, and both Shift keys.
    See the POPUP statement for a discussion of shift values.

    scancode is a numeric value from 1 to 83 that defines the key to
    trap, according to the scancode table.
    ========================================================================
    Now the section in the Popup Statement that is of interest is:
    ========================================================================
    This specifies the key combinations to popup with. 'shift' is built
    from bits shown in the table. 'scancode' specifies the key to operate.
    (see scancode table). 'ignore' is built from bits shown in the table
    and shows which simultaneous shifts you don't want considered.

    modifier key binary hex dec
    ─────────────────────────&#947 2;────────────
    Shift 0000 0011 03 3
    Ctrl 0000 0100 04 4
    Alt 0000 1000 08 8
    Scroll Lock 0001 0000 10 16
    Num Lock 0010 0000 20 32
    Caps Lock 0100 0000 40 64
    Insert Status 1000 0000 80 128
    %Shift = 3 : %Ctrl = 4 : %Alt = 8
    %ScrollLock = 16 : %NumLock = 32 : %CapsLock = 64 : %InsertStat = 128
    %Ignore = %InsertStat+%ScrollLock+%NumLock+%CapsLock+%Shift+%Ctrl
    ============================================================================
    And now for the ScanCode Table:
    ============================================================================
    Scancode Chart

    key scan code unshifted +shift +control +alt
    ------------------------------------------------------
    Esc 1 27 27 27 *
    1 ! 2 49 33 * 120
    2 @ 3 50 64 3 121
    3 # 4 51 35 * 122
    4 $ 5 52 36 * 123
    5 % 6 53 37 * 124
    6 ^ 7 54 94 30 125
    7 & 8 55 38 * 126
    8 * 9 56 42 * 127
    9 ( 10 57 40 * 128
    0 ) 11 48 41 * 129
    -_ 12 45 95 31 130
    =+ 13 61 43 * 131
    Backspace 14 8 8 127 *
    Tab 15 9 15 * *
    Q 16 113 81 17 16
    W 17 119 87 23 17
    E 18 101 69 5 18
    R 19 114 82 18 19
    T 20 116 84 20 20
    Y 21 121 89 25 21
    U 22 117 85 21 22
    I 23 105 73 9 23
    O 24 111 79 15 24
    P 25 112 80 16 25
    [{ 26 91 123 27 *
    ]} 27 93 125 29 *
    Enter 28 13 13 10 *
    Ctrl 29 * * * *
    A 30 97 65 1 30
    S 31 115 83 19 31
    D 32 100 68 4 32
    F 33 102 70 6 33
    G 34 103 71 7 34
    H 35 104 72 8 35
    J 36 106 74 10 36
    K 37 107 75 11 37
    L 38 108 76 12 38
    ;: 39 59 58 * *
    '" 40 39 34 * *
    `~ 41 96 126 * *
    Left shft 42 * * * *
    \| 43 92 124 28 *
    Z 44 122 90 26 44
    Numpad 5 76 53 * * *
    Right Arw 77 77 54 116 *
    Gray + 78 43 43 * *
    End 79 79 49 117 *
    Down Arw 80 80 50 * *
    Page Down 81 81 51 118 *
    Insert 82 82 48 * *
    Delete 83 83 46 * *
    F11 217 133 135 137 139
    F12 218 134 136 138 140
    X 45 120 88 24 45
    C 46 99 67 3 46
    V 47 118 86 22 47
    B 48 98 66 2 48
    N 49 110 78 14 49
    M 50 109 77 13 50
    ,< 51 44 60 * *
    .> 52 46 62 * *
    /? 53 47 63 * *
    Rght shft 54 * * * *
    PrtSc 55 42 ** 16 *
    Alt 56 * * * *
    Spacebar 57 32 32 32 32
    Caps lock 58 * * * *
    F1 59 59 84 94 104
    F2 60 60 85 95 105
    F3 61 61 86 96 106
    F4 62 62 87 97 107
    F5 63 63 88 98 108
    F6 64 64 89 99 109
    F7 65 65 90 100 110
    F8 66 66 91 101 111
    F9 67 67 92 102 112
    F10 68 68 93 103 113
    Num Lock 69 * * * *
    Scroll Lk 70 * * * *
    Home 71 71 55 119 *
    Up Arrow 72 72 56 * *
    Page up 73 73 57 132 *
    Gray - 74 45 45 * *
    Left Arw 75 75 52 115 *
    ==================================================================
    So to include the use of function keys with the shift/ctrl/alt
    keys, you probably need to forego the use of the KEY(n) form
    that triggers on just the F1-F10, F11, and F12 keys, and rely on
    just the form that includes shiftkeys. Note that PB/DOS really
    is limited to just the original 83 keyboard layout - it can work
    with the newer keyboards that may have 104 to 112 keys, but it
    is not designed to recognize any added scancodes, though it will
    of course respond to macrokey assignments.

    Now let me briefly explain an alternate approach that can work
    just as well. Because the computer is so fast, hundreds of
    thousands of statements can be exercised in the time it takes to
    make a keyboard entry. So what is the computer suppose to be
    doing in the meantime while you make up your mind which key to
    hit? Likely, it will be whiling away the time in a DO or WHILE
    loop.

    If you stick another DO look inside that one, you can monitor for
    a keypress on the keyboard with the INSTAT function, just idling
    along until a keypress says there is new work to do.

    Something like this:
    Code:
    DO
      DO UNTIL INSTAT
        'do whatever between keyboard inputs
      LOOP
      'you get here when a key has been pressed
    LOOP
    Now I am going to reveal a simple piece of code that reveals
    exactly what combo of valid keys has been pressed. I did not
    invent this code, but I did refine it a bit:
    Code:
    DO
      DO UNTIL INSTAT
      LOOP
      ky$ = INKEY$
      kp$ = CHR$(ASC(RIGHT$(ky$,1))+(127 AND LEN(ky$)=2) AND 255)
      SELECT CASE kp$
      CASE " " TO "z"    'normal text, punctuation, or digit key
      CASE CHR$(198)     'Home key on keypad pressed
      CASE CHR$(199)     'Cursor Up key on keypad pressed
      CASE CHR$(200)     'Page Up key on keypad pressed
      CASE CHR$(202)     'Cursor Left key on keypad pressed
      CASE CHR$(203)     'the 5 key on the keypad pressed
      CASE CHR$(204)     'Cursor Right key on keypad pressed
      CASE CHR$(206)     'End key on keypad pressed
      CASE CHR$(207)     'Cursor Down key on keypad pressed
      CASE CHR$(208)     'Page Down key on keypad pressed
      'other case statements can be inserted here
      CASE CHR$(27)       'Esc key pressed
      CASE CHR$(3)        '"C" with Ctrl key pressed          
      END SELECT
    LOOP
    The reason this works is because the INKEY$ function returns
    nothing if no key is pressed, one character if a single valid
    key is pressed, except for the keypad which acts as an extended
    code if the num lock is set so that the digits are suppressed.

    Unfortunately, the Alt key acts to prevent INKEY$ from getting
    a key code in some cases, and in others, say when used with the
    Ctrl key, does nothing to change the character code further. So
    there are key codes or combinations that are not available with
    this technique. But I have found it to be very user friendly
    and prefer to employ it rather then use a KEY statement.

    ------------------
    Old Navy Chief, Systems Engineer, Systems Analyst, now semi-retired

    Comment


    • #3
      Thanks, Donald. Unfortunately, my program is monitoring, logging and making
      realtime adjustments based on input from > 200 sensors, some on timescales
      of milliseconds, so there's no one place to put such a loop. I could put in
      dozens of polling loops, or calls to a single loop watching for keystrokes,
      but the program is just about finished and I hate to make big changes this late,
      especially in the realm of keystrokes where it is so difficult to test for every
      possible timing interaction (reliability is a huge, #1 priority on this project).

      At this point, I'm leaning toward changing the hot keys and declaring it to be an
      "improvement" over the hot keys they're used to. If they won't swallow that, I'll
      just tell them how long it will take to implement an interrupt driven keyboard
      interceptor, and see if they'll go for it.

      Thanks again,
      Jerry

      ------------------

      Comment


      • #4
        You may be able to incorporate int16 subfunction 2. I posted
        this earlier but can't find the link.
        Code:
        function keyboardstat$
            reg 1, 2
            call interrupt &h16
            t$ = bin$(reg(1))
            do until len(t$) > 8
            t$ = "0" + t$
            loop
            function = right$(t$,8)
            end function
        This will return the status of Shift, Ctrl, Alt, Scroll, Num Lock
        Caps Lock and Insert.



        ------------------
        There are no atheists in a fox hole or the morning of a math test.
        If my flag offends you, I'll help you pack.

        Comment


        • #5
          Jerry, Don

          Since the program is doing fast IO, the custom key checker will not (in my opinion) work.

          Some months ago, I tried something very similar and discovered that both instat and inkey$ can take up to 55 msec to function.

          My guess is that both instat and inkey$ wait for data to be updated by the 18-Hz system interrupt.

          This is no problem for most programs, but in this case it's fatal.

          Jim

          ------------------

          Comment


          • #6
            Well, that's disturbing! I'll have to check that out. Thanks for the heads-up, Jim


            ------------------

            Comment


            • #7
              I wonder if that behaviour would be any different running on a single-task DOS machine versus a Windows-whatever multitasking environment, or Linux using DOSEMU (also multitasking, of course.)

              ------------------
              PB/DOS 3.5 on Fedora Linux

              Comment


              • #8
                Maybe you can set up an interrupt handler in your program and pick off the keystrokes there.

                I have not done this in about ten years, but I know I worked from a PB/DOS example provided by someone (Erik Olson?) which did this.




                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  jerry -

                  i posted on this subject. for details see
                  http://www.powerbasic.com/support/pb...ead.php?t=1316

                  regards

                  jim

                  ------------------

                  Comment


                  • #10
                    Unfortunately, I don't have an answer for you, but I do have some
                    thoughts to share.

                    First, there are two underlying methods of soliciting event data,
                    and both are used in PC design: One is Hardware Interrupts, and
                    the other is Polling device registers for specific flags. In
                    theory, Interrupts should respond faster, since they are triggered
                    by the device, and the system should respond to them very quickly.
                    Interrupts also save on overhead time, because you can simply wait
                    until one occurs after enabling the PC to accept them. With
                    polling, you are engaged in a cyclic process where you have to
                    keep checking to see if something has happened, and decide just
                    how often you do this. Some devices, such as keyboards, are
                    generally regarded as slow input, and for most people, scanning
                    for a keypress about 18 times a second might be fast enough.

                    The difference should be apparent when you think about trying to
                    wake up in the morning. If your alarm, which is like an interrupt,
                    works as it should, you can simply set it and snooze until it
                    goes off. If you don't have an alarm, you have to keep rousing
                    yourself up to check the clock until it is time to get up.

                    There has been work done for changing the period used for polling
                    devices. This is frequently used in game programming, to improve
                    the response time for keyboards and game controllers. The idea
                    is that you make the system clock run faster, so that some polling
                    takes place more frequently, but you slow it down elsewhere, so
                    that other services are not affected.

                    I did some reading on this subject long ago, and it was a
                    technique used both with DOS and with Windows. I imagine you
                    can look for code that will do this elsewhere on the Internet,
                    and that might give you one answer.

                    You can also consider another program that runs in tandum with
                    your main program, which monitors for key presses. If it finds
                    something to act on, it might possibly take some action that the
                    main program can immediately detect and act on.

                    With windows, one of the problems that a DOS programmer will
                    have to face sometimes is that overall, the system as a whole is
                    less responsive because there is so much more that the system is
                    trying to do. Faster PCs has given us back reasonable performance,
                    but how often do you signal the PC that you want to load and run
                    another application, and have to wait several seconds for it to
                    respond? It's not always an ongoing problem, but it can happen
                    even for very fast PCs.

                    ------------------
                    Old Navy Chief, Systems Engineer, Systems Analyst, now semi-retired

                    Comment


                    • #11
                      I've always found that some thing like this works well:
                      -
                      Group your interrupts to use up something in the order of 50-53ms
                      duration for each group.

                      Code:
                      Igroup=0
                      Igroupmax=(maximum number of Interrupt groups)  
                      DO
                         IF INSTAT 
                            call keyhandler
                         ELSE
                            Igroup=(Igroup+1) MOD Igroupmax  
                            call interruptgrouphandler(Igroup)
                         END IF
                      LOOP
                      ------------------
                      Dave

                      Avalon - Somewhere on the Australian coast
                      Dave.

                      You're never too old to learn something stupid.

                      Comment


                      • #12
                        No guarantee that this'll work in your application but it's worth a try:

                        Trap the F1 key and immediately in the F1 trap routine test to see if the CTL key is also pressed.
                        Code:
                        'test key trapping to see if f1 and ctr-F1 can be distinguisheed
                         
                        cls
                         
                        key(1) on
                        on key(1) gosub f1
                         
                        t!=timer
                        do
                        'print ".";
                        loop until (timer-t!) > 10
                         
                        print "Time up"
                        end
                         
                         
                        f1:
                        status%=0
                        ctl_key_pressed%=4
                         
                        !push ds
                        !mov ah,2           ;function 2 of..
                        !int &h16           ;..BIOS interupt 16h tests the shift/ctl/alt key status
                        !mov status%,al
                        !pop ds
                         
                        if (status% and ctl_key_pressed%) then
                        	gosub ctlf1
                        else
                        	print "F1"
                        end if
                        
                        re turn
                         
                         
                        ctlf1:
                        print "ctl-f1"
                        return
                        ------------------

                        Comment


                        • #13

                          An example for setting up your own keyboard int trap from
                          within your own PBDOS program is in the download area under
                          pbdos/games/pbgameky.zip or just follow this link.
                          http://www.powerbasic.com/files/pub/...s/pbgameky.zip

                          this zip contains two examples, one in asm, and one in PBDOS.
                          It's definately worth taking a look at. I never thought it could
                          be that simple.

                          Buck

                          ------------------

                          Comment

                          Working...
                          X