;*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   KBDMON - Kbd Device Driver Monitor Code

;/*****************************************************************************
;*
;* SOURCE FILE NAME = KBDMON.ASM
;*
;* DESCRIPTIVE NAME = Physical Keyboard Device Driver Monitor Code
;*
;*
;* VERSION      V2.0
;*
;* DATE         04/15/93
;*
;* DESCRIPTION  This module contains Keyboard Monitor related code.
;*
;* FUNCTIONS    MonDispEntry()-Keystroke Monitor Dispatcher (Re)Entry Point
;*
;* NOTES        DEPENDENCIES:  Controller or keyboard must be set to the PC
;*                             compatible scan code set.
;*              RESTRICTIONS:  Machine must be a 386 or compatible with a 386.
;*
;*              ENTRY POINTS:  MonRegister
;*                             MonDispentry
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*   10/09/92                     D55711 - First character missing when
;*                                switching to/from DOS session with monitor
;*                                installed.
;*
;*   unknown                      B712206 - Notification packet problem.
;*
;*   Unknown                      B736552 - Unknown
;*
;*   Unknown                      783515  - Unknown
;*
;*   04/12/94  81507              Defect 81507 - update sequence of instructions
;*                                for a Block call to meet specifications
;*****************************************************************************/
     .286p
     .sall
     .xcref
     .xlist
     Include basemaca.inc    ;DOS macros.
     Include osmaca.inc      
     CPUMODE 286             ; 
     Include struc.inc       ;Structured assembly macros.
     Include devhlp.inc      ;DevHlp & Signal equates, char queue structure.
     Include devsym.inc      ;Device driver header definitions.
     Include kbdseg.inc      ;Segment definitions.
     Include kbdddr.inc      ;Keyboard Device Driver structures & equates.
     .list

     ;External Routines
     Extrn AccessKCB         :Near
     Extrn HotKeyCheck       :Near
     Extrn PutInKIB          :Near
     Extrn ConsInpFilter     :Near
     Extrn PutInSQB          :Near               

     ;External Variables
     Extrn CBDataSel         :Word
     Extrn DeviceHelp        :DWord
     Extrn SQHotKeyData      :Byte               ;          

     StkFrameVars            ;Setup local stack varibles.

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

     Public   MonDispEntry
     MonDispEntry Proc Far

