;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/

     Page  58,132
     Title   KBDSTICK - Kbd Device Driver AIM Sticky Key Processor
     Name    KBDSTICK

;/*************************************************************************
;*
;* SOURCE FILE NAME = KBDSTICK.ASM
;*
;* DESCRIPTIVE NAME = PKBD AIM Sticky Key Scan Code Processor
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/17/90
;*
;* DESCRIPTION  AIM Sticky Key Processing is done here
;*
;* FUNCTIONS StickyKeyProc() Interrupt Time Sticky Key Scan Code Procedure
;*           StickyShftCnt() Count the number of consecutive shift keys for AIM
;*           UpdStickyTbl()  Update the table of currently defined modifier keys
;*
;* NOTES        DEPENDENCIES:  Controller or keyboard must be set to the PC compati-
;*                             ble scan code set.
;*              RESTRICTIONS:  Machine must be a 386 or compatible with a 386.
;*
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*
;*
;*
;*
;**************************************************************************/



.286p
.sall
.xcref
.xlist
  Include     mvdm.inc
  Include     osmaca.inc    
  CPUMODE     286           ;* Macro file for OS/2 Kernel
  Include     struc.inc     ;* Structured assembly macros.
  Include     devhlp.inc    ;* DevHlp & Signal equates, char queue structure.
  Include     devsym.inc    ;* Device driver header definitions.
  Include     kbdseg.inc    ;* Segment definitions.
  Include     kbdddr.inc    ;* Keyboard Device Driver structures & equates.
  Include     kbdaim.inc    ;* AIM  Keyboard Device Driver AIM structures/equates.
.list

;*
;** External  Routines
;*

  EXTRNFAR   ProcessScanCode
  Extrn      QueryMouse           :Far
  EXTRNFAR   TypaControl_Reset

;*
;** External Variables
;*

  Extrn AIMFlags             :Word
  Extrn StickyTbl            :Byte
  Extrn LastScan             :Byte
  Extrn StuckScan            :Byte
  Extrn StickMakes           :Word
  Extrn StickBreaks          :Word
  Extrn CtrlMakes            :Word
  Extrn CtrlBreaks           :Word
  Extrn IntFlagArea          :Word
  Extrn AIMFlags             :Word
  Extrn KeyPacket1           :Word
  Extrn MSEStickyStatus      :Word
  Extrn DeviceHelp           :DWord


AIMCode Segment  ;/***/

Assume  CS:AIMCode,DS:DGROUP,ES:Nothing

public Start_AIMCode
Start_AIMCode label   byte

Public StickyKeyProc
StickyKeyProc Proc Far

