;;; -*- Mode:Common-Lisp; Package:X11; Fonts:(MEDFNB HL12B HL12BI); Base:10 -*-

;;;			      RESTRICTED RIGHTS LEGEND

;;;Use, duplication, or disclosure by the Government is subject to
;;;restrictions as set forth in subdivision (c)(1)(ii) of the Rights in
;;;Technical Data and Computer Software clause at 52.227-7013.
;;;
;;;			TEXAS INSTRUMENTS INCORPORATED.
;;;				 P.O. BOX 2909
;;;			      AUSTIN, TEXAS 78769
;;;				    MS 2151
;;;
;;; Copyright (C) 1988 Texas Instruments Incorporated. All rights reserved.

#|

This file contains all of the code for supporting the keyboard at the lowest level.

|#

;;; Change history:
;;;
;;;  Date      Author	Description
;;; -------------------------------------------------------------------------------------
;;; 03/22/89    DAN     Patch 1.55; Change initial-repeat-delay to 30 instead of 60.
;;; 03/22/89    DAN     Patch 1.54; Fix SYS:KBD-GET-HARDWARE-CHAR to not crash the server
;;;			on pre-5.0 bands due to tv:*mac-keyboard-p*.
;;; 03/17/89    DAN     Patch 1.49; Added Auto-Repeating code to BUFFER-KEYBOARD-EVENTS.
1; ; ;  12/22/88       DKM       Changed kbd-get-hardware-char to not confuse a mode-status code with a keystroke code.
; ; ;                                Pressing the CAPS LOCK key down resulted in thinking a SYSTEM key was pressed.*
;;; 12/08/88	WJB	Changed BUFFER-KEYBOARD-EVENTS to prevent stepper from munging keys.
;;; 12/06/88	1DLS*	Update the SYS:KBD-GET-HARDWARE-CHAR to the Release 5 version.
;;; 10/217*/88	1DLS*	1Remove references to the keyboard process, which is not needed anymore*
;;; 10/217*/88	1DLS*	1Let the TERMINAL key be handled by the Explorer window system causing the X server to exit*
;;; 10/03/88	WJB	Disable/Enable ucode mouse tracking when entering/leaving X.
;;;  9/21/88    LGO     Eliminate the x-keyboard process - it was never needed
;;;  9/21/88    LGO     Re-write sys:kbd-get-hardware-char
;;;  9/20/88    LGO     Move explorer keysym definitions to the keysyms file
;;;  9/20/88    LGO     Move EXPLORER-KEYSYM-MAP definitions to DEVICE-AND-EVENT-STRUCTURES
;;;  7/11/88    DAN     Changed length of EXPLORER-KEYSYM-MAP to (* MAX-KEYSYMS-PER-KEYCODE
;;;			MAP-LENGTH) and MAX-KEY-CODE to 255.
;;;  5/13/88    TWE	Changed the keyboard event queue to use a new type: EVENT-QUEUE
;;;			instead of io-buffer.
;;;  5/12/88    TWE	Fixed up the initialization of KEY-MODIFIERS-LIST.
;;;  5/06/88    TWE	Modified KEYBOARD-OVERSEER to set the keyboard process variable
;;;			to NIL if the user kills it off.
;;;  3/29/88    TWE	Changed KEYBOARD-PROCESS to a defvar so that it wouldn't be set
;;;			to NIL when the system is remade.  Changed EXPLORER-KEY-SYMS to
;;;			be based upon the X keysyms instead of Explorer keysyms.
;;;  3/09/88    TWE	Fixed up the initialization of the keyboard process.
;;;  3/07/88    TWE	Changed SYS:KBD-GET-HARDWARE-CHAR to switch to the X window when
;;;			enabling X.
;;;  2/26/88    TWE	Added keysym code.
;;;  2/24/88    DAN	Initial creation.