;/***************************************************************************
;*
;* FUNCTION NAME = MonDispEntry()
;*
;* DESCRIPTION   = Keystroke Monitor Dispatcher (Re)Entry Point
;*
;*   This routine's address is passed to the monitor dispatcher, along
;*   with a End-of-Monitor Chain buffer address for each session for
;*   which a monitor chain exists.  When monitors are registered in a
;*   session, every keystroke is passed to the dispatcher.  This entry
;*   point is invoked after the monitor dispatcher has placed a packet
;*   in the End of Monitor Chain data area.
;*
;*   Note that once Key packets are passed to the monitor dispatcher it
;*   might change foreground sessions.  But monitors can still be
;*   passing characters when their session is not active.
;*
;*   When entered here, there is a record in the end-of-chain buffer
;*   whose address is in ES:SI at the time this routine is entered.
;*   Then check the CharData record in that buffer with the Console
;*   Input Filter code and throw out keys that are not allowed in a
;*   keyboard input buffer.  IF the CharData record remains,an attempt is made
;*   to acquire a KIB element from the FreeList.  IF not the foreground
;*   session, or IF already acquired half of the highest amount
;*   that has been available while active, I can't get any. In that
;*   case leave the record in the end-of-chain buffer and yield until
;*   it can get another record (IF in active session) or until the
;*   record has been read (background session).  Then return to the
;*   monitor dispatcher.
;*
;*   If Single Queue mode is in effect, then the Single Queue
;*   Device Driver Entry Point is called to place an SQDR into
;*   the SQB.  If the SQ device driver returns ERROR_SQ_NOT_
;*   IN_MODE, then the PSG will be taken out of SQ mode, and
;*   CharDataRecord will be placed into the KIB as usual.
;*
;*   Entry Point: MonDispentry     Linkage: FAR
;*
;*
;* INPUT         = A monitor packet which was placed in the output
;*                 buffer for the current screen group by the Monitor
;*                 Dispatcher.
;*
;* OUTPUT        = NONE(Keystroke buffers are altered, CharData flags are
;*                      updated).
;*
;* RETURN-NORMAL = Return to Monitor Dispatcher.
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

      Assume ES:DGROUP

       PushF                           ;Save flags.
       PushA                           ;Save regs.
       Mov     DI,SI                   ;Put buffer offset in DI.
       Sub     DI,MonChainEnd          ;Make DI point to beginning of bfr's PSG
       Add     SI,2                    ;Point past record length field in bfr.

  ;*
  ;*From here on DI is the index of the current PSG we're using and SI
  ;*is the index to the Key Packet. First check if this record is a
  ;*Flush record, indicating a flush is going on.
  ;*

  Test Byte Ptr [SI].KPacketLen,FlushPacket ;Check is this a flush packet.
 .If <nz> NEAR                              ;Was it?
    And [DI].PSGFlags,Not Flushing          ;Yes, indicate done.
 .Else NEAR                                 ;Check if we should ignore this
                                            ;packet.
                                                                        ;          
                                            ;Notification Packet. If so

  .If <<Byte Ptr [SI].DDFlags> eq XRorPNot > OR
   .If <<Byte Ptr [SI].DDFlags> eq MLNotification>

                                            
                                            ;Notification Packet, or
                                            ;If this is a Multi-Layer NLS
                                            ;Notification Packet
                                            ;IGNORE THIS PACKET!, also:
    And [DI].NotifyFlags, NOT NotPctSent    ;Clear Mons. did not accept flag.
                                            ;This is set due to XRorPNot packet
                                            ;NOTE: MLNotification packet donot
                                            ;set the NotPctSent flag.
                                            
                                            ;          
   .Else NEAR
      Test Byte Ptr [SI].KPacketLen,OpenPacket+ClosePacket

     .If <z> NEAR AND                       ;OK to continue if not Open or
                                            ;Close packet.
      Test [DI].PSGFlags,Flushing           ;Check if flush in progress.
     .If <z> NEAR                           ;If not, process this packet.
                                            ;Inserted by monitor?
       Test Byte Ptr [SI].KPacketLen,NotInserted
       .If <z>                              ;Was it?
          Mov DH,MHotKeyDown                ;Set bit needed by next call.
          Mov AX,[SI].Key.Shift             ;Get shift status from key packet
                                            
                                            ;shift state in AX not BX.
          Call HotKeyCheck                  ;Yes so go check for SM hotkey.
       .Endif
                                                                        ;          
                                                                        ;          
        Test [DI].PSGFlags, SQMODE          ;Check for Single Queue mode.
       .If < nz > AND                       ;If we're in SQ mode, AND
        Test [SI].DDFlags, NotSQPacket      ;(Check if packet is to go in SQ)
       .If < z >                            ;Packet should go in SQB,
       Push    SI                           ;copy from kbdscan.asm when ;          
       Push    BX                           ;no monitor installed.      ;          

         .If <bit SQHotKeyData nz 03>       ;If nonzero                 ;          
                                                                        ;          
            Call PutInSQB                   ;Call SingleQ DD with Hot Key Info

         .Endif                             ;Endif                      ;          

       Pop     BX                                                       ;          
       Pop     SI                                                       ;          
       Call    PutInSQB                     ;Attempt to put an SQDR into
                                            ;the Single Queue Buffer.  This
                                            ;routine could clear SQ mode.
       .Endif                               ;End if in Single Queue Mode and
                                                                        ;          


        Call ConsInpFilter                  ;Go send events as appropriate.

       .If <nc> NEAR AND                    ;If ConsInpFilter said keep record
        Test [DI].PSGFlags, SQMODE          ;AND (check for Single Queue Mode)
       .If < z >                            ;NOT currently in SQ mode,
          Call PutInKIB                     ;Go add element to KIB.
          Clc                               ;Mov AccessKCB into loop    ;          

          Jmp short GetKCB                  ;and force skip of signal test.
                                            
          Cli                               ;81507 - Disable interrupts
         .While <ES:[BX].KCBInPtr eq 0>     ;Wait if rec still in EndOfChainBfr.
             Push AX                        ;81507 - Save ax
             Push BX                        ;Save KCB offset
             Push DI                        ;Save PSG offset
             Lea BX,[DI].MonBlockID         ;Get Blocker value...
             Mov AX,DS                      ;for use as Blocked Event
             Mov CX,-1                      ;Indicate to never timeout
             Mov DI,CX                      ;indicate to never timeout.(DI:CX)
             Mov DX, DevHlp_ProcBlock       ;DH = 0 = Interruptible block,
                                            ;DL = DevHlp function.
             Call [DeviceHelp]              ;Go block the monitor chain
             Cli                            ;81507 - Disable interrupts
             Pop DI                         ;Restore PSG offset
             Pop BX                         ;Restore KCB offset
             Pop AX                         ;81507 - Restore ax
GetKCB:                                                                 ;          
             Pushf                          ;Save the flags from the block.
             Mov DH,ES_DI                   ;Tell PhysToVirt where to put result
             Push DI                        ;Save PSG pointer
             Call AccessKCB                 ;Go get access to this SG's KCB
             Mov BX,DI                      ;Put KCB offset in BX
             Pop DI                         ;Restore PSG pointer
             Popf
; tmp JC     POPAF <AX>                     ;Macro to safely restore flags.
                                                                        ;          
            .If <c> AND                     
            .If <nz>                        ;Ctl-Break/C
                Mov SI,[DI].E0FwdPtr        ;Get E0's fwd pointer
                Mov ES:[BX].KCBInPtr,SI     ;Put it in KCB In Pointer
               .If <SI gt 0>                ;If there are other els in KIB
                   Mov ES,CBDataSel         ;Set ES KIB selector
                   Dec SI                   ;Correct for list starting w/ ele 1
                   IMul SI,KIBElLen         ;Set offset into element list.
                   Add SI,FLISTOFFSET       ;Point to the element.
                   Mov ES:[SI].KIBRevPtr,AX ;Set RevPtr to EOL.
               .Endif                       ;Endif other els in KIB
               Jmp PacketProcessed          
            .Endif                          
         .EndWhile
          Sti                               ;Enable interrupts after PhysToVirt
       .Endif                               ;End "ConsInpFilter didn't eat key"
                                            ;And Not in Single Queue Mode.
     .Endif
   .Endif
 .Endif
PacketProcessed:
  PopA                                      ;Restore regs.
  PopF                                      ;Restore flags.
  Ret                                       ;Return to monitor dispatcher.

MonDispEntry Endp

Code Ends
     End