;**************************************************************************
;*
;* FUNCTION NAME : StickyKeyProc
;*
;* DESCRIPTION   : Interrupt Time Sticky Key Scan Code Procedure
;*
;*           Scan codes are checked to see if they affect the AIM (Alternate
;*           Input Method) Sticky Key Input Mode.
;*
;* NOTES         : This Routine is only called when AIM processing
;*                 for Sticky Keys is active.
;*
;*
;* INPUT         : AL scan code
;*                 DS is the PKBD Data Sel
;*
;* EXIT-NORMAL   :
;*
;*         - Scan code is sent back to the ProcessScanCode Rtn for
;*           further processing.
;*
;* EXIT-ERROR    : None.
;*
;* EFFECTS       : Sticky key modifiers (Keys that seem to be stuck down)
;*                 may be un/defined.
;*
;* INTERNAL CALLS: UpdStickyTbl
;*                 StickyShftCnt
;* External Calls:
;*   Routines    :  None
;*   DevHelps    :  None
;*
;*************************************************************************
;*
;* BEGIN PSEUDOCODE
;*
;*  At this point the scan code is in AL and our Sticky Keys State
;*  Machine is driven off of the AIMflags.
;*
;*  If <The AIMflags indicate to consume the next break scan> AND
;*  If <The current scan code is equal to the one we saved>
;*       Turn off the AIMflag saying EatNextBreak.
;*       Turn on the AIMflag that tells the ProcessScanCode
;*         rtn to consume this break scan code.
;*       Re-Initialize the saved scan code to zero.
;*  ElseIf <AIMFlags do not indicate to stick the next key>
;*       Call StickyShiftKeyCount (StickyShftCnt)
;*       If <This is a break scan code>
;*               Turn on AIMflag indicating to remove a Sticky Key
;*                 scan from the Sticky Key Table.
;*               Call UpdStickyTbl to check if this scan code needs
;*                 to be removed.
;*       Endif
;*  Else
;*       Or on the Break Bit
;*       Save this scan code.
;*       Call UpdStickyTbl to add this break scan code.
;*       Turn off AIMFlag indicating to Stick the Next scan code.
;*       Turn on AIMflag indicateing to Eat the Next Break.
;*  Endif
;*  Save the this scan code in our DS for multi-make checking.
;*  Return
;*
;* END PSEUDOCODE
;*
;*************************************************************************

                                                                ;* AIM

  .If <bit AIMFlags nz EatNextBreak> AND                        ;* AIM
  .If <AL eq StuckScan>                                         ;* AIM
                                                                ;* AIM
        And  AIMFlags, NOT EatNextBreak                         ;* AIM
        And  IntFlagArea.XKeyFlags, NOT SecPrefix               ;* AIM
        Or   AIMFlags, ConsumeScan                              ;* AIM
                                                                ;* AIM
        Mov  StuckScan, 0                                       ;* AIM
                                                                ;* AIM
  .ElseIf <bit AIMFlags z StickNextScan>                        ;* AIM
                                                                ;* AIM
        Call  StickyShftCnt                                     ;* AIM
        Push  AX                                                ;* AIM
        Mov   AH,AL                                             ;* AIM
        Or    AH,AH                                             ;* AIM
       .If <s>                                                  ;* AIM
             Or   AIMFlags, DelStickyKey                        ;* AIM
             Call UpdStickyTbl                                  ;* AIM
       .Endif                                                   ;* AIM
        Pop   AX                                                ;* AIM
  .Else                                                         ;* AIM
                                                                ;* AIM
        Push  AX                                                ;* AIM
        Or    AL, BreakBit                                      ;* AIM
        Mov   StuckScan, AL                                     ;* AIM
                                                                ;* AIM
        And   AIMFlags, NOT StickNextScan                       ;* AIM
        Or    AIMFlags, EatNextBreak                            ;* AIM
        Or    AIMFlags, AddStickyKey                            ;* AIM
        Call  UpdStickyTbl                                      ;* AIM
                                                                ;* AIM
        Pop   AX                                                ;* AIM
                                                                ;* AIM
  .Endif                                                        ;* AIM
                                                                ;* AIM
   Mov LastScan, AL                                             ;* AIM
                                                                ;* AIM
   Ret                                                          ;* AIM
                                                                ;* AIM
StickyKeyProc Endp                                              ;* AIM


Public StickyShftCnt
StickyShftCnt Proc