(DEFPARAMETER initial-repeat-delay 30
	      "260ths of a second before repeating starts.  Set this to 0 to shut off
the repeat capability.*") 

(DEFPARAMETER continuous-repeat-delay 2.
	      "2Number of 60ths of a second to delay before repeating again.*")

(DEFCONSTANT scan-code-up   0)
(DEFCONSTANT scan-code-down #o200)

(DEFPARAMETER *DEFAULT-KEYBOARD-QUEUE-SIZE* 64
  "Maximum number of keyboard button/motion events that can be saved.")

(DEFPARAMETER KEYBOARD-EVENT-QUEUE (MAKE-EVENT-QUEUE *DEFAULT-KEYBOARD-QUEUE-SIZE*)
  "Event queue to hold all keyboard key events.")


#|

*DOCUMENTATION ALERT*  *DOCUMENTATION ALERT*  *DOCUMENTATION ALERT*

The following constants are the bit numbers of the locking
keys: CAPS, BOLD, ITALIC and MODE.  One way to use these
constants is to use the LOGBITP function.  The indication of
which locking keys are on comes from the "all keys up" character
sequence received from the keyboard when no key is depressed.

The status indication received from the keyboard after it
generates the "all keys up" character sequence has the following
format:
    .-----------..-----------..-----------.
    ! 8 ! 7 ! 6 !! 5 ! 4 ! 3 !! 2 ! 1 ! 0 !  Bit number, units bit
    `-----------'`-----------'`-----------'
      !   !   !    !   !   !    !   !   !
      !   !   !    !   !   !    !   !   `---- Mode lock on = 1
      !   !   !    !   !   !    !   !
      !   !   !    !   !   !    !   `-------- Italic lock on = 1
      !   !   !    !   !   !    !
      !   !   !    !   !   !    `------------ Bold lock on = 1
      !   !   !    !   !   !
      !   !   !    !   !   `----------------- Caps lock on = 1
      !   !   !    !   !
      !   !   `----`---`--------------------- Reserved (zero)
      !   !
      !   `---------------------------------- Always 1
      !
      `-------------------------------------- Parity (even)

|#

(DEFPARAMETER LAST-CHAR-WAS-ESCAPE NIL)

(DEFUN BUFFER-KEYBOARD-EVENTS (CHAR)
  ;; Only keep the down bit and the scan code (lop off the high bit).
  (SETQ CHAR (LOGAND CHAR #o377))
  (COND ((AND (FBOUNDP 'STEPPER-SNARF-CHARS)
	      (FUNCALL #'STEPPER-SNARF-CHARS CHAR))
	 ;;Stepper snarfed the char... skip the rest
	 )
	((AND (NOT (ZEROP CHAR))
              (NOT LAST-CHAR-WAS-ESCAPE))
	 ;; We have a real character.  Let stepper snarf it
	 ;; or stuff it into the keyboard buffer
	 (WRITE-EVENTS KEYBOARD-EVENT-QUEUE CHAR (TIME:MICROSECOND-TIME)
		       SYS:MOUSE-X SYS:MOUSE-Y)
         (WHEN (AND (= (keyboard-control.auto-repeat (device.keyboard-control
                                                       (input-info.keyboard input-info)))
                       AUTO-REPEAT-MODE-ON)
                 (repeatable-key? (LOGAND char #x7F))
                 (PLUSP (LOGAND scan-code-down char)))        ;1do we have a downstroke?*
           (server-trace "~%In BUFFER-KEYBOARD-EVENTS: going into auto-repeat loop")
           (UNLESS (PROCESS-WAIT-WITH-TIMEOUT        ;1wait for keystroke or timeout*
                     tv:*DEFAULT-READ-WHOSTATE* initial-repeat-delay
                     #'tv:kbd-hardware-char-available)
1                   *;1; Else start repeating the character*
             (LET ((char (LOGAND #o177 char)))         ;1strip off the up/down bit.*
               (LOOP
                 (WITHOUT-INTERRUPTS
1                           *;1;Generate fake upstroke/downstroke pairs.*
                   (WRITE-EVENTS KEYBOARD-EVENT-QUEUE (LOGIOR scan-code-up   char)  ;1upstroke*
                                 (TIME:MICROSECOND-TIME) SYS:MOUSE-X SYS:MOUSE-Y)
                   (WRITE-EVENTS KEYBOARD-EVENT-QUEUE (LOGIOR scan-code-down char)  ;1downstroke*
                                 (TIME:MICROSECOND-TIME) SYS:MOUSE-X SYS:MOUSE-Y)
                   (WHEN (PROCESS-WAIT-WITH-TIMEOUT ;1wait for new keystroke or timeout*
                           tv:*DEFAULT-READ-WHOSTATE* continuous-repeat-delay
                           #'tv:kbd-hardware-char-available)
                     (RETURN nil)))))
             (server-trace "~%In BUFFER-KEYBOARD-EVENTS: Leaving auto-repeat loop"))))
	((ZEROP CHAR)
	 ;; This is an escape character.  It indicates that all of the keys
	 ;; are up.  For now we ignore it.  In the future, we may want to mark
	 ;; all of the down bits to 0, since all keys are up.
	 (SETQ LAST-CHAR-WAS-ESCAPE T))
	(T
	 ;; This is the character after the escape character.  This indicates several
	 ;; things (see the above DOCUMENTATION ALERT).  For now, we will ignore it.
	 ;; What we may want to do in the future is to set the state of the locking
	 ;; keys to the value reflected here.
	 (SETQ LAST-CHAR-WAS-ESCAPE NIL))))

  
(let ((inhibit-fdefine-warnings :just-warn))
  (defun sys:kbd-get-hardware-char ()
    "Returns the next character in the microcode interrupt buffer, and NIL if there is none"
    (let ((char (IF (AND (BOUNDP 'tv:*mac-keyboard-p*)
                         tv:*mac-keyboard-p*)
		    (sys:mx-get-key)
		    (sys:%io sys:%kbd-get-char sys:*keyboard*))))
      (cond ;1; If we are not in the X server just return the character for the Explorer window system.*
	((or (null char) (not x-enabled))
	 char)
	;1; If the SYSTEM or TERMINAL key are pressed we give control back to the Explorer window*
	;1; system and return the character.*
	((and (OR (= (logand char #o177) sys:scan-code-system)
		  (= (logand char #o177) sys:scan-code-terminal))
	      (logtest (expt 2 7) char)  ;1; key down*
	      (not LAST-CHAR-WAS-ESCAPE));1;not mode status (comes after escape character)*
	 ;1; Disable the X server.*
	 (x-disable)
	 (setq si:escape-flag nil)
	 char)
	;1; Otherwise the X server is in control so let it have the character and return the NULL*
	;1; character to the keyboard process so it will do nothing.*
	(t
	 (buffer-keyboard-events char)
	 0)))))


(DEFUN repeatable-key? (key)
  (LET* ((keybd (input-info.keyboard input-info))
         (cntrl (device.keyboard-control keybd)))
    (server-trace "~%In repeatable-key?: key- ~16r, repeatable= ~s"
                  key (AREF (keyboard-control.auto-repeats cntrl) key))
    (PLUSP (AREF (keyboard-control.auto-repeats cntrl) key))))

(DEFPARAMETER KEYBOARD-DEVICE (MAKE-DEVICE :EVENTS KEYBOARD-EVENT-Queue))




