;*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   KBDXLAT - Translation Process
     Name    KBDXLAT

;/*************************************************************************
;*
;* SOURCE FILE NAME = KBDXLAT.ASM
;*
;* DESCRIPTIVE NAME = Physical Keyboard Device Driver Translation Routines
;*
;*
;* VERSION      V2.0
;*
;* DATE         20/02/92
;*
;* DESCRIPTION  Keyboard scan code translation.
;*
;* FUNCTIONS    KbdXlate()      Keyboard Scan Code Translation
;*              CapsCheck()     Check IF character should be shifted
;*              SKCtlCheck()    Check IF character has special control code
;*              SKAltCheck()    Check IF character has extended code
;*              AccCheckout()   Check and Process Valid Accents
;*              ExtAccent()     Check and Process Valid Extended Accents
;*              BadAccent()     Process an Accent that does Not Apply to a Char
;*              AltPadPacket()  Set up a KeyPacket for the Break of the Alt Key
;*              MakeE0Packet()  Set up a KeyPacket for the E0 scan code
;*              CopyPacket()    Copy KeyPacket1 to KeyPacket2
;*              UnPauseChk()    Check For Key to End Pause Mode
;*              SGCheck()       Check if Scan Code Break from another SG
;*              AtlGraphCheck() Process an Alt-Graph character input
;*              CheckExtended() Checks for extended codes.
;*
;*
;* 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
;*   03/08/93              61012  Shiftlock bit not working fully on accents
;*   01/05/92              54339  Some keys with no support at all
;*                                The numeric pad comma, right tab and space
;*                                 keys are not working.
;*   01/05/92              55364  problem with type 11 (dec) keys
;*                         B786969
;*                         B725826
;*                         B708318
;*                         B719588
;*                         B705184
;*                         B704944
;*                         DCR 1579 Brazil extra keypad key
;*                         787418
;*                         B719593
;*                         DCR 1546 TO supprot languages with more they six
;*                                   accents.
;*                         61012
;**************************************************************************



.286p
.sall
.xcref
.xlist
  Include basemaca.inc    ; DOS macros.
  Include osmaca.inc      
  CPUMODE 286             ; 
  Include struc.inc       ; Structured assembly macros.
  Include devsym.inc      ; Device driver header definitions.
  Include kbdseg.inc      ; Segment definitions.
  Include kbdddr.inc      ; Keyboard Device Driver structures & equates.
  Include kbdxlat.inc     ; Translation structures & equates.
  Include devhlp.inc      ;            DevHlp & Signal equates
.list

;External Routines
  Extrn KHBuffer               :Near   ;           

;External Variables
  Extrn NewExtSCLen      :ABS
  Extrn MiscFlags        :Byte
  Extrn OtherFlags       :Byte
  Extrn AltTable         :Byte
  Extrn AltPadMap        :Byte
  Extrn CtlPadMap        :Byte
  Extrn NewExtSC         :Byte
  Extrn KCBShFlgs        :Word
  Extrn KeyHistory       :Word
  Extrn IDFlags          :Byte
  Extrn KbdHWIDs         :Word
  Extrn SCCount          :Byte                    ;%%              
  Extrn KeyHistBuf       :Byte                    ;%%              
  Extrn ScanBlockId      :Word                    ;%%              
  Extrn IntFlags         :Byte                    ;%%              
  Extrn DeviceHelp       :DWord                   ;%%              
  Extrn NumPadAccum      :Byte

  StkFrameVars

Code Segment

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

Public KbdXlate
Procedure KbdXlate, HYBRID

;**********************************************************************
;*
;* FUNCTION NAME  = KbdXlate
;*
;* DESCRIPTION    = Keyboard Scan Code Translation
;*
;*                  This routine translates the scan code received from
;*                  the keyboard and places it in a KeyPacket.
;*                  It also sets all flags that are based on the scan code
;*                  received.
;*
;*
;*
;* INPUT          =    AL=Raw Scan Code
;*                     DS:SI = Ptr to KeyPacket1
;*                     DS:StkTmpL = Ptr to KeyPacket2
;*                     DS:DI = Ptr to translation flag area
;*                     ES:BX = Ptr to Translate Table
;*
;* RETURN-NORMAL = Monitor Key Packet filled in
;*                 AL=Raw scan code if translation successful
;*
;* RETURN-ERROR  = If found a break of a shift key that had seen no
;*                 make, returns 0 and CX hold the unexpected shift bits.
;*
;* OUTPUT        = NONE(All regs except SI, DI and the Seg regs may be altered
;*                      Key Packet filled in)
;*
;* Internal References =
;*    Routines: UnPauseChk           AltGraphCheck
;*              AccCheckout
;*              CapsCheck            SKCtlCheck
;*              SKAltCheck           CheckExtended
;*              AltPadPacket         MakeE0Packet
;*
;* External References:
;*    Routines:  KHBuffer
;*
;*
;**********************************************************************

     Push   BP                             ; Save BP for stack frame vars.
     Mov    Byte Ptr [SI].KPacketLen+1,AL; Save scan code in Lgth field "MonFlags".
     And    [DI].XKeyFlags,Not NormalAlt   ; Turn flag off to start
     Mov    AH,AL                          ; Copy scan code into AH
     Or     AH,AH                          ; Check if key break bit in
    .If <s>                                ; If it is
       Or   [SI].DDFlags,KeyBreak          ; Set Flag
       And  AH,Not BreakBit                ; Clear the break bit from the scan code
    .Endif                                 ; Endif key break bit on

     Push   BX                             ; Put table start offset on the stack.
     Push   CX                             ; Save the SG Number
     Mov    CX,AX                          ; Now calculate...
     And    CX,07Fh                        ; ...the index into...
     Dec    CX                             ;  ...XlateTable for...
     IMul   CX,KDefLen                     ;     ...this scan code.
     Add    CX,KDefs                       ; Point past header to keydefs.
     Add    CX,BX                          ; Add offset into table.
     Push   SI
     Mov    SI,CX
     Mov    BX,ES:[SI].XlateOp             ; Get Xlate Operation word.
     And    BX,ActionMask                  ; Isolate translate action field.
     Pop    SI
     Mov    StkTmpReg,CX

     Push   DS                             ; Make sure we have PKBD's
     Mov    DS, StkDS                      ; DS here.
     Test   OtherFlags,InterruptTime       ; If it's interrupt time
     Pop  DS                               ; Restore caller's DS.
     Pop  CX                               ; Restore SG Number
                                           
    .If <nz> AND
      .If <BX ne 12> AND                   ; If it isn't one of the shift flags
      .If <BX ne 14>                       ; then put it in the keyhistory buffer
           Push  BX                        ; Save translate table pointer
                                           ;                
           Call  KHBuffer                  ; Buffer up scan codes
           Push  DS                        ; Save DS
           Pusha                           ; 
           Mov   DS, StkDS                 ; Get PKBD DS
          .If <bit IntFlags nz ScanBlockSet> AND  ; If Block is set AND
          .If <SCCount eq 0>                      ; If SCCount equals zero
;              And  IntFlags, NOT ScanBlockSet    ; Clear flag  ptr B729992
               Mov  BX, ScanBlockId        ; Get block ID
               Mov  AX, [ScanBlockId+2]    ; Get block ID
               Mov  DL,DevHlp_ProcRun      ; Run the Blocked process
               Call DeviceHelp             ; Do it
          .Endif                           ; 
           Popa                            ; 
           Pop  DS                         ; Restore callers DS
                                           ;            End
           Pop  BX                         ; Restore translate table pointer
    .Endif                                 ; 
                                           
     Mov  [SI].Key.Scan,AH                 ; Put scan code in key packet
     Test [DI].XKeyFlags,SecPrefix         ; Check if saw E0 prefix last time
    .If <nz>                               ; If we did
        Or [SI].DDFlags,SecondaryKey       ; Indicate so.
                                           
       .If <AL eq 53>                      ; If this is '/' on Numpad
          Test [SI].Key.Shift,AltFlag      
         .If <nz>                          ; If ALT Key is down
             Mov [SI].Key.Scan,0A4h        ; Set extended scan code
         .Else                             ; Else no Alt down
             Test [SI].Key.Shift,CtlFlag   ; Check if Ctl key down
            .If <nz>                       ; If it is
                 Mov [SI].Key.Scan,095h    ; Set extended scan code
            .Else                          ; Else no Alt or Ctl key down
                   push bx                 ;           
                   push ds
                   mov  ds,StkDS
                   mov  bx,KbdHWIDs
                   pop  ds
                   ror  bx, 8
                   .If <BX e JAGUAR> AND              ;If it's a 122 Key JAGUAR
                   test [si].Key.Shift,RShiftFlag+LShiftFlag ;Check Shift Keys.
                   .if <nz>
                       Mov  [SI].Key.XChar,' '        ; Its now a space!
                       mov  [SI].Key.Scan,39h
                   .else
                       Mov  [SI].Key.XChar,'/'        ; Its now an extended '/'
                       mov  [SI].Key.Scan,OtherKey
                   .endif
                   pop  bx                            ;           
            .Endif                         ; Endif Ctl key down
         .Endif                            
          Jmp EndActionCase                ; of country/code page.
       .Endif
    .Endif

     ;*
     ;*From now on, ES:StkTmpReg points to the Xlate table entry. If running in
     ;*a VDM, that pointer may have been created by a LOADALL, so don't
     ;*allow interrupts, nor change Seg Regs. Also, the beginning offset
     ;*of the translate table itself is on the top of stack.
     ;*


     Push   SI
     Mov    SI,StkTmpReg
     Add    SI,2
     Mov    CX,Word Ptr ES:[SI]            ; Get Char1 and Char2 values.
     Pop    SI
     Mov    DX,[SI].Key.Shift   ; Get the current shift status from Key.

    .If <BX ne 7> AND           ; If not a padkey clear possible Alt-nnn entry.
    .If <BX ne 14>                         ; Don't clear on Alt key, either.
       Mov [DI].XAltKeyPad,0               ; Clear Alt-nnn entry.
    .Endif
     Mov AL,CL                             ; Copy Char1 for use later.
    .If <BX gt MaxAct>                     ; Was the action number too big?
       Jmp NoXlate                         ; Yes, so don't try to translate.
    .Endif
     Shl    BX,1                           ; Make action number an offset.
     Add    BX,Offset KbdCode:XJumpTable   ; Point to processor address.
     Jmp    CS:[BX]                        ; Go translate.

     ;*
     ;* Following is the branch table for the various actions that
     ;* can be performed on a keystroke. Processing re-merges at the
     ;* bottom of this CASE structure, at label "EndActionCase".
     ;*

Public NoXlate, AlphaKey, SpecKey, SpecKeyC, SpecKeyA, SpecKeyCA
Public FuncKey, PadKey,   SpecCtlKey,  PrtScr, SysReq, AccentKeyType
Public ShiftKeys, ToggleKey,  AltKey,  NumLock, CapsLock, ScrollLock
Public XShiftKey, XToggleKey, SpecKeyCS,   SpecKeyAS, XXKey
Even
XJumpTable:
    dw  NoXlate              ; 0  Invalid action code, no translate done.
    dw  AlphaKey             ; 1  Alphabetical character key.
    dw  SpecKey              ; 2  Special non-alpha key, no CAPSLOCK or ALT.
    dw  SpecKeyC             ; 3  Special non-alpha key, with CAPSLOCK.
    dw  SpecKeyA             ; 4  Special non-alpha key, with ALT.
    dw  SpecKeyCA            ; 5  Special non-alpha key, w/CAPSLOCK and ALT.
    dw  FuncKey              ; 6  Function keys.
    dw  PadKey               ; 7  Numeric keypad keys.
    dw  SpecCtlKey           ; 8  Keys that do special things with CTL.
    dw  PrtScr               ; 9  The print screen key.
    dw  SysReq               ; A  The system request key.
    dw  AccentKeyType        ; B  A key that affects the NEXT key (dead key).
    dw  ShiftKeys            ; C  The LSHIFT, RSHIFT, and CTL keys.
    dw  ToggleKey            ; D  General Toggle key.
    dw  AltKey               ; E  The ALT key.
    dw  NumLock              ; F  The NUMLOCK key.
    dw  CapsLock             ; 10 The CAPSLOCK key.
    dw  ScrollLock           ; 11 The SCROLL LOCK key.
    dw  XShiftKey            ; 12 Extended shift key (for DBCS use).
    dw  XToggleKey           ; 13 Extended toggle key (for DBCS use).
    dw  SpecKeyCS            ; 14 Special key for NLS support.
    dw  SpecKeyAS            ; 15 Special key for NLS support.
    dw  Reserved             ; 16 Reserved for DBCS
    dw  Reserved             ; 17 Reserved for DBCS
    dw  Reserved             ; 18 Reserved for DBCS
    dw  Reserved             ; 19 Reserved for DBCS
    dw  XXKey                ; 1a Ex Ex key support.use with Jaguar KBD

   ;*
   ;*   On entering the following routines, the following regs are set:
   ;*
   ;*     CL = Char1  and  CH = Char2  (both from XlateTable entry)
   ;*     DX = ShiftFlags (same as in Key CharData record)
   ;*     AL = Char1 also  AH = Received scan code (Breakbit cleared)
   ;*     SI = Pointer to Key Packet   DI = Pointer to current PSG
   ;*     ES:StkTmpReg = Pointer to XlateTable entry for this scan code.
   ;*     SS:SP = Pointer to Word holding Offset of top of XlateTable
   ;*
   ;*   Also, Key.Scan = AH and Key.XChar = 0 on entry to the routines.
   ;*

AlphaKey:                                  ; Alphabetical character key.
          Test DL,AltFlag                  ; Check if Alt key is pressed.
         .If <nz>                          ; Is it?
            And [DI].XlateFlags,Not Use3Index  ; Use Char3 if AltGraph
            Call AltGraphCheck             ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt  ; Check if it's not the AltGraph
           .If <nz>                        ; If alt key is normal Alt
               Xor  AH,AH                  ; Yes, so make Char1 an offset.

               Push DS                     ;           For Arabic and Hebrew
               Push SI                     ; 
               Mov  DS, StkDS              ; 
               Mov  SI,StkTmpReg           ; 
              .If <bit MiscFlags nz MLayerMode> AND
              .If <ES:[SI].Char4 ne 0>     ; If char 4 is not 0
                 Mov AL, ES:[SI].Char4     ; 
              .Endif                       ; 
               Pop SI                      ; 
               Pop DS                      ; 

               Mov BX,AX                   ; Now make it the base.
              .If < BX le "z" >            ; If in the range,           
                Push DS                    ;           
                Mov  DS,StkDS              ; AltTable is in the base DS
                Mov  AH,[AltTable+BX-"a"]  ; Fetch Alt-[] mapped code.
                Pop  DS                    ;           
              .Else                        ; Else
                Mov  AH, [SI].Key.Scan     ; Get original scan
              .Endif                       
               Mov  [SI].Key.Scan,AH       ; Put in Key record.
               Xor  AL,AL                  ; Set `extended char' code.

           .Endif
         .Else
            Test DL,CtlFlag                ; Else, check if Ctl key is pressed.
                                           ; for this KCB
                                           
           .If <nz> OR                     ; Is it  OR?
            Test [DI].XHotKeyShift,CtlFlag ; Also check in interrupt shift
                                           ; state
           .If <nz> AND                    ; Is it being held down at all
           ;mueller for Sarka
            Push DS                        
            Mov  DS, StkDS                 
            Test Otherflags, InterruptTime 
            Pop  DS                        
           .If <nz>                        ; translations are independent.
                                           
                                           ; Check limit on char1 value!


                                           ;           
              Push   DS
              Push   SI
              Mov    DS, StkDS
              Mov    SI,StkTmpReg
             .If <bit MiscFlags nz MLayerMode> AND
             .If <ES:[SI].Char4 ne 0>      ;If char 4 is not 0
                Mov  AL, ES:[SI].Char4
                Mov  CL, AL
             .Endif
              Pop SI
              Pop DS
              Sub AL,"a"-1                 ;Convert Char1 to control code.


             .If <CL eq 'c'>               ;Is this Ctrl-C?

               .If <[DI].XInputMode eq 0>   ; If we are in cooked mode
                 Or [SI].DDFlags,PSBreakKey ; Tell dd it's the PSUEDO-BREAK KEY.
                 Jmp NoPauseCheck           ; Do not check if paused, Ctl-C
                                            ; has priority over resuming output
               .Endif
             .ElseIf <CL eq 'p'>            ; Is this Ctrl-P?
               .If <[DI].XInputMode eq 0>   ; are we in cooked mode?
                 Or [SI].DDFlags,PSPrintEchoKey  ;  PSUEDO-PRTECHO KEY.
                 Jmp NoPauseCheck           ; Do not check if paused, Ctl-P
                                            ; priority over resuming output
               .Endif
             .ElseIf <CL eq 's'>            ; Is this Ctrl-S?
               .If <[DI].XInputMode eq 0>   ; Right, are we in cooked mode?
                  Or [SI].DDFlags,PSPauseKey; PSUEDO-PAUSE KEY.
               .Endif
             .Endif
           .Else                            ; Check for regular shifts/capslock.
              Mov BL, CapsTogl              ; Set indicator that CapsLock and
                                            ; ShiftLock affect key.
              Call CapsCheck                ; Determine shifting of the char.
           .Endif                           ; Endif Ctrl or Interrupt time.
         .Endif                             ; Endif Alt is down.

          Call UnPauseChk                   ; Go check if in pause state.

NoPauseCheck:
          Mov [SI].Key.XChar,AL             ; Put xlated character into Key rec.
                                            
          Test [SI].DDFlags,KeyBreak        ; Check if this a break or make.
         .If <z>                            ; If it isn't then go and check accent.
                                            
            Call AccCheckout                ; Go check if accent combo going on.
                                            
         .Endif                             ; Endif this is a make.
                                            
          Jmp EndActionCase          ; Go to bottom of Xlate Action case table.

SpecKey:                             ; Special non-alpha, no CAPSLOCK or ALT.
          Call UnPauseChk                   ; Go check if in pause state.
          Test DL,AltFlag                   ; Check if Alt key is pressed.
         .If <nz>                           ; Is it?
            And  [DI].XlateFlags,Not Use3Index  ; Use Char3 if AltGraph
            Call AltGraphCheck              ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt   ; Check if it's the AltGraph
           .If <z>                          ; If alt key is AltGraph
                                            ; which is undefined for key
              Mov  [SI].Key.XChar,AL        ; put it in CDR
              Call AccCheckout              ; Check if acc. combo going on.
              Jmp  EndActionCase            ; Go to bottom of Xlate Action
           .Endif                           ; case table
            Jmp NoXlate                     ; then Key combo is undefined
         .Endif                             ; Endif Alt Key down
                                            
          Mov  BX,SP                        ; Get Xlate table header off.
          Mov  BX,SS:[BX]                   ; Put it in BX
          Test ES:[BX].XTFlags1,ShiftLock   ; Check if SHIFTLOCK keyboard.
         .If <nz>                           ; If it is
             Mov BL,CapsTogl                ; Indicate a CAPSLOCK check.
         .Else                              ;           
             Mov BL, 0                      ; 
         .Endif                             
          Test DL, CtlFlag                  ; Check if Ctrl key down.
         .If <nz>                           ; If so ...
             Call SKCtlCheck                ; check if char has special
                                            ; control code.
         .Else                              ; Else Ctrl key not down,
             Call CapsCheck                 ; Check for shifting.
         .Endif                             ; Endif Ctrl down.
          Mov  [SI].Key.XChar,AL            ; Put Char in Key rec.
          Call AccCheckout                  ;           
          Jmp  EndActionCase                ; Go to bottom of Xlate Action.

SpecKeyC:                                   ; Special non-alpha key, with CAPSLOCK.
          Call UnPauseChk                   ; Go check if in pause state.
          Test DL,AltFlag                   ; Check if Alt key is pressed.
         .If <nz>                           ; Is it?
            And  [DI].XlateFlags,Not Use3Index ; Use Char3 if AltGraph
            Call AltGraphCheck              ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt   ; Check if not the AltGraph
           .If <nz>                         ; If alt key is normal Alt
              Push SI                       ; 
              Mov  SI,StkTmpReg             ; 
             .If <ES:[SI].Char4 eq 0>       ; then check if char 4 is 0
                                            
                Pop  SI                     ; 
                Call CheckExtended          ; See if new extended code
                                            ;  is defined
                .If <c>                     ; If it is defined.
                    Call AccCheckout        ; Check if acc. combo going on.
                    Jmp  EndActionCase      ; Go to bottom of Xlate Action
                .Endif                      
                 Add  AH,118                ; calculate extended code.
                 Mov [SI].Key.Scan,AH       ; Put extended code in Key rec.
                 Jmp NoXlate                ; the key combo is undefined
             .Else                          ; else if char 4 isn't 0
                Mov AL,ES:[SI].Char4        ; then use it
                Pop SI                      ; 
             .Endif                         ; Endif Char 4 is 0
           .Endif                           ; Endif Alt key is normal Alt.
          Jmp SpecAccent                    ; Go check if this is accent
         .Endif                             ; Endif Alt Key down

          Test DL, CtlFlag                  ; Check if Ctrl key down.
         .If  <nz>                          ; If so ...
             Call SKCtlCheck                ; check if char has special
                                            ; control code.
         .Else                              ; Else Ctrl is not down.
                                            ;            CapsCheck in Else
             Mov  BL,CapsTogl               ; Indicate check CAPSLOCK.
             Call CapsCheck                 ; Check for shifting.
         .Endif

SpecAccent:
         .If <AL b 8>                       ; Indicate this is unprocessed
              Or   [SI].DDFlags,AccentKey   ; accent.
              Test [SI].DDFlags,KeyBreak    ; Check for the key BREAK.
             .If <z>                        ; Is it?
                And [DI].XlateFlags,Not PrevAccent ; No, clear previous
                                                   ; accent number.
                Or Byte Ptr [DI].XlateFlags,AL     ; Save accent number
                                                   ;  for the next key.
             .Endif
              Jmp EndActionCase      ; Go to bottom of Xlate Action case table.
         .Endif
          Mov  [SI].Key.XChar,AL            ; Put Char in Key rec.
          Call AccCheckout                  
          Jmp  EndActionCase         ; Go to bottom of Xlate Action case table.

SpecKeyA:                                   ; Special non-alpha key, with ALT.
          Call UnPauseChk                   ; Go check if in pause state.
                                            
          Mov  BX,SP                        ; Get Xlate table header off.
          Mov  BX,SS:[BX]                   ; Put it in BX
          Test ES:[BX].XTFlags1,ShiftLock   ; Check if SHIFTLOCK keyboard.
         .If <nz>                           ; If it is
             Mov BL,CapsTogl                ; Indicate a CAPSLOCK check.
         .Else                              ;           
             Mov BL, 0                      ; 
         .Endif                             
          Test DL, AltFlag                  ; Check if Alt is down,
         .If <nz>                           ; If it is...
             Call SKAltCheck                ; Check for extended code.
         .Else                              ; If it is not down,
            .If <bit dl nz CtlFlag>         
               Call SKCtlCheck              ; Check for spec. Ctrl code.
            .Else
               Call CapsCheck               ; Check for Shifting.
            .Endif                          
             Mov [SI].Key.XChar,AL          ; Put Char in Key rec.
         .Endif                             ; Endif Alt is down.
          Call AccCheckout                  
          Jmp  EndActionCase                ; Go to bottom of Xlate Action.

SpecKeyCA:                   ; Special non-alpha key, w/CAPSLOCK and ALT.
          Call UnPauseChk                   ; Go check if in pause state.
          Mov  BL,CapsTogl                  ; Indicate check CAPSLOCK.
          Test DL, AltFlag                  ; Check if Alt is down,
         .If <nz>                           ; If it is...
             Call SKAltCheck                ; Check for extended code.
         .Else                              ; If it is not down,
             Call CapsCheck                 ; Check for Shifting.
             Test DL, CtlFlag               ; Check if Ctrl is down,
            .If <nz>                        ; If it is then...
                Call SKCtlCheck             ; Check for spec. Ctrl code.
            .Endif                          ; Endif Ctrl is down.
         .Endif                             ; Endif Alt is down.
          Mov [SI].Key.XChar,AL             ; Put Char in Key rec.
          Jmp EndActionCase                 ; Go to bottom of Xlate Action.

FuncKey:                                    ;Function keys.

                          ;************************************************
                          ; Ray Andrade "CHANGE TEAM" defect #79165.
                          ; Ctl-Alt F10-F10 is the new DUMP key for notebooks
                          ;************************************************
          Test DL,CtlFlag                   ; Check if Ctrl is down
         .If <nz>                           ; If it is then...
            Test DL,AltFlag                 ;Check Alt Key.
           .If <nz>                         ;If its not down?
             .If <CL eq 10>                 ;Test Function key F10.
                Test [DI].XKeyFlags,DumpKeyOnce ; Check if second time.
               .If <nz>                       ; Is it?
                  Or [SI].DDFlags,DumpKey     ; So tell dd it's the DUMP KEY.
               .Else
                  Test [SI].DDFlags,KeyBreak  ; Check if this's key break.
                 .If <nz>                     ; Is it?
                    Or [DI].XKeyFlags,DumpKeyOnce ; Yes indicate seen once.
                    jmp CT
                 .Endif
               .Endif
             .Endif
           .Endif
         .Endif
                              ;***********************************************

          Call UnPauseChk                   ;Go check if in pause state.
CT:                                         ;Continue
          Test DL,AltFlag                   ;Check Alt Key.
         .If <nz>                           ;Is it down?
            And  [DI].XlateFlags,Not Use3Index  ; Use Char3 if AltGraph
            Call AltGraphCheck              ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt   ; Check if it's not AltGraph
           .If <nz>                         ; If alt key is normal Alt
               .If <CL gt 10>               ; Yes, so check if F11 or F12.
                  Add CL,128                ; If so, extended code 139 or 140
               .Else
                  Add CL,103                ; Extended code is range 104-113.
               .Endif                       ; 
           .Else                            ; Else ALt key was Atl-Graph
                                            
                Mov [SI].Key.XChar,AL       ; Move char 3 to key packet
                Mov CL,[SI].Key.Scan        ; Move scan to CL
                                            
           .Endif                           ; Endif Alt or AltGraph check
         .Else                              ; Endif no Alt key down
            Test DL,CtlFlag                 ; Check Ctl Key.
           .If <nz>                         ; Is it down?
             .If <CL gt 10>                 ; Yes, so check if F11 or F12.
                Add CL,126                  ; If so, extended code 137 or 138.
             .Else
                Add CL,93                   ; Extended code is range 94-103.
             .Endif
           .Else
              Test DL,RShiftFlag+LShiftFlag ; Check Shift Keys.
             .If <nz>                       ; Is one down?
               .If <CL gt 10>               ; Yes, so check if F11 or F12.
                  Add CL,124                ; If so, extended code 135 or 136.
               .Else
                  Add CL,83                 ; Extended code is range 84-93.
               .Endif
             .Else                          ; Else this is a non-shifted FKey.
               .If <CL gt 10>               ; Check if F11 or F12.
                  Add CL,122                ; If so, extended code 133 or 134.
               .Else
                  Add CL,58                 ;Extended code is range 59-68.
               .Endif
             .Endif
           .Endif
         .Endif
          Mov [SI].Key.Scan,CL              ; Put code in CharData rec.
                                            
          Call AccCheckout                  ; Check if accent combo going on.
                                            
          Jmp EndActionCase                 ; Go to bottom of Xlate Action case table.


PadKey:                                           ; Numeric keypad keys.
                                                  
        .If <bit DL nz AltFlag> AND               ; If Alt key down
        .If <CL eq 12> AND                        ; If current key mapped to Del?
        .If <bit [SI].DDFlags z KeyBreak>         ; If a make key
           .If <bit DL nz CtlFlag>  OR            ; If CtlFlag down OR
           .If <bit [DI].XHotKeyShift nz CtlFlag> ; If interrupt shift ctl
              Jmp NoPauseChk                      ; Don't Pause Check! REBOOT.
           .Endif                                 ; Endif
        .Endif                                    ; Endif

          Call UnPauseChk                         ; Go check if in pause state.

NoPauseChk:

          Xor BX,BX                    ; Clear for use later.
          Test DL,AltFlag              ; Check if Alt key down.
         .If <nz> NEAR                 ; Are we entering Alt-nnn?
                                       ; Maybe. First check for reboot request.
           .If <CL eq 12> AND          ; And is current key mapped to Del?
                                       
            Test [SI].DDFlags,KeyBreak ; Check if this a break
           .If <z> AND                 ; If it isn't (only reboot on make of Del)
                                       
            Test DL,CtlFlag            ; Maybe. First check for reboot request.
           .If <nz> OR                 ; Is Ctl down too
                                       ; for this KCB  OR

                                            
            Test [DI].XHotKeyShift,CtlFlag  ; Also check in interrupt shift
                                            ;   state
           .If <nz>                         ; Is it being held down at all
                                            
              Or [SI].DDFlags,RebootKey     ; Tell dd it's the REBOOT KEY.
              Jmp EndActionCase             ; Quit now.
           .Endif
            And  [DI].XlateFlags,Not Use3Index  ; Use Char3 if AltGraph
            Call AltGraphCheck               ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt    ; Check if it's not AltGraph
           .If <nz>                          ; If alt key is normal Alt
                                             
              Test [DI].XKeyFlags,SecPrefix  ; Check if secondary key
             .If <nz>                        ; If it is
                 Add [SI].Key.Scan,50h       ; Make scan extended code
                 Mov [SI].Key.XChar,0        ; Make char extended code
             .Else                           ; Else primary pad key
                 Test [SI].DDFlags,KeyBreak  ; Check if is a key break.
                .If <z>                      ; Is it?
                   Mov BL,CL                 ; No, so make Char1 value index.
                                             ; Fix for VDMs (start)
                   Push DS                   ; Save current data sel
                   Mov  DS,StkDS             ; Get base DDs data sel
                   Mov  CL,[BX+AltPadMap]    ; Numeric value of the key.
                   Pop  DS                   ; Restore current data sel
                                             ; Fix for VDMs (start)
                   Or   CL,CL                ; Check if value is -1.
                  .If <s>                    ; Is it.
                     Mov [DI].XAltKeyPad,0   ; Not numeric, reset.
                    .If <AH eq 83>           ; If this is DEL key
                        Jmp NoXlate          ; No extended value, undefined
                    .Else                    ; Else extended char
                        Jmp EndActionCase    ; Mark char defined
                    .Endif                   ; Endif Extended Char exists
                  .Else
                     Mov AL,10               ; Else multiply old...
                     Mul [DI].XAltKeyPad     ; ...accumulator by 10.
                     Add AL,CL               ; And add new key.
                     Mov [DI].XAltKeyPad,AL  ; Save modified accum.
                     Jmp NoXlate             ; Mark keystroke undefined
                  .Endif
                .Else                        ;  Begin Else a break
                   Jmp NoXlate               ; Mark keystroke undefined
                .Endif
             .Endif                          ; Endif primary or secondary key
                                             
           .Else
              Mov  [SI].Key.XChar,AL         ; Put Char into Key rec.
              Test [SI].DDFlags,SecondaryKey ; Check if G keyboard dup key.
             .If <nz>                        ; Is it?
                 Mov [SI].Key.Scan,OtherKey  ; Yes, so mark it so.
             .Endif                          ; 
           .Endif                            ; Endif normal ALT
         .Else NEAR                          ; No Alt key down.
                                             
            Test [DI].XKeyFlags,SecPrefix    ; Check if secondary key
           .If <nz>                          ; If it is
               Mov AL,OtherKey               ; Set Char to E0
           .Else                             ; Else regular pad key
               Xor AL,AL                     ; Set Char to "extended"
           .Endif                            
            Test DL,CtlFlag                  ; Check if Ctl key down.
           .If <nz>                          ; Is it?
              Mov BL,CL                      ; Yes, so make Char1 value index.
                                             ; Fix for VDMs (start)
              Push DS                        ; Save current data sel
              Mov  DS,StkDS                  ; Get base DDs data sel
              Mov  AH,[BX+CtlPadMap]         ; Extended value of the key.
              Pop  DS                        ; Restore current data sel
              Mov  [SI].Key.Scan,AH          ; Set extended code for this key.
           .Else                  ; Not Alt- or Ctl-, so figure out Num status.
             .If <CL eq 3> OR                ; Is this the minus key?
             .If <CL eq 13>                  ; Or is this the Brazil period key?
                mov al,ch                    ;  then ignore shift state
             .Elseif <CL eq 7>               ; Or is this the plus key?
                Mov AL,CH         ; Yes, so use Char2 regarless of shifts.
                                             ;            Brazil extra keypad key
                push bx                      ;           
                push ds
                mov  ds,StkDS
                mov  bx,KbdHWIDs
                pop  ds
                ror  bx, 8
                .If <BX e JAGUAR> AND              ; If it's a 122 Key JAGUAR
                test dl,RShiftFlag+LShiftFlag      ; Check Shift Keys.
                .if <nz>                           ; shifted pad '+' is now a TAB...
                     mov  al,9                     ; so set new code...
                .endif
                pop  bx                            ;           
             .Else
                Test DL,RShiftFlag+LShiftFlag      ; Check for shift key.
               .If <nz>                            ; Is one down?
                  Or BL,NumTogl                    ; Yes, so set NumLock bit.
               .Endif
                And DL,NumTogl                     ; Clear all bits but NumLock.
                Xor DL,BL                          ; Flip it if shift key was down.
               .If <nz>                            ; Is the case Num Lock?
                  Mov AL,CH                        ; Yes, so use Char2.
               .Endif
                                                   
               .If <z> OR                          ; If we should not shift
                Test [SI].DDFlags,SecondaryKey     ; if G keyboard dup key.
               .If <nz>                            ; If it is
                 .If <CL eq 11>                    ; Is this the Ins key?
                    Test [SI].DDFlags,KeyBreak     ; Yes check if key BREAK.
                   .If <nz>                             ; Is it?
                      And [DI].XKeyFlags,Not InsKeyDown ; Yes clear latch.
                   .Else                                ; Not Ins Key Break.
                      Test [DI].XKeyFlags,InsKeyDown    ; Check if seen Ins.
                     .If <z>                            ; Have we?
                        Or [DI].XKeyFlags,InsKeyDown    ; No, so set latch.
                        Xor Byte Ptr [SI].Key.Shift,InsTogl ; Toggle in CDR
                     .Else                   ; Otherwise this is repeat of make.
                        Or [SI].DDFlags,MultiMake  ; So indicate so.
                     .Endif
                   .Endif
                 .Endif
               .Endif              ; Endif we should set/clear insert toggle
                                   
             .Endif
           .Endif
            Mov  [SI].Key.XChar,AL          ; Put character value in Key rec.
            Test [SI].DDFlags,SecondaryKey  ; Check if G keyboard dup key.
           .If <nz>                         ; Is it?
              Mov [SI].Key.XChar,OtherKey   ; Yes, so mark it so.
           .Endif
         .Endif                             ; Endif Alt key down or not check
                                            
          Call AccCheckout                  ; Go check if accent combo going on.
                                            
          Jmp EndActionCase        ; Go to bottom of Xlate Action case table.


SpecCtlKey:                                    ; Keys that do special things with CTL.
          Call UnPauseChk                      ; Go check if in pause state.
          Test DL,AltFlag                      ; Check if Alt key down.
         .If <nz>                              ; Is it?
            And  [DI].XlateFlags,Not Use3Index ; Use Char3 if AltGraph
            Call AltGraphCheck                 ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt      ; Check if it's not the AltGraph
           .If <nz>                            ; If alt key is normal Alt
                                               
              Xor AL,AL                        ; Set Char to be extended
             .If <AH eq 1Ch> AND               ; If this is the Enter key
              Test [SI].DDFlags,SecondaryKey
             .If <nz>                          ; on the pad keys
                                               
                 Mov [SI].Key.Scan,0A6h        ; Set extended code
             .Endif
           .Endif                              

            Jmp SetCharField                   ; go set char field
         .Endif
                                               
          Test [SI].DDFlags,SecondaryKey       ; Check if G keyboard dup key.
         .If <nz>                              ; Is it?
             Mov [SI].Key.Scan,OtherKey        ; Yes, so mark it so.
         .Endif
          Test DL,CtlFlag                      ; Check if Ctl key down.
         .If <nz>                              ; Is it?
            Mov AL,CH                          ; Yes, so use Char2.
         .Endif
       SetCharField:                           
                                               ; aLT shoudl have precedence
                                               ; when Ctrl and Altare down.

          Mov [SI].Key.XChar,AL                ; Put Char into Key rec.
                                               
                                               
          Call AccCheckout                     ; Check if accent combo going on.
                                               
          Jmp EndActionCase     ; Go to bottom of Xlate Action case table.


PrtScr:                                        ; The print screen key.
          Call UnPauseChk                      ; Go check if in pause state.

          push bx                              ;           
          push ds
          mov  ds,StkDS
          mov  bx,KbdHWIDs
          pop  ds
          ror  bx, 8
          .If <BX e JAGUAR>                    ; If it's a 122 Key JAGUAR
               test dl,RShiftFlag+LShiftFlag   ; Check Shift Keys.
               .if <nz>                        ; shifted pad '*' is now a ','...
                    pop  bx
                    mov  al,','                ; so set extended code...
                    mov  [si].Key.Scan,33h     ; for scan and char
                    jmp  PScrOver
               .endif
          .endif
          pop  bx                              ;           

          Test DL,AltFlag                      ; Check if Alt key down.
         .If <nz>                              ; Is it?
            Test [DI].XKeyFlags,SecPrefix      ; Check if secondary key
           .If <nz> OR                         ; If it is OR...
            Push DS                            ; Make sure we have PKBD's
            Mov  DS, StkDS                     ; DS here.
            Test MiscFlags,EnhancedKbd         ; Check if enhanced kbd
            Pop  DS                            
           .If <z>  OR                         ; OR...If it's a regular kbd
            Push DS                            
            Mov  DS, StkDS                     ; 
            Test IDFlags, SuperSport           ; Check if 122 key SuperSport KBD
            Pop  DS                            ; Restore caller's DS.
           .If <nz>                            ; If it is...
              Test DL,CtlFlag                  ; Check if Ctl key is down
             .If <nz> OR                       ; If it is
                                               ; for this KCB
                                               
              Test [DI].XHotKeyShift,CtlFlag   ; Also check in interrupt shift
                                               ; state
             .If <nz>                          ; Is it being held down at all
                                               
                Or  [SI].DDFlags,PrintFlushKey ; Indicate this is FlushPrtbuf
                Jmp EndActionCase              ; Go to bottom of Xlate Action
                                               ; case table.
             .Endif

              Push DS                          ;           
              Mov  DS, StkDS                   ;           
             .If <bit MiscFlags z EnhancedKbd> ;           If not enhanced KBD
                Pop DS                         ;           (then regular AT KBD)
                Jmp EndActionCase    ;           Go to bottom of Xlate Action
             .Endif                            ;           Endif
              Pop  DS                          ;          
              Jmp  NoXlate                     ; Else that's undefined for this key.
                                               ; PTM 5024 begin
           .Else                               ; Else it Pad Key * on G kbd
              Xor AL,AL                        ; Set extended code
           .Endif                              ; Endif PrtScr or *
         .Else  NEAR                           ; Else no Alt key down
            Test DL,CtlFlag                    ; Check if Ctl key down.
                                               ; for this KCB
                                               ; PTM 5992 - Begin
           .If <nz> OR                         ; Is it  OR?
            Test [DI].XHotKeyShift,CtlFlag     ; Also check in interrupt shift
                                               ; state
           .If <nz>                            ; Is it being held down at all
                                               ; PTM 5992 - End
              Test [DI].XKeyFlags,SecPrefix    ; Check if secondary key
             .If <nz> OR                       ; If it is OR...
              Push DS                          ; Make sure we are using PKBD's
              Mov  DS, StkDS                   ; DS here.
              Test MiscFlags,EnhancedKbd       ; Check if enhanced kbd
              Pop  DS                          
             .If <z> OR                        ; OR...If it's a regular kbd
              Push DS                          
              Mov  DS, StkDS                   ; DS here.
              Test IDFlags, SuperSport         ; Check if 122 key SuperSport KBD
              Pop  DS                          ; Restore caller's DS.
             .If <nz>                          ; If it is...
                  Xor AL,AL                    ; Yes so set extended code...
                  Mov [SI].Key.Scan,CH         ;  ...for the Ctl-PrSc combination.
                  Or  [SI].DDFlags,PrintEchoKey; Tell dd it's the PRINT
                                               ; ECHO KEY.
                                               
             .Else                             ; Else its the keypad *
                  Xor AL,AL                    ; so set extended code...
                  Mov [SI].Key.Scan,96h        ; for scan and char
             .Endif                            
           .Else                               ; Else Ctrl key not down.
              Test [DI].XKeyFlags,SecPrefix    ; Check if secondary key
             .If <nz> OR                       ; If it is OR...
              Test DL,RShiftFlag+LShiftFlag    ; Check if a shift flag down.
             .If <nz> AND                      ; If a shift key is down AND...
              Push DS                          ; Make sure that we are using
              Mov  DS, StkDS                   ; the PKBD's DS here.
              Test MiscFlags,EnhancedKbd       ; Check if enhanced kbd
              Pop  DS                          
             .If <z> OR                        ; AND...If it's a regular kbd
              Push DS                          
              Mov  DS, StkDS                   ; the PKBD's DS here.
              Test IDFlags, SuperSport         ; Check if 122 key SuperSport Kbd
              Pop  DS                          ; Restore caller's DS
             .If <nz>                          ; If it is...
                Xor  AL,AL                     ; Yes, so clear char code.
                Or   [SI].DDFlags,PrtScrKey    ; Tell dd it's PRINT SCREEN KEY.
                Test [SI].DDFlags,KeyBreak     ; Check for the key BREAK.
               .If <nz>                        ; Is it?
                  And [DI].XKeyFlags,Not PSKeyDown ; Yes, clear PS Key latch
               .Else
                  Test [DI].XKeyFlags,PSKeyDown ; Check if seen PS key yet.
                 .If <z>                        ; Have we?
                    Or [DI].XKeyFlags,PSKeyDown ; No, set latch saying have.
                 .Else                          ; Otherwise repeat of the make.
                    Or [SI].DDFlags,MultiMake   ; So indicate so.
                 .Endif                         ; Endif no PS key yet check
               .Endif                           ; Endif Key break or not check
             .Else                              ; PTM 2606:  Shift keys not
                                                ; down or not enhanced kbd.
                Test [SI].DDFlags, KeyBreak     ; If this is a break of the
               .If < nz >                       ;  PrtScr key,
                  And [DI].XKeyFlags,Not PSKeyDown  ; Ensure latch is
                                               ;  cleared.
               .Endif                          ; Endif PrtScr break.
             .Endif                            ; Endif shift key down
           .Endif                              ; Endif Ctl down or not check
         .Endif                                ; Endif Alt key down check
PScrOver:
          Mov [SI].Key.XChar,AL                ; Put character in Key rec.
                                               ; PTM 6860 - Begin
          Call AccCheckout                     ; Go check if accent combo going on.
                                               ; PTM 6860 - End
          Jmp EndActionCase       ;Go to bottom of Xlate Action case table.


AccentKeyType:                    ; A key that affects the NEXT key (dead key).
          Call UnPauseChk                    ; Go check if in pause state.
          Test DL,AltFlag                    ; Check if ALT down.
         .If <nz>                            ; Is one?
             Or   [DI].XlateFlags,Use3Index  ; Use Char3 if AltGraph
             Call AltGraphCheck              ; Process if AltGraph
             Test [DI].XKeyFlags,NormalAlt   ; check if it was Altgraph key
            .If <z>                          ; If it was AltGraph key
              .If <CL a 7>                   ; If char 3 wasn't accent
                  Mov  [SI].Key.XChar,CL     ; Put char in CDR
                  Mov  [SI].Key.Scan,AH      ; Put scan in CDR
                  Call AccCheckOut           ; Go check if accent combo (p6860)
                  Jmp  EndActionCase         ; And quit now
              .Else                          ; Else char3 was an accent or 0
                 .If <CL eq 0>               ; If Char 3 was 0
                     Jmp NoXlate             ; Mark Key packet undefined
                 .Else                       ; Else it was an accent
                     Xor BH,BH               ; Flag no shift check
                     Jmp ShiftAccent
                 .Endif                      ; Endif Char3 was 0 or not
              .Endif                         ; Endif Char3 accent or not
            .Endif                           ; Endif Altgraph key down
         .Endif                              ; Endif ANY Alt key down
          Test [DI].XKeyFlags,NormalAlt      ; Check if it's not the AltGraph
         .If <nz> OR                         ; If alt key is normal Alt
          Test DL,CtlFlag
         .If <nz>                            ; OR CTL key is down
            Push SI                          ; 
            Mov  SI,StkTmpReg                ; 
            Mov  CL,ES:[SI].Char5            ; Get accent entry index
                                             ;   for CTL or ALT character
                                             
           .If <ES:[SI].Char3 eq 7>          ; If char 3 is a 7, extended accent
              Mov CL,0                       ; CL=0, char5 is only for ex accent use
                                             ; in this case.
           .Endif                            ; Endif
            Pop SI                           ; 
                                             ;             Put the CtlFlag
            Test DL,CtlFlag                  ; check first, THEN NormalAlt check
           .If <nz>                          ; If its the CTL key
               Mov BX,CtlAcChar              ; So get Ctl-Accent offset.
           .Endif
            Test [DI].XKeyFlags,NormalAlt    ; Check if it's not the AltGraph
           .If <nz>                          ; If alt key is normal Alt
               Mov BX,AltAcChar              ; So get Alt-Accent offset.
           .Endif                            

            Xor  CH,CH                       ; Make accent number a word.
            Dec  CX                          ; Accent 1 is offset zero.
            IMul CX,AccEntryLen              ; Set offset of accent table entry.
            Add  CX,Accents                  ; Add offset of accent entries.
            Add  CX,BX                       ;  Add offset for Ctl or Alt
                                             ;  accent
            Mov  BX,SP                       ; Point to stack.
            Add  CX,SS:[BX]                  ; Point into translate table.
            Mov  BX,CX                       ; Put pointer in base reg.
            Mov  BX,Word Ptr ES:[BX]         ; Fetch char and scan.
            Or   BX,BX             ; Check if a Scan/Char mapping for this key.
           .If <z>                           ; Is there?
               Jmp NoXlate                   ; No, so go mark untranslated.
           .Endif                            ; Else, use the mapping.
            Mov Word Ptr [SI].Key.XChar,BX   ; Put them into Key.
                                             
            Call AccCheckout                 ; Go check if accent combo going on
            Jmp  EndActionCase               ; Quit now.
         .Endif
                                             
          Mov BL,0                           ; indicate that CapsTogl has no
                                             ; affect on this key.
          push  bx                           
          mov   bx,sp
          mov   bx,ss:[bx+2]
          mov   bx,es:[bx].XTFlags1          ; get the XT header flags
          test  bx,ShiftLock                 ; Shiftlock keyboard?
          pop   bx
          jz    nocaps

          mov   bl,CapsTogl                  ; nope... so do caps check
nocaps:                                      ; 
          Call CapsCheck                     ; Determine shifting of character.

ShiftAccent:                                 ; Merge here for accent process
         .If <nz>                            ; If we should shift
            Mov CL,CH
         .Endif
         .If <CL a 7>                        ; Is translate table entry
                                             ;  actually a character
            Mov [SI].Key.XChar,CL            ; Put character in CDR

            .IF <bit [SI].DDFlags z KeyBreak>  
               Call AccCheckOut                ; Go check if accent combo
            .ENDIF                             

            Jmp EndActionCase          ;Go to bottom of Xlate Action case table.

         .Else                               ; Else actually an accent
            Or CL,CL                         ; check if accent defined.
           .If <z>                           ; Is it?
              Jmp NoXlate                    ; No, so go mark undefined.
           .Endif
            Xor CH,CH                        ; Make accent number a word.
            Mov BL,[DI].XlateFlags           ; Get the translation flags
            And BL,PrevAccent                ; Clear all bits but previous
                                             ;  accent number (in BL)
            Mov AL,CL                        ; Save accent number
           .If <BL eq CL> AND                ; If this is same accent number
                                             ;  as last time AND
            Test [SI].DDFlags,KeyBreak       ; Check if this is a BREAK
           .If <z> AND                       ; AND it is not a break

            Push SI                          ; 
            Mov  SI,StkTmpReg                ; 
            Mov  BX,ES:[SI].XlateOp          ; Get accent flags
            Pop  SI                          ; 
            Mov  CL,7                        ; Set highest accent number
            Sub  CL,AL                       ; Subtract actual accent number
            Shl  BX,CL                       ; Put accent flag in high bit
           .If <s>                           ; AND if an accent is defined
              Mov  DX,[SI].Key.Shift         ; Get current shift from Key.
              Call AccCheckOut               ; Go process this key
           .Endif
                                        ;Indicate this is an unprocessed accent.
            Or   [SI].DDFlags,AccentKey
            Test [SI].DDFlags,KeyBreak       ; Check for the key BREAK.
           .If <z> NEAR                      ; Is it?
              And [DI].XlateFlags,Not PrevAccent  ; No, clear prev accent
              Or  Byte Ptr [DI].XlateFlags,AL     ; Save accent number for next
                                                  ;  key.
              ;DCR 1546
              Mov [DI].XAccent, 0                 ;Clear Extended Accent number
             .If < al eq 7>                       ;If char 3 is a 7
                Push AX                           ;We have an extended accent
                Push SI                           ; 
                Mov  SI,StkTmpReg                 ; 
                Mov  AL,ES:[SI].Char5             ;Get char 5 Accent Index
                Pop  SI                           ; 
                Mov  Byte Ptr [DI].XAccent,AL     ;Put in Xtended accent field
                Pop  AX                           ; 
             .Endif
           .Endif
            Jmp EndActionCase          ;Go to bottom of Xlate Action case table.
         .Endif
SysReq:                                ;The system request key.

              ;* the PrtScr key on an Enhanced Keyboard
              ;* sends the SysReq scan code if the Alt Key is down
              ;* which it must be for the Print Buffer flush key combo
              ;* (Ctl-Alt-PrtScr).  Therefore we must check for it here.

          Push DS                              ; Make sure that we are using
          Mov  DS, StkDS                       ; the PKBD's DS here.
          Test MiscFlags,EnhancedKbd           ; Check if enhanced kbd
          Pop  DS                              
         .If <nz> AND                          ; If it is AND....
          Test [SI].DDFlags,KeyBreak           ; Check if this is a break
         .If <z> AND                           ; ...AND If it's NOT (a make)
          Test DL,AltFlag                      ; Check if Alt key down.
         .If <nz> AND                          ; If it is AND....
          Test DL,CtlFlag                      ; Check if Ctl key is down
                                               ; for this KCB
                                               
         .If <nz> OR                           ; Is it  OR?
          Test [DI].XHotKeyShift,CtlFlag       ; Also check interrupt shift
                                               ; state
         .If <nz>                              ; Is it being held down at all
                Or [SI].Key.Shift,CX
                Or [DI].XHotKeyShift,CX        ; Also set hot key shift state
                Or [SI].DDFlags,PrintFlushKey  ; Indicate Flush Prt buf
                Jmp EndActionCase              ; Go to bottom of Xlate Action
                                               ; case table.
         .Else                                 
                Or [SI].DDFlags,SysReqKey      ; Indicate this is SysReq key
         .Endif


ShiftKeys:                                    ; LSHIFT, RSHIFT, and CTL keys.
AltKey:                                       ; And the ALT key.
          Test [DI].XlateFlags,E1Prefix       ; CHeck if scan code proceeded
         .If <nz> AND                         ; by E1, if so AND
          Test CX,CtlFlag                     ; check if this is Ctrl key
         .If <nz>                             ; AND if it is Ctrl
              Test [SI].DDFlags,KeyBreak      ; Check if this is a break
             .If <z>                          ; if it is not
                Or [DI].XlateFlags,PseudoCtl  ; Flag this as not actually
                                              ; a Ctrl key but a code
                                              ; sent by Enhanced Kbd
             .Endif
              Jmp NoXlate                     ; Mark key packet undefined
         .Endif
                                              
                                              ; Setup alternate shift bits
                                              ; before checking for MultiMake.
          Mov  BX,SP                          ; Point to stack.
          Mov  BX,SS:[BX]                     ; Put XlateTable offset into reg.
          Mov  BX,ES:[BX].XTFlags1            ; Get the XT header flags
          Push SI                             ; 
          Mov  SI,StkTmpReg                   ; 
          Mov  AH,ES:[SI].Char3               ; Get alternate shift from entry.
          Pop  SI                             ; 
          Test [SI].DDFlags,SecondaryKey      ; Check if G keyboard dup key.
         .If <nz>                             ; Is it?
            Test CX,RShiftFlag+LShiftFlag     ; Is the key a shift key
           .If <nz>                           ; If so....

            ;*If it is then this is coming from a "G" keyboard secondary
            ;*pad key, and NUMLOCK is on.  This combination sends
            ;*the following scan codes:  E0, left shift make, E0,
            ;*pad key make, E0, pad key break, E0, left shift break.
            ;*In this case, we don't want to change the shift flags
            ;*anywhere.

              Jmp NoXlate                       ;@@ Mark key packet undefined
           .Endif                             ;@@ Endif shift key

            Xchg CH,AH              ;Yes, so swap shift bit mask with alternate.
         .Endif                               
                                              
          Test [SI].DDFlags,KeyBreak          ; Check if this is a MAKE
         .If <z>                              ; If it is
             Test Byte Ptr [DI].XHotKeyShift+1,CH ; Check if this key down
                                              ; In the system already
                                              ; for Ctl and Alt
            .If <nz> OR                       ; If it is OR
             Test CX,RShiftFlag+LShiftFlag    ; Is the key a shift key
            .If <nz> AND                      ; If so AND....
             Test [SI].DDFlags,SecondaryKey   ; And if this is NOT a secondary
            .If <z> AND                       ; shift key code sent by a pad
                                              
             Test Byte Ptr [DI].XHotKeyShift,CL ; Check if this key down
            .If <nz>                          ; If it is
                                              ; In the system already
                                              
                                      ; flag as shift key also, do not put in KIB.
                Or [SI].DDFlags,MultiMake+ShiftMask ; Indicate so and do not
                                              ; update shift state.
                                              
                Jmp EndActionCase             ; Complete translation
            .Endif                            ; Endif this is a multimake
         .Endif                               ; Endif this is a key make
                                              

          Test CX,RShiftFlag+LShiftFlag+SysRqFlag   ; Is the key other...
         .If <nz>                                   ; ...than Ctl or Alt?
            And [DI].XKeyFlags,NOT DumpKeyOnce      ; Cancel Dump sequence.
         .Endif
          Or   [SI].DDFlags,ShiftMask         ; Indicate this is a shift key.
          Test BX,ShiftLock                   ; ShiftLock keyboard?
         .If <nz> AND                         ; Is it shift lock and...
          Test BX,ShiftToggle                 ; ShiftToggle Kbd?
         .If <z> AND                          ; Is it NOT shift toggle and..
          Test CL,RShiftFlag+LShiftFlag       ;...is this key one of..
         .If <nz> AND                         ;     ...two shift keys?
          Test [SI].DDFlags,KeyBreak          ; Check for the key BREAK.
         .If <z>                          ; If not, make sure ShiftLock is off.
            And DL,Not CapsTogl               ; Turn it off.

            ;* Turn it off in the interrupt driven shift state for
            ;* hot keys also

            And Byte Ptr [DI].XHotKeyShift+1,Not CapsTogl
         .Endif
          Test [SI].DDFlags,KeyBreak          ; Check for the key BREAK.
         .If <z>                              ; Is it?
            Test CX,DX                        ; No, its a MAKE
           .If <nz>                           ; So check if we've seen it
              Or [SI].DDFlags,MultiMake       ; If we have, indicate so.
           .Endif                             ; Endif Multimake
            Or DX,CX             ;No, so make sure this shift key's flag is set.
            Or [DI].XHotKeyShift,CX           ; Also set hot key shift state
         .Else                                ; Else process key-break.
           .If <AL eq AltFlag>                ; Check is this the AltKey?
                Xor  AL,AL                    ; Clear out a reg
                Xchg AL,[DI].XAltKeyPad       ; Swap with ALT-nnn accumulator.
                Or   AL,AL                    ; Check if accumulation going on.
               .If <nz>                       ; Was there?
                  Mov  [SI].Key.XChar,AL      ; Yes so make a Char from total.
                  Mov  [SI].Key.Scan,0        ; And make the scan code zero.
                                              
                  Test [SI].DDFlags,SecondaryKey ; If this isn't an AltPad seq.
                 .If <z>                      ; with right (secondary) Alt key.
                    And [SI].DDFlags,Not (KeyBreak+KeyTypeMask)  ;Fix flags.
                 .Else
                    Push DS                   ; Make sure that we are using
                    Mov  DS, StkDS            ; the PKBD's DS here.
                    Mov  Byte Ptr NumPadAccum,AL
                    Pop  DS
                                              ; Indicate translation requires
                                              ; 3rd packet with NumPadAccum
                 .Endif                       ; for this Alt-Numpad combo.
                  Or   [DI].XSpecFlags,UseTwoAlt + UseTwoPac
                                             
                  Call AccCheckout           ; check if accent combo going on.
                                             
               .Endif                        ; Endif accumulation going on
           .Endif                            ; Endif this was an ALT key
            Mov BX,CX                        ; Save shift key values
            Not CX                           ; Make shift flags into a mask.

     ;*Topview does not send cursor key scan codes through
     ;*and if this is a Ferrari keyboard, we only get E0s from the
     ;*secondary cursor keys.  Then if the left ALT is pressed
     ;*to remove the popup, we think the ALT make was actually
     ;*the right alt make because it was preceded by an E0 from a
     ;*cursor key. And the break does not clear things up.

              Test BL,RShiftFlag+LShiftFlag  ;...is this key one of..
             .If <z>                         ;     ...two shift keys?
                Test DH,BH                   ; Check if this key is actually
                                             ; the one that's down
               .If <z>                       ; If it isn't
                  And DH,CL                  ; Clear bit for key actually down
               .Else                         ; Else we've got the right key
                  And DH,CH          ;Clear upper byte shift flag for shift key.
               .Endif
                Test DH,AH                   ; Check if other shift key is down.
               .If <z>               ;Is primary or secondary shift key still down?
                  And DL,CL                  ; No so clear lower byte shift flag.
               .Endif

         ;* A system wide word for the shift state
         ;* must be maintained that is only modified by interrupts
         ;* and is only used for Hot Key Checking

                Push DX                     ; Save new key packet shift
                Mov  DX,[DI].XHotKeyShift   ; Get hot key shift state
                Test DH,BH                  ; Check if this key is actually
                                            ; the one that's down
               .If <z>                      ; If it isn't
                  And DH,CL                 ; Clear bit for key actually down
               .Else                        ; Else we've got the right key
                  And DH,CH   ;Clear upper byte shift flag for this shift
               .Endif
                Test DH,AH                  ; Check if other shift key is down.
               .If <z>        ;Is primary or secondary shift key still down?
                  And DL,CL                 ; No, so clear lower byte shift flag.
               .Endif
                Mov [DI].XHotKeyShift,DX
                Pop DX
             .Else
                And DL,CL             ;No, so clear lower byte shift flag.
                And Byte Ptr [DI].XHotKeyShift,CL
             .Endif
         .Endif
          Mov [SI].Key.Shift,DX           ; Also save in Key rec.

          Test [DI].XSpecFlags, UseTwoAlt ; Check to see if an
                                          ; Alt-Num operation was completed.
         .If <nz>                         ; If so then..
            Call AltPadPacket             ; setup second of two packets for
                                          ; Alt-Numpad sequence.
         .Endif

          Jmp EndActionCase               ; Go to bottom of Xlate Action case table.

ScrollLock:                               ; The SCROLL LOCK key.

         ;* This is special case of ToggleKeys because of Ctl-Break.
         ;* On an Enhanced keyboard, the Ctl-Break sends the following
         ;* set of scan codes:
         ;* Ctrl make-E0-ScrollLock make-E0-ScrollLock break-Ctrl break
         ;* so we must check if it was an AT keyboard or preceded by EO
         ;* before identifying it as Ctl-Break.

          And  [DI].XKeyFlags,NOT DumpKeyOnce ; Cancel Dump sequence.
          Test [DI].XKeyFlags,SecPrefix       ; Check if secondary key
         .If <nz> OR                          ; If it is OR...
          Push DS                             ; Make sure that we are using
          Mov  DS, StkDS                      ; the PKBD's DS here.
          Test MiscFlags,EnhancedKbd          ; Check if enhanced kbd
          Pop  DS                             
         .If <z>  OR                          ; OR...If it's a regular kbd
          Push DS                             
          Mov  DS, StkDS                      ; the PKBD's DS here.
          Test IDFlags, SuperSport            ; Check if 122 key SuperSport Kbd
          Pop  DS                             ; Restore caller's DS.
         .If <nz>                             ; If it is...
            Test DL,CtlFlag                   ; Check if Ctl also pressed.
                                              ; for this KCB
                                              
           .If <nz> OR                        ; Is it  OR?
            Test [DI].XHotKeyShift,CtlFlag    ; Also check in interrupt shift
                                              ;   state
           .If <nz>                           ; Is it being held down at all
                                              
              Mov [SI].Key.Scan,0             ; Set Ctl-Break extended code.
                                              ; Tell dev driver  BREAK KEY.
              Or   [SI].DDFlags,BreakKey      ; 
              Test [SI].DDFlags,KeyBreak      ; Check if this is the key break.
             .If <nz>                         ; If so, clear Scroll Lock
                                              ; down bit in Packet & PSG.
                And Byte Ptr [SI].Key.Shift+1,Not (ScrollFlag ShR 8)
                                              ; Clear bit in hot key shift
                                              ; status also
                And Byte Ptr [DI].XHotKeyShift+1,Not (ScrollFlag ShR 8)
             .Else                            ; Set Scroll Lock down bit
                                              ; in packet & PSG.
                Or Byte Ptr [SI].Key.Shift+1,(ScrollFlag ShR 8)
                                              ; Set bit in hot key shift
                                              ; status also
                Or Byte Ptr [DI].XHotKeyShift+1,(ScrollFlag ShR 8)
             .Endif
              Jmp EndActionCase               
           .Else                              ; Not Ctl-Break, fall thru
                                              ; to ToggleKey processing.
              Jmp ToggleKey
           .Endif
         .Else                                ; Not Ctl-Break, fall thru to
                                              ; ToggleKey processing.
            Jmp ToggleKey
         .Endif

NumLock:                                      ; The NUMLOCK key.

          ;* We must check if this is the Enhanced keyboard
          ;* which will emulate Ctrl being down (PseudoCtl Flag
          ;* will be set) for the PAUSE key or an AT kbd w/ Ctl down.

          Test [DI].XlateFlags,PseudoCtl   ; Check if secondary kbd
                                           ; emuating the Ctl key
         .If <nz> OR                       ; If it is OR...
                                           
          Push DS                          
          Mov  DS, StkDS                   ; the PKBD's DS here.
          Mov  BX, KbdHWIDs
          Pop  DS                          
          Ror  BX, 8                       
         .If <BX ne FERRARI_G> AND         ; If it's not a 101/102 AND
         .If <BX ne JAGUAR> AND            ; If it's not a 122 Key JAGUAR
                                           
          Test DL,CtlFlag                  ; Check if Ctl also pressed.
                                           ; for this KCB
                                           
         .If <nz> OR                       ; Is it  OR?
          Test [DI].XHotKeyShift,CtlFlag   ; Also check in interrupt shift
                                           ;   state
         .If <nz>                          ; Is it being held down at all
                                           
                                           
            Test DL, AltFlag               ; Check for Alt key down.
           .If < z >                       ; No alt key, process Ctl-NumLk,
              Test [SI].DDFlags,KeyBreak   ; Check if this is a key break
             .If <nz>
                And [DI].XlateFlags,Not PseudoCtl ; Clear flag

                Test [DI].XlateFlags,PauseSt  ; If the NumLock
                                              ; make preceded the Ctrl make
               .If <z>                        ; then this is not the break of
                                              ; of a Pause.  Therefore do not
                                              ; throw the key away. Treat it
                   Jmp ToggleKey              ; as a normal shift break.
               .Endif                         ; Endif this was not the Pause.
                And [DI].XlateFlags,Not PauseSt ; Reset the Pause sequence flag.
                Jmp NoXlate                 ; Mark Key Packet undefined
             .Else                          ; Else it's a make scan code
                Or [SI].DDFlags,PauseKey    ; So tell dd it's the PAUSE KEY.
                Or [DI].XlateFlags,PauseSt  ; Flag the make of the
                Or [DI].XlateFlags,SGPaused
                                            ; NumLock to be used as a latch.
                Jmp EndActionCase           ; Completed translation
             .Endif                         ; Endif key break or not
           .Else                            
              And  [DI].XlateFlags,Not PseudoCtl ; Clear flag
              Test DL,CtlFlag               ; so test if Ctrl is also down.
             .If <z>                        ; If Ctrl is not down then the
                Jmp NoXlate                 ; key sequence Alt-Pause Key
                                            ; is undefined.
             .Endif                         ; Endif Ctrl is down with Alt.
           .Endif                           ; End alt key down check.
         .Endif                             
          Test DL,CtlFlag                   ; Check if Ctl also pressed.
                                            ; for this KCB
                                            
         .If <nz> OR                        ; Is it  OR?
          Test [DI].XHotKeyShift,CtlFlag    ; Also check in interrupt shift
                                            ;   state
         .If <nz>                           ; Is it being held down at all
                                            
            Test DL,AltFlag                 ; Yes, check Alt key also.
           .If <nz>                         ; Is it?
              Test [DI].XKeyFlags,DumpKeyOnce ; Yes check if second time.
             .If <nz>                       ; Is it?
                Or [SI].DDFlags,DumpKey     ; So tell dd it's the DUMP KEY.
             .Else
                Test [SI].DDFlags,KeyBreak  ; Check if this's key break.
               .If <nz>                     ; Is it?
                  Or [DI].XKeyFlags,DumpKeyOnce ; Yes indicate seen once.
               .Endif
             .Endif
           .Endif
            Test [SI].DDFlags,KeyBreak      ;Check if this's the key break.
           .If <nz>                         ;If so, clear Num Lock down
                                            ; bit in Packet & PSG.
              And Byte Ptr [SI].Key.Shift+1,Not (NumFlag ShR 8)
                                            ; Clear bit in hot key shift
                                            ; status also
              And Byte Ptr [DI].XHotKeyShift+1,Not (NumFlag ShR 8)
              Test [DI].XKeyFlags,DumpKeyOnce
             .If <z>                        ; If this wasn't the dump key
                 Or [SI].DDFlags,ShiftMask  
                                            ; Indicate this is a shift key.
             .Endif

              Test [DI].XlateFlags,PauseSt  ;  If the NumLock
                                            ; make preceded the Ctrl make
             .If <z>                        ; then this is not the break of
                                            ; of a Pause.  Therefore do not
                                            ; throw the key away. Treat it
                 Jmp ToggleKey              ; as a normal shift break.
             .Endif                         ; Endif this was not the Pause.
              And [DI].XlateFlags,Not PauseSt ; Reset the Pause sequence flag.

           .Else                            ;Set Num Lock down bit in packet
                                            ;  & PSG.
              Or Byte Ptr [SI].Key.Shift+1,(NumFlag ShR 8)
                                            ; Set bit in hot key shift
                                            ; status also
              Or Byte Ptr [DI].XHotKeyShift+1, (NumFlag ShR 8)
              Test [DI].XKeyFlags,DumpKeyOnce
             .If <z>                        ; If this wasn't the dump key
                 Or [SI].DDFlags,ShiftMask  
                                            ; Indicate this is a shift key.
             .Endif
              Or [DI].XlateFlags,PauseSt    ; Flag the make of the
                                            ; NumLock to be used as a latch.
           .Endif

         .Else NEAR                         ; Not Ctl-Numlock, fall thru
                                            ; to common Toggle key check.

CapsLock:                                   ; The CapsLock key itself.
ToggleKey:                                  ; Or any general Toggle key.
            Mov  BX,SP                      ; Point to stack.
            Mov  BX,SS:[BX]                 ; Get translate table offset.
            Test [SI].DDFlags,SecondaryKey  ; Check if G kbd dup key.
           .If <nz>                         ; Is it?
              Push SI                       ; 
              Mov  SI,StkTmpReg             ; 
              Mov  CH,ES:[SI].Char3         ; Yes, so get mask for that key.
              Pop  SI                       ; 
           .Endif
            And  [DI].XKeyFlags,NOT DumpKeyOnce       ; Cancel Dump sequence.
            Or   [SI].DDFlags,ShiftMask               ; Indicate this is shift key.
            Test Word Ptr ES:[BX+XTFlags1],ShiftLock  ; ShiftLock type?
           .If <nz> AND                               ; Is it shift lock and...
            Test Word Ptr ES:[BX+XTFlags1],ShiftToggle; ShiftLock Toggle?
           .If <z> AND                                ; Is it shift lock latch and...
           .If <AL eq CapsTogl>                       ;.is it the CapsLock key?
              Test [SI].DDFlags,KeyBreak              ; Check for the key BREAK.
             .If <z>                                  ; If not, set ShiftLock on.
                Or [SI].Key.Shift,CX                  ; And in the Key rec.
                Or [DI].XHotKeyShift,CX               ; Set bit in hot key shift
                                                      ; status also
             .Else                                    ; On key-break, only clear
                                                      ;  DOWN bit.
                Not CX                                ; Make shift bits a mask.
                And Byte Ptr [SI].Key.Shift+1,CH      ; And in the Key rec.
                And Byte Ptr [DI].XHotKeyShift+1,CH   ; Clear bit in hot key
                                                      ;  shift status also
             .Endif
           .Else                             ; This is not a shift-lock keyboard.
              Test [SI].DDFlags,KeyBreak              ; Check for the key BREAK.
             .If <nz>                                 ; Is it?
                Not CX                       ; Yes, so make shift bits a mask.
                And Byte Ptr [SI].Key.Shift+1,CH      ; And in the Key rec.
                And Byte Ptr [DI].XHotKeyShift+1,CH   ; Clear in hot key shift
                                                      ;  status also
                And [DI].XKeyFlags,CL                 ; Clear latch for this key.
             .Else
                Or Byte Ptr [SI].Key.Shift+1,CH       ;And in the Key rec.
                Or Byte Ptr [DI].XHotKeyShift+1,CH    ; Set bit in hot key
                                                      ;  shift status also
                Test [DI].XKeyFlags,CL                ; Check if seen this key yet.
               .If <z>                                ; Have we?
                  Or [DI].XKeyFlags,CL                ; No so set latch.
                  Xor Byte Ptr [SI].Key.Shift,CL      ; And in the Key rec.
                  Xor Byte Ptr [DI].XHotKeyShift,CL   ; Set Latch in hot key
                                                      ; shift status also
               .Else                                  ; Otherwise this is a repeat
                                                      ; of the make.
                  Or [SI].DDFlags,MultiMake           ; So indicate so.
               .Endif
             .Endif
           .Endif
         .Endif                                  ; Endif from NumLock plus Ctl
                                                 ; test above.
          Jmp EndActionCase                      ; Go bottom of Xlate Action
                                                 ;  case table.

SpecKeyCS:                                       ; Special key for NLS support.
          Call UnPauseChk                        ; Go check if in pause state.
          Test DL,AltFlag                        ; Check if Alt key down.
         .If <nz>                                ; Is it?
            And  [DI].XlateFlags,Not Use3Index   ; Use Char3 if AltGraph
            Call AltGraphCheck                   ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt    ; Check if it's not the AltGraph
           .If <nz>                          ; If alt key is normal Alt
                                             
                Call CheckExtended           ; See if new extended code
                                             ;  is defined
                .If <c>                      ; If it is ...
                    Jmp EndActionCase        ; the key combo is defined
                .Endif                       ; Endif there was one defined
                 Jmp NoXlate                 ; get out now.
           .Endif                            ; Endif normal Alt.
            Jmp SKCSEnd                      ; 
         .Else NEAR                          ; Else no Alt key down
            Push SI                          ; 
            Mov  SI,StkTmpReg                ; 
            Test DL,RShiftFlag+LShiftFlag    ; Is a shift key down
           .If <nz>                          ; Yes so,
               Test DL,CapsTogl              ; See if capslock is on
              .If <nz>                       ; If it is
                 Mov AL,ES:[SI].Char5        ; Use character 5
              .Else                          ; If it is not then...
                 Mov AL,CH                   ; Use char 2
              .Endif                         ; Endif CapsLock is on.
           .Else NEAR                        ; Else no shift key down
               Test DL,CapsTogl              ; See if capslock is on
              .If <nz>                       ; If it is
                 Mov AL,ES:[SI].Char4        ; Use character 4
              .Endif
           .Endif                            ; Endif shift key down.
            Pop  SI                          ; 
            Test DL, CtlFlag                 ; Check if Ctrl is down,
           .If <nz>                          ; If it is then...
               Call SKCtlCheck               ; Check for spec. Ctrl code.
           .Endif                            ; Endif Ctrl is down.
         .Endif                              ; Endif Alt is down.
SKCSEnd:
         .If <AL b 8> AND                    ; If this was an accent key index
         .If <AL a 0>                        ; 
            Or   [SI].DDFlags,AccentKey      ; Indicate this is an
                                             ; unprocessed accent.
            Test [SI].DDFlags,KeyBreak       ; Check for the key BREAK.
           .If <z>                           ; Is it?
              And [DI].XlateFlags,Not PrevAccent ; No, clear prev accent num
              Or  Byte Ptr [DI].XlateFlags,AL    ; Save accent num for next key
           .Endif
         .Else                               ; Else this not an accent table entry
            Mov  [SI].Key.XChar,AL           ; Put character into key packet
            Call AccCheckOut                 ; Check for valid accent
         .Endif                              ; Endif this is an accent index.
          Jmp EndActionCase                  ; Go to bottom of Xlate case table.

SpecKeyAS:                                   ; Special key for NLS support.
          Call UnPauseChk                    ; Go check if in pause state.
          Test DL,AltFlag                    ; Check if Alt key down.
         .If <nz>                            ; Is it?
            And  [DI].XlateFlags,Not Use3Index  ; Use Char3 if AltGraph
            Call AltGraphCheck               ; Process if AltGraph
            Test [DI].XKeyFlags,NormalAlt    ; Check if it's not the AltGraph
           .If <nz>                          ; If alt key is normal Alt
              Push SI                        ; 
              Mov  SI,StkTmpReg              ; 
              Mov  AL,ES:[SI].Char4          ; Use char4
              Pop  SI                        ; 
              Mov  [SI].Key.Scan,AL          ; Put it in scan code field.
              Jmp  SpecKeyEnd                ; Go to merge
           .Endif
         .Else                               ; Else no Alt key down
            Test  DL,RShiftFlag+LShiftFlag   ; Is a shift key down
           .If <nz>                          ; Yes so,
                 Mov AL,CH                   ; Use char 2
                 Jmp SpecKeyEnd              ; Go to merge
           .Endif                            ; Else no shift key down
         .Endif                              ; Endif Alt key down.
          Test DL, CtlFlag                   ; Check if Ctrl is down
         .If <nz>                            ; If it is then...
             Call SKCtlCheck                 ; Check for special control code.
         .Endif                              ; Endif Ctrl is down

SpecKeyEnd:
         .If <AL b 8> AND                    ; If this was an accent key index
         .If <AL a 0>
            Or [SI].DDFlags,AccentKey        ; Indicate this is an
                                             ; unprocessed accent.
            Test [SI].DDFlags,KeyBreak       ; Check for the key BREAK.
           .If <z>                           ; Is it?
              And [DI].XlateFlags,Not PrevAccent ; No, clear prev accent num
              Or  Byte Ptr [DI].XlateFlags,AL    ; Save accent num for next key
                                                 
              Mov [DI].XAccent, 0             ; Clear Extended Accent number
             .If < al eq 7>                   ; If char 3 is a 7
                Push AX                       ; We have an extended accent
                Push SI                       ; 
                Mov  SI,StkTmpReg             ; 
                Mov  AL,ES:[SI].Char5         ; Get char 5 Accent Index
                Pop  SI                       ; 
                Mov  Byte Ptr [DI].XAccent,AL ; Put in Xtended accent field
                Pop  AX                       ; 
             .Endif                           ; 
           .Endif
         .Else                       ; Else this is not an accent table entry
            Mov  [SI].Key.XChar,AL   ; Put character into key packet
            Call AccCheckOut         ; Check for vaild accent.
         .Endif                      ; Endif this is an accent table entry.
          Jmp EndActionCase          ; Go to bottom of Xlate Action case table.


                                                
XXKey:                                          ; EXtended EXtended Key Case
          Call UnPauseChk                       ; Go check if in pause state.
         .If <bit DL nz AltFlag>                ; If Alt key pressed
            And  [DI].XlateFlags,Not Use3Index  ; Clear Use3Index
            Call AltGraphCheck                  ; Process if AltGraph
           .If <bit [DI].XKeyFlags nz NormalAlt>; If key is normal Alt key
              Push SI                           ; Save keypacket offset
              Mov  SI,StkTmpReg                 ; Get Translate Table Char offset
              Mov  CL,ES:[SI].Char5             ; Get  CHAR5
              Pop  SI                           ; Restore keypacket offset
              Mov  [SI].Key.Scan,CL             ; Put  CHAR5  in scan code field
           .Endif                               ; Endif normal Alt key
         .Elseif <bit DL nz CtlFlag>            ; If Ctrl Key is pressed
            Push SI                             ; Save keypacket offset
            Mov  SI,StkTmpReg                   ; Get Translate Table Char offset
            Mov  CL,ES:[SI].Char4               ; Get  CHAR4
            Pop  SI                             ; Restore keypacket offset
            Mov  [SI].Key.Scan,CL               ; Put  CHAR4  in scan code field
         .Elseif <bit DL nz RShiftFlag+LShiftFlag>;If Left or Right Shift Key
            Mov  [SI].Key.Scan,CH               ; Put  CHAR2  in scan code field
         .Else                                  ; Else not shifted
            Mov  [SI].Key.Scan,CL               ; Put  CHAR1  in scan code field
         .Endif                                 ; Endif
          Call AccCheckout                      ; Check if accent combo going on
          Jmp  EndActionCase                    ; To bottom of Xlate Action table


XShiftKey:                              ; Extended shift key (for DBCS use).
XToggleKey:                             ; Extended toggle key (for DBCS use).
Reserved:                               
NoXlate:                                ; Invalid action code, no translate done.
  And [DI].XKeyFlags,NOT DumpKeyOnce    ; Cancel Dump sequence.
  Or  [SI].DDFlags,UndefKey             ; Mark this key undefined.


Public EndActionCase
EndActionCase:  ;*** This is the end of the Xlate Action case table ***.

  Test [SI].DDFlags, UndefKey              
 .If <z> AND                               ; This logic tests to see if the
  Test [DI].XSpecFlags, UseTwoAlt          ; current keypacket is for an
 .If <z>                                   ; extended keystroke or not.
     Mov BL,[SI].Key.XChar                 ; If it is then bit 1 of the Status
    .If <BL eq 0> OR                       ; field in the keypacket is turned
     Test [DI].XKeyFlags, SecPrefix        ; on.
    .If <nz>                               ; 
        Or [SI].Key.Status, EXTENDEDCODE   ; Turn the bit on in the Status.
    .Endif                                 ; 
 .Endif                                    
                                           
  Push DS                                  
  Mov  DS, StkDS                           
  Test OtherFlags,InterruptTime            ; If it's interrupt time...
  Pop  DS                                  ; create an extra packet for the E0.
 .If <nz> AND                              
  Test [DI].XKeyFlags,SecPrefix            ; Test to see if an E0 or E1
                                           ; came before this packet.
 .If <nz> AND                              ; If E0 or E1 did precede then,
  Test [DI].XlateFlags, E1Prefix           ; Check to see if it was an E0.
 .If <z>                                   ; If it was the E0 then,
     Call  MakeE0Packet                    ; Call MakeE0Packet to manufacture an
                                           ; extra packet to precede this one.
 .Endif                                    ; Endif an E0 preceded this packet.


  Mov BX,[SI].DDFlags                      
 .If <BX eq ShiftMask> OR                  ; char and scan fields for
 .If <BX eq ShiftMask+KeyBreak> OR         ; shift packets
 .If <BX eq ShiftMask+SecondaryKey> OR
 .If <BX eq ShiftMask+KeyBreak+SecondaryKey>
     Mov Word Ptr [SI].Key.XChar, 0        
                                           ;  Scan Code fields in CharData
                                           ;  Record for Japan compatability.
     And [SI].Key.Status, NOT EXTENDEDCODE
                                           
                                           ; is an extended scan instead of
                                           ; an E0 char., if this is a shift pac.
     Test [DI].XInputMode,SHIFTREPORT      ; (P13303) Are we in Shift rep. mode?
    .If <nz>                               ; If so......
        Or [SI].Key.Status,1               ; Flag as shift report packet
    .Endif                                 ; Endif Shift Report
 .Endif                                    ; Endif Shift Report
  And [DI].XlateFlags,Not E1Prefix         ; Clear indicator.
  And [DI].XKeyFlags, Not SecPrefix
  Pop BX                                   ; Fix stack.
  Mov AL, Byte Ptr [SI].KPacketLen+1       ; Restore scan code in AL.
  Sti                                      ; Restore ints disabled by PhysToVirt.
  Pop BP                                   ; Fixup stack
  Ret

KbdXlate Endp

Public  CapsCheck
CapsCheck Proc

;************** START OF SPECIFICATIONS ******************************
;*
;* FUNCTION NAME  CapsCheck
;*
;* DESCRIPTION    Check IF character should be shifted
;*
;*                This routine checks IF a characer should be shifted.
;*                It checks IF CapsLock, ShiftLock or the shift key
;*                effect this key.  IF the char should be shifted,
;*                then it places Char2 in AL.
;*
;*
;* INPUT          AL = CHAR1 from translate table
;*                CH = CHAR2 from translate table
;*                DX = ShiftFlags
;*                AH = Scan code w/ break bit cleared
;*                BX = SHIFTLOCK & CAPSLOCK effect indicators
;*
;* Exit-Normal   AL = ASCII character after shift checking
;*
;* Exit-Error    None
;*
;* Effects      AX, BX, registers, carry flag changed.
;*
;*
;*********************************************************************

   Xor  BH,BH                            ; Prepare a byte.
   Test DL,RShiftFlag+LShiftFlag         ; Check if Shift key down.
  .If <nz>                               ; Is one of them?
     Or   BH,CapsTogl                    ; Yes, so prepare to check Capslock.
     Push BX                             
     Push DS                             ; 
     Mov  DS, StkDS                      ; 
     Mov  BX,SP                          ; Get Xlate table header
     Mov  BX,SS:[BX+6]                   ; And put it in BX
    .If <bit ES:[BX].XTFlags1 nz LayeredTbl>    ; If codepage has Secondary Layer
                                         ; DONT TOUCH THAT DIAL! - EXCEPTION!
                                 ; This means we have ARABIC or HEBREW country
                                 ; CAPS MUST HAVE NO EFFECT IN THESE COUNTRIES
       Mov AL,CH                         ; Use Char2.
    .Endif                               ; 
     Pop DS                              ; 
     Pop BX                              ; 
  .Else                                  ; Endif a shift key is down
     Push BX                             ; 
     Push DS                             ; 
     Mov  DS, StkDS                      ; 
     Mov  BX,SP                          ; Get Xlate table header
     Mov  BX,SS:[BX+6]                   ; And put it in BX
                                         ; 
    .If <bit ES:[BX].XTFlags1 nz LayeredTbl>   ; If codepage has Secondary Layer
                                ; DONT TOUCH THAT DIAL! - EXCEPTION!
                                ; This means we have ARABIC or HEBREW country
                                ; CAPS MUST HAVE NO EFFECT IN THESE COUNTRIES
       Pop DS                            ; 
       Pop BX                            ; 
       Ret                               ; 
    .Endif                               
                                         ; 
     Pop DS                              ; 
     Pop BX                              ; 
  .Endif                                 ; 
   And  DL,BL                            ; Isolate Capslock flag.
   Push BX                               ; Save BX for now
   Mov  BX,SP                            ; Get Xlate table header
   Mov  BX,SS:[BX+4]                     ; And put it in BX
   Test ES:[BX].XTFlags1,ShiftLock       ; Check if Shiftlock  kbd
   Pop  BX                               ; Restore BX
  .If <nz>                               ; If it is then...
     Test BL, CapsTogl                   ; Check if shift lock effects key type.
    .If <nz>                             ; If it does then...
       Or BH,DL                          ; either Capslock, Shift,
                                         ; or both will cause shifting
    .Else                                ; If it does not
       Or BH,BH                          ; fix the zero flag.
    .Endif                               ; Endif shift lock effects key type.
  .Else                                  ; Else its a CapsLock kbd
     Test BL, CapsTogl                   ; Check if CapsLock effects key type.
    .If <nz>                             ; If it does then...
       Xor BH,DL                         ; Add Capslock & ShiftFlag to decide state.
    .Else                                ; If it does not
       Or BH,BH                          ; fix the zero flag.
    .Endif                               ; Endif CapsLock effects key type.
  .Endif                                 ; Endif shift lock keyboard.
  .If <nz>                               ; Should key be capitalized?
       Mov AL,CH                         ; So use Char2.
  .Endif                                 ; 
   Ret

CapsCheck Endp

Public  SKCtlCheck
SKCtlCheck Proc

;***********************************************************************
;*
;* FUNCTION NAME  SKCtlCheck
;*
;* DESCRIPTION    Check IF character has special control code
;*
;*                This routine checks IF a character or scan code has a
;*                special control code associated with it.
;*                IF it does then it sets the appropriate ASCII/scan
;*                codes.
;*
;* NOTES          Ctl key is already known to be down
;*
;* INPUT          AH = Scan code w/ break bit cleared
;*
;* Exit-Normal    AL = ASCII character after special control code check
;*
;* Exit-Error     None
;*
;* Effects:     AX
;*
;*
;**********************************************************************

  .If <AH eq 3>                          ; Is this Ctl-2?
     Xor AL,AL                           ; Yes, so set extended code.
  .ElseIf <AH eq 7>                      ; Is this Ctl-6?
     Mov AL,30                           ; Set ASCII "RS" code.
                                         
  .ElseIf <AH eq 15>                     ; Is this Ctl-Tab?
     Xor AL,AL                           ; Yes, so set extended code.
     Mov [SI].Key.Scan,94h               ; Yes, so set extended code.
                                         
  .ElseIf <AH eq 26>                     ; Is this Ctl-[?
     Mov AL,27                           ; Yes, so set "Esc" code.
  .ElseIf <AH eq 27>                     ; Is this Ctl-]?
     Mov AL,29                           ; Yes, so set ASCII "GS" code.
  .ElseIf <AH eq 43>                     ; Is this Ctl-\?
     Mov AL,28                           ; Yes, so set ASCII "FS" code.
  .ElseIf <AL eq "-">                    ; Is this Ctl-dash?
     Mov AL,31                           ; Yes, so set ASCII "US" code.
                                         
  .ElseIf <AH eq 12>                     ; Is this the key for scan code 12.
     Mov AL,31                           ; Yes, so set ASCII "US" code.
                                         
  .ElseIf <AL eq " ">                    ; Is this the space key?
     ;Value in AL is correct.            ; Yes, so leave as is.
  .Else                                  ; If here, combo is undefined.
     Mov AL, -1                          ; Go mark Undefined.
     Or  [SI].DDFlags,UndefKey           
  .Endif                                 ; 
   Ret                                   ; Endif Ctl key down check

SKCtlCheck Endp

Public  SKAltCheck
SKAltCheck Proc

;***********************************************************************
;*
;* FUNCTION NAME  SKAltCheck
;*
;* DESCRIPTION    Check IF character has extended code
;*
;*                This routine checks IF a characer or scan code has a
;*                special extended code associated with it.
;*                IF it does then it sets the appropriate ASCII/scan
;*                codes.
;*
;* NOTES          Alt key is already known to be down
;*
;*
;* INPUT          DI = Per Session Data Area Address
;*                SI = Key Packet Address
;*                DX = ShiftFlags
;*                AH = Scan code w/ break bit cleared
;*
;* Exit-Normal    AL = ASCII character after special control code check
;*
;* Exit-Error     None
;*
;* Effects        AX, BX, registers, carry flag changed.
;*
;* Internal References:
;*    Routines: AltGraphCheck   CheckExtended
;*
;**********************************************************************

  And [DI].XlateFlags,Not Use3Index     ; Use Char3 if AltGraph
  Call AltGraphCheck                    ; Process if AltGraph
  Test [DI].XKeyFlags,NormalAlt         ; Check if it's not the AltGraph
 .If <nz>                               ; If alt key is normal Alt
   .If <AL eq " ">                      ; Is this the space key?
      Mov [SI].Key.XChar,AL             ; Yes, so leave as is.
                                        
   .Else                                ; Set extended code for others
      Call CheckExtended                ; Go check if this is new extended
                                        ; scan code
     .If <nc>                           ; If it is, everything is set up
                                        ; otherwise it's old so
         Add AH,118                     ; calculate extended code.
         Mov [SI].Key.Scan,AH           ; Put extended code in Key rec.
     .Endif
                                        
   .Endif
 .Else                                  ; else it was AltGraph
    Mov [SI].Key.XChar,AL               ; Yes, so leave as is.
 .Endif                                 ; Endif UNDEFINED or normal ALT
  Ret

SKAltCheck Endp

Public  AccCheckOut
AccCheckout Proc

;**********************************************************************
;*
;* FUNCTION NAME  AccCheckout
;*
;* DESCRIPTION    Check and Process Valid Accents
;*
;*             This routine is called from KbdXlate and checks if an
;*             accent key was hit prior to the current key.  If so,
;*             a check is made to see if the key is affected by that
;*             accent and if it is
;*             the value specified by the accent table entry is put in
;*             the key packet and control returns to KbdXlate.
;*             If the key is not affected by that accent, then it is
;*             put in a seperate keypacket and control returns to
;*             KbdXlate to process the current key.
;*
;* INPUT       Beginning offset of translate table on the stack
;*
;* Exit-Normal Monitor Key Packet filled in
;*
;* Exit-Error  N/A
;*
;* Effects     BX
;*
;* Internal References:
;*    Routines: BadAccent
;*
;**********************************************************************

    ;* Check if last key seen was an accent key.

    Push BX                             ; Save BX
    Mov  BL,[DI].XlateFlags             ; Get flags from PSG.
    And  BL,PrevAccent                  ; Isolate previous accent number
                                        ;  field.
   .If <nz> NEAR                        ;  Was there one?
                                        
     .If < BL eq 7 >                    ; If All bits set, Extended Accent Case
        Mov  BL, Byte Ptr [DI].XAccent  ; Get the Extended Accent number
        Call ExtAccent                  ; Call Ext Accents
        Jmp  AccExit                    ; Get out
     .Endif

      Push CX                           ; Save reg
      Push DI                           ; Yes, save index reg for now.
      Push DX                           ; Save reg
      Push SI                           ; Save other index reg for now.

      ;* Translate table offset now six words back on the stack.

      Xor  BH,BH                        ; Clear upper byte of accent number.
      Mov  DI,BX                        ; Put accent number in index reg.
      Dec  DI                           ; Accent entry 1 has offset zero.
      IMul DI,AccEntryLen               ; Set offset of correct accent
                                        ; table entry.
      Add  DI,Accents                   ; Set offset within overall translate
                                        ; table.
      Mov  SI,SP                        ; Point to stack.
      Add  DI,SS:[SI+12]                ; Add offset of translate table itself.
      Pop  SI                           ; Restore SI.
      Push BX                           ; 
      Mov  BX,StkTmpReg                 ; 
      Mov  DX,ES:[BX].XlateOp           ; Get Xlate Operation word.
      Pop  BX                           ; 
      Mov  CL,7                         ; Set # of bits to highest accent no.
      Sub  CL,BL                        ; Subtract actual accent number.
      Mov  BX,DI                        ; Save accent table entry offset.
      Or   DX,DX                        
                                        ;  max. number of accents are used
                                        ; that the flags bits are set
                                        ; correctly for DX.
      Shl  DX,CL                        ; Shift Accent Flags left by
                                        ; calculated count.
     .If <ns>                           ; So is this key affected by the
                                        ; previous accent?
          Push BX
          Xor  BX,BX                    ; Get XTable start address
          Mov  CX,ES:[BX].XTFlags1      ; Get the XT header flags.
          Pop  BX                       ; Restore accent table offset
          Pop  DX                       ; Restore reg
          Pop  DI                       ; Restore index reg
          Call BadAccent                ; No! Go take care of things.
          Pop  CX                       ; Restore reg
     .Else                              ; Accent flags say this key is accented.
        Pop  DX                         ; Restore shift flags for now.
        Push DX                         ; But leave them saved.
        Push AX                         ; Save AX for now.
        Mov  AL,[SI].Key.XChar          
        Mov  CX,20                      ; Set max pairs in Accent table entry.
        Add  DI,AcMap1                  ; Point to  first pair in accent entry.
TLoop:        ;***Top of loop looking for current scan code in accent table entry.
        Mov  DX,ES:[DI]                 ;Pick up next pair.
       .If <DX eq 0>                    
                                        ; of the list
          Mov CX,1                      ; Set end of loop condition
       .ElseIf <AL eq DL>               ; Else Have we found a match?
          Jmp Short XLoop               ;   Yes, so exit from loop.
       .Endif
        Add  DI,2                       ; Increment our pointer.
        Loop TLoop                      ; Repeat.
XLoop:  Or   CX,CX                      ; Check if no match before end of entry.
       .If <z>                          ; Is that true?
            Push BX
            Mov  BX,0                   ; Get XTable start address
            Mov  CX,ES:[BX].XTFlags1    ; Get the XT header flags.
            Pop  BX                     ; Restore accent table offset
            Pop  AX                     ; Restore the
            Pop  DX                     ;  Regs
            Pop  DI                     ; Restore PSG index
            Call BadAccent              ; No. Go take care of things.
            Pop  CX                     ; Restore reg
       .Else                            ; Else we found our accented
                                        ; character value.
          Mov [SI].Key.XChar,DH         ; Put it in CharData rec.
          Mov [SI].Key.Scan,0           ; Zero scan code for accented chars.
          Or  [SI].DDFlags,AccentedKey  ; Indicate accent affected key.
          Pop AX                        ; Restore
          Pop DX                        ; Regs
          Pop DI                        ; Restore PSG index
          Pop CX                        ; Restore reg
       .Endif
     .Endif
      And [DI].XlateFlags,Not PrevAccent ; Clear previous accent field.
   .Endif

AccExit:
    Pop  BX                             ; Restore BX
    Test [SI].DDFlags,AccentedKey       ; Check if accent affected key.
   .If <nz> OR                          ; Did it?
   .If <[SI].DDFlags e BadKeyCombo>     ; check if this was an invalid combo?
      Pop BX                            ; Throw away original return address.
      Jmp EndActionCase                 ; And quit now.
   .Endif
    Ret                                 ; Else return.

AccCheckout Endp

Public  ExtAccent
ExtAccent  Proc

;**********************************************************************
;*
;*
;* FUNCTION NAME  ExtAccent
;*
;* DESCRIPTION    Check and Process Valid Extended Accents
;*
;*             This code introduced           
;*             to support languages with more than 6 accents.
;*
;*             This routine is called from KbdXlate and checks if an
;*             accent key was hit prior to the current key.  If so,
;*             a check is made to see if the key is affected by that
;*             accent and if it is
;*             the value specified by the accent table entry is put in
;*             the key packet and control returns to KbdXlate.
;*             If the key is not affected by that accent, then it is
;*             put in a seperate keypacket and control returns to
;*             KbdXlate to process the current key.
;*
;* INPUT       BL has Extended Accent Number (range of 7 - 255)
;*             ES is sel of Translate table
;*
;* Exit-Normal Key Packet filled in
;*
;* Exit-Error  N/A
;*
;* Effects     All registered saved
;*
;* Internal References:
;*    Routines: BadAccent
;*
;*
;**********************************************************************


    ;* BL has Extended Accent Number
    ;* ES is sel of Translate table

      Push AX                            ; Save AX for now.
      Push CX
      Push DX
      Push DI

                                         ; Point DI to 7th accent entry:
                                         ; Accent entry 1 has offset zero.
      Mov  di, 6                         ; so use 6 to get to 7th entry.
      IMul DI,AccEntryLen                ; Multiply to get 7th offset.
      Add  DI,Accents                    ; Add offset of Accents in table


      Mov  AL,[SI].Key.XChar             ; Get the character
      Xor  CH,CH                         ; Clear out CH
      Mov  CL, ES:[DI]                   ; Get the length of this Accent entry

      Sub  BL, 7                ; Normalize.(7th entry is 0th Ex Accent Entry)
     .While < BL ne 0 >         ; While I haven't reached the right entry
        Add DI, CX              ; Point to next accent entry
        Mov CL, ES:[DI]         ; Get the length of this Accent entry
        Dec BL                  ; Dec the entry count
     .Endwhile                  ; Endwhile

                                ; DI points to the proper accent table
      Mov BX, DI                ; Save DI in BX for later use.
      Sub CX,7                  ; Make CX = number of accent entries
      Add DI, 7                 ; Adjust DI to point to 1st accent pair
      shr cx, 1                 ; Get cx/2 since we move 2 at a time
AccLoop:                        ; Look for scan code in accent table
      Mov DX,ES:[DI]            ; Pick up accent pair
     .If <AL eq DL>             ; IF we found a match?
        Pop DI                  ; Get xlateflags value in DI
        Jmp FoundAcc            ; Yes, so exit from loop.
     .Endif                     ; Endif
      Add  DI,2                 ; Increment our pointer.
      Loop AccLoop              ; Repeat, loop CX times.
      Pop  DI                   ; Get xlateflags value back in DI

FoundAcc:
      Or CX,CX                       ; Check if no match before end of entry.
     .If <z>                         ; Is that true?
        Push BX                      ; Save accent table offset
        Xor  BX,BX                   ; Get XTable start address
        Mov  CX,ES:[BX].XTFlags1     ; Get the XT header flags.
        Pop  BX                      ; Restore accent table offset
        Inc  BX                      ; Point pass the length value (1st byte).
        Call BadAccent               ; Go take care of things.
     .Else                           ; Else we found our accented char value
        Mov [SI].Key.XChar,DH        ; Put it in CharData rec.
        Mov [SI].Key.Scan,0          ; Zero scan code for accented chars.
        Or  [SI].DDFlags,AccentedKey ; Indicate accent affected key.
     .Endif

      Pop DX
      Pop CX
      Pop AX
      And [DI].XlateFlags,Not PrevAccent ; Clear previous accent field.
      Mov [DI].XAccent, 0                ; Clear Extended Accent number

      Ret

ExtAccent Endp

Public  BadAccent
BadAccent Proc

;**********************************************************************
;*
;* FUNCTION NAME  BadAccent
;*
;* DESCRIPTION    Process an Accent that does Not Apply to a Char
;*
;*                Set up a KeyPacket that must be passed as a standalone
;*                character
;*
;*
;* INPUT          SI = @ of KeyPacket1
;*                ES:BX = @ of Accent Table Entry for accent to pass
;*                CX = Translate Table Header Flags
;*
;* Exit-Normal    Key Packet filled in
;*
;* Exit-Error     N/A
;*
;* Effects        CX
;*
;* Internal References:
;*    Routines: CopyPacket
;*
;*
;**********************************************************************


  Push SI
  Push DI
  Test CX,AccentPass                 ; Check if key packets should be passed
 .If <z>                             ; If not... OR
     Mov [DI].XSpecFlags, UseOneAcc  ; Indicate to caller that this is an
                                     ; invalid accent for a country that does
                                     ; NOT want to beep or display invaild
                                     ; accent combos.
     Mov [SI].DDFlags,BadKeyCombo    ; strategy proc to return invalid parm.
 .Else                               ; Else key packets should be passed
     Push DI                         ; Save translation flags offset
     Call CopyPacket                 
                                     ; packet into the extra packet.
     Pop  DI                         ; Restore translation Flags offset
     Mov  SI,StkTmpL                 ; Pointer to KeyPacket2 is on
                                     ; the local stack. This was setup
                                     ; by the caller of KbdXlate.
     Mov [SI].DDFlags,AccentedKey+AccentKey  ; Indicate printable accent char.
     Mov CX,ES:[BX]                  ; Get char/scan to pass from accent entry.
     Mov Word Ptr [SI].Key.XChar,CX  ; Put in KeyPacket2.
                                     ; Indicate for the PKBD an invalid
                                     ; accent translation of 2 packets.
     Mov [DI].XSpecFlags, UseTwoPac + UseTwoAcc
 .Endif
  Pop DI
  Pop SI
  Ret

BadAccent Endp

Public AltPadPacket
AltPadPacket  Proc

;**********************************************************************
;*
;* FUNCTION NAME  AltPadPacket
;*
;* DESCRIPTION    Set up a KeyPacket for the Break of the Alt Key
;*
;*                A monitor packet is set up so that on Alt-Numpad
;*                sequences the break of the Alt key is not lost.
;*
;*
;* INPUT          SI = pointer to KeyPacket1
;*
;* Exit-Normal    Key Packet filled in
;*
;* Exit-Error     NONE
;*
;* Effects:     None, Registers are preserved.
;*
;* Internal References:
;*    Routines: CopyPacket
;*
;*
;**********************************************************************
                                         
  Push SI                                ; Save the registers
  Push DI                                ; that we will use here
  Push CX                                ; to duplicate the first packet.
  Call CopyPacket                        
                                         ; packet into the extra packet.

    ;&& Now DI points to KeyPacket2.

  Or  [DI].DDFlags,ShiftMask+KeyBreak    ; Indicate that this is shift packet.
  Mov word ptr [DI].Key.XChar,0          ; Zero out the original char field.
  Pop CX                                 ; Restore registers.
  Mov SI,DI                              ; Point SI to Keypacket2
  Pop DI                                 ; 
                                         ; Indicate for the PKBD an Alt-Numpad
                                         ; combo translation of 2 packets.
  Mov  [DI].XSpecFlags, UseTwoPac + UseTwoAlt
  Test [DI].XInputMode,SHIFTREPORT       ; Are we in shift report mode ?
 .If <nz>                                ; If so then...
     Or [SI].Key.Status,1                ; flag this as a shift report packet.
 .Endif                                  ; Endif a shift report packet.
  Pop SI                                 ; 
  Ret                                    

AltPadPacket Endp

Public MakeE0Packet
MakeE0Packet Proc

;**********************************************************************
;*
;* FUNCTION NAME  MakeE0Packet
;*
;* DESCRIPTION    Set up a KeyPacket for the E0 scan code
;*
;*              A second Keypacket is set up for an E0 scan code packet
;*              that should have preceded the current scan code.
;*
;*              is now manufactured and passed in combination with the
;*              packet that follows the E0 scan code.  This change was
;*              made in order to ensure that the E0 packet would always
;*              end up in the correct screen group.
;*
;* INPUT        SI = @ of KeyPacket1
;*
;* Exit-Normal  Key Packet filled in
;*
;* Exit-Error   NONE
;*
;* Effects:     None, Registers are preserved.
;*
;* Internal References:
;*    Routines: CopyPacket
;*
;**********************************************************************
                                         
  Push SI                                ; Save the registers
  Push DI                                ; that we will use here
  Push CX                                ; to duplicate the first packet.

  Call CopyPacket                        
                                         ; packet into the extra packet.

    ;* Now DI points to KeyPacket2.

  Mov  [DI].DDFlags, 0                   ; Clear the flag bits for new packet.
  Or   [DI].DDFlags, SecPrefixCode       ; Indicate this is a secondary prefix.
  Push DS                                
  Mov  DS, StkDS                         
  Mov  CX, KCBShFlgs                     ; Get the saved Shift Flags.
  Pop  DS                                
  Mov  [DI].KPacketLen+1,OtherKey        ; Put Scan Code in KPacketLen field
  Mov  [DI].Key.Shift,CX                 ; Put Shift Flags in packet.
  Mov  [DI].Key.XChar,0                  ; Zero out the original char field.
  Mov  [DI].Key.Scan,0                   ; Zero out the original Scan field.
  Pop  CX                                ; Restore registers.
  Pop  DI
  Mov  [DI].XSpecFlags, UseTwoPac + UseTwoE0
                                         ; Indicate for the PKBD an E0 scan
                                         ; code translation of 2 packets.

  Pop SI                                 ; 
  Ret                                    

MakeE0Packet Endp

Public  CopyPacket
CopyPacket Proc

;**********************************************************************
;*
;* FUNCTION NAME  CopyPacket
;*
;* DESCRIPTION    Copy KeyPacket1 to KeyPacket2
;*
;*             This routine is called from BadAccent, AltPadPacket,
;*             and MakeE0Packet.  It's purpose is to duplicate the
;*             first keypacket to the extra  keypacket which follows
;*             the first.  This is done so that the Interrupt Handler
;*             can pass both keypackets on the same interrupt.
;*
;*
;* INPUT         SI = @ of KeyPacket1
;*               StkTmpL on Local Stack has offset of KeyPacket2.
;* Exit-Normal   Contents of KeyPacket1 copy to KeyPacket2.
;*
;* Exit-Error    NONE
;*
;* Effects       BX
;*
;*
;**********************************************************************

  Mov CX,KeyPacketLen                    ; Set length of packets.
  Mov DI,StkTmpL                         ; Pointer to KeyPacket2 is on
                                         ; the local stack. This was setup
                                         ; by the caller of KbdXlate.
  SaveReg<SI,DI>                         ; Save packet addresses

CopyLoop:                                ; Loop copying packet.
     Mov  CH,DS:[SI]                     ; Get byte from first packet.
     Mov  DS:[DI],CH                     ; Put in Packet2.
     Xor  CH,CH                          ; Fix counter reg.
     Inc  SI                             ; Increment source ptr.
     Inc  DI                             ; Increment dest ptr.
     Loop CopyLoop                       ; Repeat for all bytes.

  RestoreReg<DI,SI>                      ; Restore addresses for KeyPacket2 and
                                         ; KeyPacket1 respectively
  Ret

CopyPacket Endp


Public UnPauseChk
UnPauseChk Proc

;*********************************************************************
;*
;* FUNCTION NAME  UnPauseChk
;*
;* DESCRIPTION    Check For Key to End Pause Mode
;*
;*                Checks if key signalled the end of Pause mode.
;*                If it did, this routine resets the flag and
;*                returns to the the end of KbdXlate.  Otherwise
;*                it just returns
;*
;*
;* INPUT          None
;*
;* Exit-Normal    Nothing affected
;*
;* Exit-Error     NONE
;*
;* Effects:     Nothing
;*
;*********************************************************************

  And [DI].XKeyFlags,NOT DumpKeyOnce        ; If here, also cancels Dump sequence.
 .If <bit [DI].XlateFlags nz SGPaused> AND  ; Check if in paused state.
 .If <bit [SI].DDFlags z KeyBreak>          ; Yes, and is this a key Make?
    And [SI].DDFlags, NOT KeyTypeMask       
    Or  [SI].DDFlags,WakeUpKey              
    And [DI].XlateFlags,NOT SGPaused
    Pop CX                                  ; Purge return address.
    Jmp EndActionCase                       ; That's all.
 .Endif
 Ret

UnPauseChk Endp

;;*************** THIS FUNCTION IS NEVER CALLED *******************
;;                        (see KHBuffer)
;;Public SGCheck
;;SGCheck Proc
;;
;**********************************************************************
;*
;* FUNCTION NAME  SGCheck
;*
;* DESCRIPTION    Check if Scan Code Break from another SG
;*
;*               Check current scan code to see if it is a key BREAK for
;*               one of the last five unique key MAKE scan codes seen.
;*               If key MAKE was in a different SG then CX = SG # and
;*               carry set, otherwise carry will be clear.
;*
;*
;* INPUT         AL = Raw Scan Code, AH = Scan Code w/ Break bit cleared
;*               CX = SG that scan code is being processed in
;*
;* Exit-Normal   Carry clear if key BREAK was not for one of 5 last MAKE
;*
;*               Carry set if key BREAK was for a MAKE in other SG
;*               CX = SG # of key MAKE
;*
;* Exit-Error    N/A
;*
;* Effects:     CX, Carry
;*
;**********************************************************************
;;
;;  Test AL,80h                   ; Check if this is a key break.
;; .If <z>                        ; If not, attempt to add scan code to KeyHistory.
;;    Push AX                     ; Save AX during following.
;;    Mov  AL,CL                  ; Put SG number in bottom of AX.
;;   .If <AX ne KeyHistory>       ; Check if repeat of last key make in this SG
;;      Xchg KeyHistory,AX        ; Isn't, so put new scan in KeyHistory.
;;      Xchg KeyHistory+2,AX      ; And move
;;      Xchg KeyHistory+4,AX      ;   the other
;;      Xchg KeyHistory+6,AX      ;      keys back
;;      Xchg KeyHistory+8,AX      ;         in the queue.
;;   .Endif
;;    Pop AX                      ; Restore AX.
;; .Else                          ; It's a key break, so check the KeyHistory.
;;    Xor BX,BX                   ; Get a zero offset.
;;   .Repeat                      ; Look for scan code in KeyHistory.
;;      Mov DX,[BX+KeyHistory]    ; Get next KeyHistory entry.
;;     .If <AH eq DH>             ; Is scan code the make for our current break?
;;       .If <CL eq DL>           ; Yes, but are we still in that SG?
;;          Mov BX,8              ; Yes, so set quit condition.
;;       .Else             ; We've found keybreak that belongs in another SG.
;;          Mov CL,DL             ; Put correct SG number in CX.
;;          Xor AL,AL             ; Tell device driver we've found problem.
;;          StC                   ; Indicate it's not a misplaced shift key.
;;          Ret                   ; Quit now.
;;       .Endif
;;     .Endif
;;      Add BX,2                  ; Point to next entry in KeyHistory.
;;   .Until <BX eq 10>
;; .Endif
;;  ClC                           ; If here, process this key normally.
;;  Ret
;;
;;SGCheck Endp


Public AltGraphCheck
AltGraphCheck  Proc

;******************************************************************************
;*
;* FUNCTION NAME   AtlGraphCheck
;*
;* DESCRIPTION     Process an Alt-Graph character input
;*
;*                 This routine processes a key type that is affected
;*                 by Alt-Graph if an Alt key is down.  If the Alt key
;*                 down is not the Alt-Graph key or the Alt-Graph combo,
;*                 it will set the carry and return.
;*
;*  NOTES          Upon entry to this routine, an Alt key is known to be
;*                 down
;*
;*
;* INPUT           DI = Per Session Data Area Address
;*                 SI = Key Packet Address
;*                 ES = Translate Table Selector
;*                 SS:SP+2 = Offset of translate table
;*                 StkTmpReg = Offset of scan code entry in translate table
;*                 DX = ShiftFlags
;*                 CharToUse = Which character to use if Alt-Graph is down
;*
;* Exit-Normal     Carry set = process as normal Alt key down
;*                 Carry clear = key has been processed
;*                 AL= ASCII character to use
;*                           OR
;*                 CharToUse = UNDEFINED
;* Exit-Error      None
;*
;* Effects         AX, BX, registers, carry flag changed.
;*
;*
;**********************************************************************

  Push SI                                   ; 
  Mov  SI,StkTmpReg                         ; 
 .If <ES:[SI].Char3 eq 0>                   ; If Char 3 is 0
    Or [DI].XKeyFlags,NormalAlt             ; indicate that only Normal ALT is down
 .Else NEAR                                 ; Else Alt-Graph character is defined
    Push BX
    Mov  AL,ES:[SI].Char3                   ; Get Char3 from translate table
                                            
    Xor BX,BX                               ; Put translate table header in BX
                                            
   .If <ES:[BX].XTKbdType eq ATKbd>         ; If an AT kbd translate table
      Test ES:[BX].XTFlags1,ShftAlt         ; check if we should use Shift-Alt as
     .If <nz>                               ; as the Alt-Graph combo, if so...
        Test DL,RShiftFlag+LShiftFlag       ; Check if a shift key is down
       .If <nz>                             ; If it is
           And [DI].XKeyFlags,Not NormalAlt ; specify to caller
                                            ; that it's Alt-Graph
           Test [DI].XlateFlags,Use3Index   ; if we're supposed to use it
          .If <nz>                          ; as an index
             Mov CL,AL
             Xor AL,AL
          .Endif
       .Else                                ; supposed to use Shift-Alt combo,
                                            ; but shift isn't down
           Mov AL,ES:[SI].Char1             ; Restore Char1
           Or [DI].XKeyFlags,NormalAlt      ; indicate that only Normal ALT is down
       .Endif                               ; Endif shift key down check
     .Else                                  ; Shift-Alt is not Alt-Graph combo,
                                            ; so it is Ctl-Alt
        Test DL,CtlFlag                     ; Check if a ctl key is down
       .If <nz>                             ; If it is
           And [DI].XKeyFlags,Not NormalAlt ; specify to caller
                                            ; that it's Alt-Graph
           Test [DI].XlateFlags,Use3Index   ; if we're supposed to use it
          .If <nz>                          ; as an index
             Mov CL,AL
             Xor AL,AL
          .Endif
       .Else                                ; supposed to use Ctl-Alt combo,
                                            ; but Ctl isn't down
           Or  [DI].XKeyFlags,NormalAlt     ; indicate only Normal ALT is down
           Mov AL,ES:[SI].Char1             ; Restore Char1
       .Endif                               ; Endif Ctlt key down check
     .Endif                                 ; Endif Shift-Alt is Alt-Graph combo
                                            ;  or not check
   .Else                                    ; Else it's an Enhanced Keyboard
      Test ES:[BX].XTFlags1,AltGrafL        ; check if we should use Left Alt key
     .If <nz>                               ; as the Alt-Graph key, if so...
        Test DX,LAltFlag                    ; Check if left Alt key is down
       .If <nz>                             ; If it is
           And [DI].XKeyFlags,Not NormalAlt ; specify to caller
                                            ; that it's Alt-Graph
           Test [DI].XlateFlags,Use3Index   ; if we're supposed to use it
          .If <nz>                          ; as an index
             Mov CL,AL
             Xor AL,AL
          .Endif
       .Else                                ; supposed to use Left Alt key,
                                            ; but it isn't the one down
           Or [DI].XKeyFlags,NormalAlt      ; indicate that only
                                            ; Normal ALT is down
           Mov AL,ES:[SI].Char1             ; Restore Char1
       .Endif                               ; Endif Left Alt key down check
     .Else                                  ; Left Alt Key is not Alt-Graph key,
                                            ; so check if it is Right

         Test ES:[BX].XTFlags1,AltGrafR     ; check if we should use Right Alt key
        .If <nz>                            ; as the Alt-Graph key, if so...
            Test DX,RAltFlag                ; Check if right Alt Key is down
           .If <nz>                         ; If it is
               And [DI].XKeyFlags,Not NormalAlt ; specify that it's Alt-Graph
               Test [DI].XlateFlags,Use3Index   ; if we're supposed to use it
              .If <nz>                          ; as an index
                   Mov CL,AL
                   Xor AL,AL
              .Endif
           .Else                            ; supposed to use Right Alt Key,
                                            ; but it isn't down
               Or [DI].XKeyFlags,NormalAlt  ; indicate that only Normal
               Mov AL,ES:[SI].Char1         ; Restore Char1
           .Endif                           ; Endif Right Alt Key down check
        .Else                               ; Else Alt-Graph is neither Left nor
                                            ; Right Alt Key
            Or [DI].XKeyFlags,NormalAlt     ; indicate that only Normal
            Mov AL,ES:[SI].Char1            ; Restore Char1
        .Endif                        ; Endif Right key Alt-Graph or not check
     .Endif                           ; Endif Left ALt key Alt-Graph or not check
   .Endif                                   ; Endif At or Enhanced Keyboard
    Pop BX                                  ; Restore BX
 .Endif                                     ; Endif Char 3 is 0 or not
  Pop SI                                    ; 
  Ret

AltGraphCheck Endp


;***********************************************************************
;*
;* FUNCTION NAME  CheckExtended
;*
;* DESCRIPTION    Checks for extended codes.
;*
;*                This routine checks if a scan code has an associated
;*                extended scan code that goes with it.  If it does,
;*                it sets the appropriate fields (scan & char) in the
;*                key packet and returns.
;*
;* NOTES          Upon entry to this routine, an Alt key is known to be
;*                down
;*
;*
;* INPUT          DI = Per Session Data Area Address
;*                SI = KeyPacket1 Address
;*                DX = ShiftFlags
;*                AH = Scan code w/ break bit cleared
;*
;* Exit-Normal    Carry set = Key has new extended code associated w/ it
;*                Carry clear = Key does not have new extended code
;*
;* Exit-Error     None
;*
;* Effects        AX, BX, registers, carry flag changed.
;*
;*
;**********************************************************************

Public  CheckExtended
CheckExtended  Proc

  Push ES                    
  Mov  ES,StkDS              ; Get base DDs data seg (could be VDM SG)

  Lea  BX, ES:NewExtSC       ; Get the offset of the table that
                             ; contains the scan codes that have new
                             ; extended codes associated with them
  Mov  CX,0                  ; Start at beginning of table
 .While <CX ne NewExtSCLen>  ; While we haven't searched entire table

    .If <AH eq ES:[BX]>      ; If we found the scan code
        Mov [SI].Key.XChar,0 ; Say its an extended
        Mov CX,NewExtSCLen   ; Set end of loop condition
        Mov BX,0             ; Set found indicator
    .Else                    ; Else this isn't the scan code
        Inc CX               ; Increment loop counter
        Inc BX               ; Increment pointer into table
    .Endif                   ; Endif found scan code we're looking for
 .EndWhile                   ; EndWhile we haven't searched entire table
 .If <BX eq 0>               ; If we found the scan code
   .If <AH eq 0Fh>           ; If it's the tab key
      Mov [SI].Key.Scan,0A5h ; Set extended code for tab key
   .Endif                    ; Endif it's the tab key
    Stc                      ; Tell caller extended char. exists.
 .Else                       ; Else we didn't find Scan code in table
    Clc                      ; tell caller
 .Endif                      ; 

 Pop ES                      
 Ret                         ; 
                             
CheckExtended Endp

Code Ends
  End