;***************************************************************************
;*
;* FUNCTION NAME : StickyShftCnt
;*
;* DESCRIPTION   : Count the number of consecutive shift keys for AIM
;*
;*                 Increments and resets the count of shift keys that enable modifier
;*                 keys and disable the sticky and filter keys functions for AIM.
;*
;* Input         : AL scan code
;*
;* Exit-normal   :
;*
;*                 - The count of Shift keys that affect the AIMs are
;*                    updated
;*                 - AIMFlags are set to indicate appropriate action for
;*                    calling rtn.
;*
;* Exit-error    : None
;*
;* Effects       : AIMFlags and count of shift keys are updated.
;*
;* Internal Calls:
;*                 UpdStickyTbl
;*                 QueryMouse
;*                 TypaControl_Reset
;*
;*
;***************************************************************************
;*
;* BEGIN PSEUDOCODE
;*
;*  And off the Breakbit in the scan code.
;*  If <the scan code is a Right Shift> OR
;*  If <the scan code is a Left Shift>
;*          Re-Init number of Ctrl makes we have seen in a row to 0.
;*          Re-Init number of Ctrl breaks we have seen in a row to 0.
;*          If <BreakBit>
;*             If <This is not a multimake>
;*                 Increment the number of ShiftKey makes seen
;*                 If <The number of StickMakes is equal to 1>
;*                   Call the QueryMouse Rtn to reset the timeframe in
;*                    which we will check for button usage.
;*                   Re-Init the Mouse Sticky Status word to 0.
;*             Endif
;*          Else
;*             If <The number of StickMakes is greater than 0>
;*                 Increment the number of ShiftKey breaks seen
;*             Endif
;*          Endif
;*          If <The number of Shift makes in a row is equal to 3 > AND
;*          If <The number of Shift breaks in a row is equal to 3 >
;*              Call the QueryMouse Rtn to check for button usage
;*              And off the pure motion bit of the Mouse Sticky Status word
;*              If <There has been no button usage during the three shifts
;*                   before defining a Modifier key>
;*                       Turn on AIMflag indicating to stick next key
;*              Endif
;*              Re-Initialize the number of ShiftKey makes to 0.
;*              Re-Initialize the number of ShiftKey breaks to 0.
;*          Endif
;*  Else
;*     If <the current scan is for a Ctrl key>
;*          Re-Initialize the number of ShiftKey makes to 0
;*          Re-Initialize the number of ShiftKey breaks to 0
;*          If <BreakBit>
;*             If <This is not a multimake>
;*                 Increment the number of Ctrl makes
;*             Endif
;*          Else
;*             If <The number of Ctrl makes gt 0>
;*                 Increment the number of Ctrl breaks
;*             Endif
;*          Endif
;*          If <The number of Ctrl makes seen in a row is eq 3> AND
;*          If <The number of Ctrl breaks seen in a row is eq 3>
;*              Call UpdStickyTbl to UnStick all the currently defined
;*                Modifier keys.
;*          Else
;*              If <The number of Ctrl makes seen in a row eq 5> AND
;*              If <The number of Ctrl breaks seen in a row eq 5>
;*                   Call TypaControl_Reset routine to Reset (Turn off)
;*                    Filter Keys.
;*                   Re-Initialize the number of Ctrl key makes to 0
;*                   Re-Initialize the number of Ctrl key breaks to 0
;*              Endif
;*          Endif
;*     Else
;*          Re-Initialize the number of ShiftKey makes to 0
;*          Re-Initialize the number of ShiftKey breaks to 0
;*          Re-Initialize the number of Ctrl key makes to 0
;*          Re-Initialize the number of Ctrl key breaks to 0
;*          Turn OFF AIMFlags for Sticking the next scan, Reseting Sticky
;*            keys and Reseting Filer keys.
;*     Endif
;*  Endif
;*
;*  Return
;*
;* END PSEUDOCODE
;*
;***************************************************************************

   Push    AX                                               ;* AIM
   And     AL, NOT BreakBit                                 ;* AIM
  .If <AL eq R_Shift> OR                                    ;* AIM
  .If <AL eq L_Shift> NEAR                                  ;* AIM
                                                            ;* AIM
           Pop   AX                                         ;* AIM
           Mov   CtrlMakes, 0                               ;* AIM
           Mov   CtrlBreaks, 0                              ;* AIM
                                                            ;* AIM
          .If <bit AL z BreakBit>                           ;* AIM
             .If <AL ne LastScan>                           ;* AIM
                  Inc StickMakes                            ;* AIM
                 .If <StickMakes eq 1>                      ;* AIM
                      Mov  CX, StickyQuery                  ;* AIM
                      Call QueryMouse                       ;* AIM
                      Mov  MSEStickyStatus, 0               ;* AIM
                 .Endif                                     ;* AIM
             .Endif                                         ;* AIM
          .Else                                             ;* AIM
              .If <StickMakes gt 0>                         ;* AIM
                  Inc StickBreaks                           ;* AIM
              .Endif                                        ;* AIM
          .Endif                                            ;* AIM
                                                            ;* AIM
          .If <StickMakes eq NumForModifer> AND             ;* AIM
          .If <StickBreaks eq NumForModifer>                ;* AIM
               Mov   CX, StickyQuery                        ;* AIM
               Call  QueryMouse                             ;* AIM
               And   MSEStickyStatus, MouseButton           ;* AIM
              .If <MSEStickyStatus eq 0>                    ;* AIM
                   Or AIMFlags, StickNextScan               ;* AIM
              .Endif                                        ;* AIM
               Mov StickMakes, 0                            ;* AIM
               Mov StickBreaks, 0                           ;* AIM
          .Endif                                            ;* AIM
                                                            ;* AIM
  .Else NEAR                                                ;* AIM
       .If <AL eq CTRL_MK>                                  ;* AIM
                                                            ;* AIM
           Pop AX                                           ;* AIM
           Mov StickMakes, 0                                ;* AIM
           Mov StickBreaks, 0                               ;* AIM
                                                            ;* AIM
          .If <bit AL z BreakBit>                           ;* AIM
             .If <AL ne LastScan>                           ;* AIM
                  Inc CtrlMakes                             ;* AIM
             .Endif                                         ;* AIM
          .Else                                             ;* AIM
              .If <CtrlMakes gt 0>                          ;* AIM
                   Inc CtrlBreaks                           ;* AIM
              .Endif                                        ;* AIM
          .Endif                                            ;* AIM
                                                            ;* AIM
          .If <CtrlMakes eq NumForUnStick> AND              ;* AIM
          .If <CtrlBreaks eq NumForUnStick>                 ;* AIM
                                                            ;* AIM
               Or AIMFlags, UnStickAll                      ;* AIM
               Call UpdStickyTbl                            ;* AIM
                                                            ;* AIM
          .Else                                             ;* AIM
             .If <CtrlMakes eq NumForReset> AND             ;* AIM
             .If <CtrlBreaks eq NumForReset>                ;* AIM
                                                            ;* AIM
                  CALLFAR TypaControl_Reset                 ;* AIM
                  Mov CtrlMakes, 0                          ;* AIM
                  Mov CtrlBreaks, 0                         ;* AIM
             .Endif                                         ;* AIM
          .Endif                                            ;* AIM
                                                            ;* AIM
       .Else                                                ;* AIM
                                                            ;* AIM
           Pop AX                                           ;* AIM
           Mov StickMakes, 0                                ;* AIM
           Mov StickBreaks, 0                               ;* AIM
           Mov CtrlMakes, 0                                 ;* AIM
           Mov CtrlBreaks, 0                                ;* AIM
           And AIMFlags, NOT StickNextScan+UnStickAll       ;* AIM
                                                            ;* AIM
       .Endif                                               ;* AIM
  .Endif                                                    ;* AIM
   Ret                                                      ;* AIM

StickyShftCnt Endp

Public UpdStickyTbl
Procedure UpdStickyTbl, HYBRID

;**************************************************************************
;*
;* FUNCTION NAME  : UpdStickyTbl
;*
;* DESCRIPTION    : Update the table of currently defined modifier keys
;*
;*       Records are either added to or deleted from the sticky key table
;*
;* NOTES          :
;*       Currently the table can hold up to (5) Modifiers keys.  The table may
;*       be cleared of all defined modifier keys if the user hits either Ctrl
;*       key three times in a row without hitting other keys.  Individual
;*       entries in the table may be cleared by simply pressing the key defined
;*       as a modifier.
;*
;*
;* INPUT          : AL scan code
;*                  AIMFlags for Adding or Deleting sticky keys are set
;*
;* EXIT-NORMAL    :
;*                  - Table updated with addition of a scan code entry
;*                     High Pitch Beep sounded
;*                  - Table updated with deletion of a scan code entry
;*                     Middle Pitch Beep sounded
;*                        OR
;*                  - Low Beep sounded on attempt to add scan codes when table
;*                      is full.
;*
;* EXIT-ERROR     : None
;*
;* Effects        : Sticky keys table is updated.
;*
;*
;**************************************************************************
;*
;* BEGIN PCODE
;*
;*  If <the AIMFlags indicate to Add a scan code to the StickyKeyTbl>
;*     Turn off the bit indicating to add to the table.
;*     While <we have not searched through the entire table>
;*        If <the current table entry is Empty>
;*             Move the scan code in AL into the table.
;*             If <the translation flag area indicates that previous
;*                 scan code seen was an extended scan code>
;*                 If <previous extended scan was an E1h>
;*                     Move E1h into the ext field for this entry
;*                 Else
;*                     Move E0h into the ext field for this entry
;*                 Endif
;*             Else
;*                 Move 0 into the ext field for this entry
;*             Endif
;*             Set the end of loop indicator
;*             KBDBeep TimedBeep,AddFreq,NormDuration
;*        Else
;*             Increment Entry index for the StickyTbl
;*        Endif
;*     EndWhile
;*     If <we could not add the scan code to the table>
;*        KBDBeep TimedBeep,FullFreq,FullDuration
;*        Indicate not to Consume this scan code in AIMFlags
;*     Endif
;*  ElseIf <AIMFlags indicate Delete scan code from the StickyKeyTbl>
;*     Turn off the bit indicating to delete from the table.
;*     While <we have not searched through the entire table>
;*        If <the current entry is equal to the scan code to delete>
;*            If <the translation flag area indicates that previous
;*                scan code seen was an extended scan code>
;*                 If <previous extended scan was an E0h> AND
;*                 If <ext field for this entry has an E0h in it>
;*                     Move a 0 into the scan code entry field
;*                     Move a 0 into the ext scan code entry field
;*                     If <we have not already issued a beep since
;*                         we entered this routine>
;*                         Indicate in AIMflags that we issued beep
;*                         KBDBeep TimedBeep,DelFreq,NormDuration
;*                     Endif
;*                 Else
;*                    If <previous extended scan was an E1h> AND  AND
;*                   .If <ext field for this entry has an E1h in it>
;*                        Move a 0 into the scan code entry field
;*                        Move a 0 into the ext scan code entry field
;*                        If <we have not already issued a beep since
;*                            we entered this routine>
;*                           Indicate in AIMflags that we issued beep
;*                           KBDBeep TimedBeep,DelFreq,NormDuration
;*                        Endif
;*                    Endif
;*                 Endif
;*            Else
;*                 If <ext field indicates that this entry in the
;*                      StickyKeyTbl is not for an extended scan code>
;*                     Move a 0 into the scan code entry field
;*                     If <we have not already issued a beep since
;*                         we entered this routine>
;*                         Indicate in AIMflags that we issued beep
;*                         KBDBeep TimedBeep,DelFreq,NormDuration
;*                     Endif
;*                     If <our current scan code is the break for a
;*                          left or right shift key>
;*                         Re-Initialize the number of ShiftKey makes
;*                           we have seen in a row to 0
;*                         Re-Initialize the number of ShiftKey breaks
;*                           we have seen in a row to 0
;*                     Endif
;*                 Endif
;*            Endif
;*        Endif
;*        Increment Entry index for the StickyTbl
;*    EndWhile
;*    Turn off the AIMFlag indicating that we issued a beep
;*  ElseIf < the AIMFlags indicate to unstick all modifiers >
;*    Get address of KeyPacket1
;*    Turn on AIMFlag that indicates we are going to inject the
;*      scan codes in the StickyTbl back into the input stream.
;*    Save the DDFlags for KeyPacket1
;*    Save the IntFlagArea XKeyFlags until we are done pumping scans.
;*    Set loop offset to zero.
;*    Repeat
;*       If <there is an entry in the StickyTbl for this offset>
;*         Get the scan code in AL.
;*         If <the scan was from a secondary keystroke>
;*              Turn on the IntFlagArea.XKeyFlags bit for secondary keys.
;*         Endif
;*         Empty out the StickyTbl for this offset.
;*         Save all
;*         Call ProcessScanCode to send the scan code to the input stream
;*         Pop all
;*       Endif
;*       Increment loop (offset) counter
;*    Until <we are done with the StickyTbl>
;*    Restore the IntFlagArea XKeyFlags
;*    Restore the DDFlags for KeyPacket1
;*    Clear out the packet length field of KeyPacket1 and put scan
;*      code back in high byte.
;*    Clear out KeyPacket1 scan and Character fields.
;*    Turn off AIMFlags for Unsticking all modifiers and injecting scans
;*      from the StickyTbl.
;*  Endif
;*  Restore BX
;*  Return
;*
;* END PCODE
;*
;**************************************************************************

   Push BX                                                               ;* AIM
   Xor  BX,BX                                                            ;* AIM
                                                                         ;* AIM
  .If <bit AIMFlags nz AddStickyKey> NEAR                                ;* AIM
                                                                         ;* AIM
      And AIMFlags, NOT AddStickyKey                                     ;* AIM
                                                                         ;* AIM
     .While <BL le MaxStickyKeys>                                        ;* AIM
                                                                         ;* AIM
         .If <<Byte Ptr [BX+StickyTbl]> eq AL>                           ;* AIM
                                                                         ;* AIM
            .If <<Byte Ptr [BX+ExtdFld+StickyTbl]> eq 0>                 ;* AIM
                                                                         ;* AIM
               .If <bit IntFlagArea.XKeyFlags z SecPrefix>               ;* AIM
                                                                         ;* AIM
                   Or AIMFlags, DupModKey                                ;* AIM
                                                                         ;* AIM
               .Endif                                                    ;* AIM
                                                                         ;* AIM
            .Else                                                        ;* AIM
                                                                         ;* AIM
               .If <bit IntFlagArea.XKeyFlags nz SecPrefix>              ;* AIM

                  .If <<Byte Ptr [BX+ExtdFld+StickyTbl]> eq Otherkey> AND
                  .If <bit IntFlagArea.XlateFlags z E1Prefix>
                                                                         ;* AIM
                      Or AIMFlags, DupModKey                             ;* AIM
                                                                         ;* AIM
                  .Else                                                  ;* AIM

                     .If <<Byte Ptr [BX+ExtdFld+StickyTbl]> eq Otherkey2> AND
                     .If <bit IntFlagArea.XlateFlags nz E1Prefix>
                                                                         ;* AIM
                         Or AIMFlags, DupModKey                          ;* AIM
                                                                         ;* AIM
                     .Endif                                              ;* AIM
                                                                         ;* AIM
                  .Endif                                                 ;* AIM
                                                                         ;* AIM
               .Endif                                                    ;* AIM
                                                                         ;* AIM
            .Endif                                                       ;* AIM
                                                                         ;* AIM
         .Endif                                                          ;* AIM
                                                                         ;* AIM
          Add BX,StkyEntrySize                                           ;* AIM
                                                                         ;* AIM
     .EndWhile                                                           ;* AIM
                                                                         ;* AIM
     .If <bit AIMFlags nz DupModKey>                                     ;* AIM
                                                                         ;* AIM
         KBDBeep TimedBeep,AddFreq,NormDuration                          ;* AIM
                                                                         ;* AIM
     .Else                                                               ;* AIM
                                                                         ;* AIM
          Xor BX,BX                                                      ;* AIM
                                                                         ;* AIM
         .While <BL le MaxStickyKeys>                                    ;* AIM
                                                                         ;* AIM
             .If <<Byte Ptr [BX+StickyTbl]> eq 0>                        ;* AIM
                                                                         ;* AIM
                   Mov Byte Ptr [BX+StickyTbl], AL                       ;* AIM
                                                                         ;* AIM
                  .If <bit IntFlagArea.XKeyFlags nz SecPrefix>           ;* AIM
                                                                         ;* AIM
                      .If <bit IntFlagArea.XlateFlags nz E1Prefix>       ;* AIM
                           Mov Byte Ptr [BX+ExtdFld+StickyTbl], OtherKey2;* AIM
                      .Else                                              ;* AIM
                           Mov Byte Ptr [BX+ExtdFld+StickyTbl], OtherKey ;* AIM
                      .Endif                                             ;* AIM
                                                                         ;* AIM
                  .Else                                                  ;* AIM
                       Mov Byte Ptr [BX+ExtdFld+StickyTbl], 0            ;* AIM
                  .Endif                                                 ;* AIM
                                                                         ;* AIM
                   Mov BL, MaxStickyKeys+StkyEntrySize                   ;* AIM
                                                                         ;* AIM
                   KBDBeep TimedBeep,AddFreq,NormDuration                ;* AIM
                                                                         ;* AIM
             .Else                                                       ;* AIM
                   Add BX,StkyEntrySize                                  ;* AIM
             .Endif                                                      ;* AIM
                                                                         ;* AIM
         .EndWhile                                                       ;* AIM
                                                                         ;* AIM
         .If <BL eq MaxStickyKeys+1>                                     ;* AIM
                                                                         ;* AIM
             KBDBeep TimedBeep,FullFreq,FullDuration                     ;* AIM
             And AIMFlags, NOT EatNextBreak                              ;* AIM
                                                                         ;* AIM
         .Endif                                                          ;* AIM
                                                                         ;* AIM
     .Endif                                                              ;* AIM
                                                                         ;* AIM
      And AIMFlags, NOT DupModKey                                        ;* AIM
                                                                         ;* AIM
  .ElseIf <bit AIMFlags nz DelStickyKey>  NEAR                           ;* AIM
                                                                         ;* AIM
     And AIMFlags, NOT DelStickyKey                                      ;* AIM
                                                                         ;* AIM
    .While <BL le MaxStickyKeys>  NEAR                                   ;* AIM
                                                                         ;* AIM
        .If <<Byte Ptr [BX+StickyTbl]> eq AL> NEAR                       ;* AIM
                                                                         ;* AIM
            .If <bit IntFlagArea.XKeyFlags nz SecPrefix>                 ;* AIM
                                                                         ;* AIM
                 .If <bit IntFlagArea.XlateFlags z E1Prefix> AND         ;* AIM
                 .If <<Byte Ptr [BX+ExtdFld+StickyTbl]> eq OtherKey>     ;* AIM
                                                                         ;* AIM
                      Mov Word Ptr [BX+StickyTbl], 0                     ;* AIM
                     .If <bit AIMFlags z StickyBeep>                     ;* AIM
                                                                         ;* AIM
                          Or AIMFlags, StickyBeep                        ;* AIM
                          KBDBeep TimedBeep,DelFreq,NormDuration         ;* AIM
                                                                         ;* AIM
                     .Endif                                              ;* AIM
                                                                         ;* AIM
                 .Else                                                   ;* AIM
                                                                         ;* AIM
                    .If <bit IntFlagArea.XlateFlags nz E1Prefix> AND     ;* AIM
                    .If <<Byte Ptr [BX+ExtdFld+StickyTbl]> eq OtherKey2> ;* AIM
                                                                         ;* AIM
                         Mov Word Ptr [BX+StickyTbl], 0                  ;* AIM
                        .If <bit AIMFlags z StickyBeep>                  ;* AIM
                                                                         ;* AIM
                            Or AIMFlags, StickyBeep                      ;* AIM
                            KBDBeep TimedBeep,DelFreq,NormDuration       ;* AIM
                                                                         ;* AIM
                        .Endif                                           ;* AIM
                                                                         ;* AIM
                    .Endif                                               ;* AIM
                                                                         ;* AIM
                 .Endif                                                  ;* AIM
                                                                         ;* AIM
            .Else                                                        ;* AIM
                                                                         ;* AIM
                 .If <<Byte Ptr [BX+ExtdFld+StickyTbl]> eq 0>            ;* AIM
                                                                         ;* AIM
                      Mov Byte Ptr [BX+StickyTbl], 0                     ;* AIM
                     .If <bit AIMFlags z StickyBeep>                     ;* AIM
                                                                         ;* AIM
                          Or AIMFlags, StickyBeep                        ;* AIM
                          KBDBeep TimedBeep,DelFreq,NormDuration         ;* AIM
                                                                         ;* AIM
                     .Endif                                              ;* AIM
                                                                         ;* AIM
                     .If <AL eq R_SHIFT_BRK> OR                          ;* AIM
                     .If <AL eq L_SHIFT_BRK>                             ;* AIM
                                                                         ;* AIM
                          Mov StickMakes, 0                              ;* AIM
                          Mov StickBreaks, 0                             ;* AIM
                                                                         ;* AIM
                     .Endif                                              ;* AIM
                                                                         ;* AIM
                 .Endif                                                  ;* AIM
                                                                         ;* AIM
            .Endif                                                       ;* AIM
                                                                         ;* AIM
        .Endif                                                           ;* AIM
                                                                         ;* AIM
         Add BL,StkyEntrySize                                            ;* AIM
                                                                         ;* AIM
    .EndWhile                                                            ;* AIM
                                                                         ;* AIM
     And AIMFlags, NOT StickyBeep                                        ;* AIM
                                                                         ;* AIM
  .ElseIf <bit AIMFlags nz UnStickAll>   NEAR                            ;* AIM
                                                                         ;* AIM
     Push SI                                                             ;* AIM
     Lea  SI,KeyPacket1                                                  ;* AIM
     Push AX                                                             ;* AIM
     Push DX                                                             ;* AIM
     Push CX                                                             ;* AIM
     Or AIMFlags, NonAIMScan                                             ;* AIM
     Mov DX, [SI].DDFlags                                                ;* AIM
     Mov CL, Byte Ptr IntFlagArea.XKeyFlags                              ;* AIM
     Mov BX,0                                                            ;* AIM
                                                                         ;* AIM
    .Repeat                                                              ;* AIM
                                                                         ;* AIM
       .If <<Byte Ptr [BX+StickyTbl]> ne 0>                              ;* AIM
          Or AimFlags, DeleteAllBeep                                     ;* AIM
          Mov AL, Byte Ptr [BX+StickyTbl]                                ;* AIM
                                                                         ;* AIM
         .If <<Byte Ptr [BX+ExtdFld+StickyTbl]> ne 0>                    ;* AIM
               Or IntFlagArea.XKeyFlags,SecPrefix                        ;* AIM
         .Else                                                           ;* AIM
               And IntFlagArea.XKeyFlags, NOT SecPrefix                  ;* AIM
         .Endif                                                          ;* AIM
                                                                         ;* AIM
          Mov Word Ptr [BX+StickyTbl], 0                                 ;* AIM
          Pusha                                                          ;* AIM
          CALLFAR ProcessScanCode                                        ;* AIM
          Popa                                                           ;* AIM
                                                                         ;* AIM
       .Endif                                                            ;* AIM
                                                                         ;* AIM
       Add BX,StkyEntrySize                                              ;* AIM
                                                                         ;* AIM
    .Until <BX gt MaxStickyKeys>                                         ;* AIM
                                                                         ;* AIM
    .If <bit AIMFlags nz DeleteAllBeep>                                  ;* AIM
         And AimFlags, NOT DeleteAllBeep                                 ;* AIM
         KBDBeep TimedBeep,DelFreq,NormDuration                          ;* AIM
    .Endif                                                               ;* AIM
                                                                         ;* AIM
     Mov Byte Ptr IntFlagArea.XKeyFlags, CL                              ;* AIM
     Pop CX                                                              ;* AIM
     Mov [SI].DDFlags, DX                                                ;* AIM
     Pop DX                                                              ;* AIM
     Mov Byte Ptr [SI].KPacketLen, 0                                     ;* AIM
     Pop AX                                                              ;* AIM
     Mov Byte Ptr [SI].KPacketLen+1, AL                                  ;* AIM
     Mov [SI].Key.Scan, 0                                                ;* AIM
     Mov [SI].Key.XChar, 0                                               ;* AIM
     And AIMFlags, NOT UnStickAll+NonAIMScan                             ;* AIM
     Pop SI                                                              ;* AIM
                                                                         ;* AIM
  .Endif                                                                 ;* AIM
                                                                         ;* AIM
   Pop BX                                                                ;* AIM
                                                                         ;* AIM
   Ret                                                                   ;* AIM
                                                                         ;* AIM
Endproc UpdStickyTbl                                                     ;* AIM

AIMCode Ends
        End
