{***********************************************************************}
{									}
{ __KeyMnu    Add a _Key record to a menu				}
{									}
{ function  __KeyMnu(MenuPtr : _MenuPtr;				}
{		     ItemPtr : _ItemPtr;				}
{			 Key : _Keys;					}
{		      Action : byte;					}
{		      Motion : _MenuMotion) : _KeyPtr;			}
{									}
{	      MenuPtr	Pointer to the menu to which the keystroke	}
{			will be added.					}
{	      ItemPtr	Pointer to an associated _Item (or NIL if none).}
{	      Key	Keystroke name. 				}
{	      Action	One or more of the following constants, which	}
{			define an action taken upon the keystroke:	}
{									}
{			_KNOACTION_MNU	 No action (may have motion)	}
{			_KTRANSMIT_MNU	 Transmit menu on this key	}
{			_KABORT_MNU	 Transmit menu with error code	}
{			_KBEEP_MNU	 Beep on this key		}
{			_KDISABLE_MNU	 Ignore this key until enabled	}
{									}
{	      Motion	Movement of the menu highlight bar which occurs }
{			when the keystroke is encountered:		}
{									}
{			_NoMove   Don't move the highlight bar		}
{			_Up	  To the next higher item, same column	}
{			_Down	  To the next lower item, same column	}
{			_Right	  Right to the next item, same row	}
{			_Left	  Left to the next item, same row	}
{			_Next	  To the next item in the list		}
{			_Previous To the previous item in the list	}
{			_First	  To the first item in the list 	}
{			_Last	  To the last item in the list		}
{			_NextCh   To the next item with a highlighted	}
{				  character defined by Key		}
{			_Goto	  To the item pointed to by ItemPtr	}
{									}
{	      __KeyMnu defines a single keystroke for the menu		}
{	      pointed to by MenuPtr.					}
{									}
{	      Keystrokes are defined by a linked list of _Key records.	}
{	      Every menu has its own list, initially consisting of the	}
{	      default list provided by _MakeMnu.  These defaults	}
{	      include the arrow keys, Tab, Enter, etc.			}
{									}
{	      __KeyMnu searches the list for a record with a character	}
{	      and scan code matching those of Key.  If a match is found }
{	      the existing record is replaced, otherwise a new _Key	}
{	      record is added to the linked list.   The functional	}
{	      value is a pointer to the newly created _Key record,	}
{	      or NIL if an error occurred				}
{									}
{	      On error _MenuError may be set to:  _InvalidWindow	}
{						  _InvalidMenu		}
{						  _InvalidKey		}
{						  _InvalidItem		}
{									}
{ Version     4.00 (C)Copyright Blaise Computing Inc. 1987		}
{_______________________________________________________________________}

function __KeyMnu(MenuPtr : _MenuPtr;
		  ItemPtr : _ItemPtr;
		      Key : _Keys;
		   Action : byte;
		   Motion : _MenuMotion) : _KeyPtr;

  var
    TempPtr,LastPtr : _KeyPtr;
    TempIPtr	    : _ItemPtr;
    Found	    : boolean;
    ChSc	    : _KeySeq;

  begin {__KeyMnu}

    __KeyMnu  := NIL;

    { First determine whether the menu and menu window pointers are	}
    { valid.								}

    if (not ValidSig(MenuPtr,MENUSIG_)) then
       Exit;
    if (not ValidWindow(MenuPtr^._MWinPtr)) then
       begin
	 SetMenuError(_InvalidWindow);
	 Exit
       end;

    { Next determine whether we are pointing at a valid item or NIL.	}
    { NIL means the keystroke is not directly associated with a par-	}
    { ticular item, although it may select the next (possibly only)	}
    { item with a particular character highlighted.  If ItemPtr is not	}
    { NIL it must have a valid signature byte, and it must be consist-	}
    { ent with MenuPtr (in MenuPtr's linked list of items):		}

    if (ItemPtr <> NIL) then
       if (not ValidSig(ItemPtr,ITEMSIG_)) then
	  Exit
       else
	  begin
	    TempIPtr := ItemPtr;
	    while (TempIPtr^._PrevItem <> NIL) do
	      TempIPtr := TempIPtr^._PrevItem;	  { Find head		}
	    if (TempIPtr <> MenuPtr^._MItemsPtr) then
	       begin
		 SetMenuError(_InvalidItem);
		 Exit
	       end
	  end;

    { Next we traverse the list of _Keys, if any, looking for a match.	}
    { A match is a record with an identical keystroke (_KChSc). 	}

    ChSc    := _KeyTable[Key];
    Found   := FALSE;
    TempPtr := MenuPtr^._MKeysPtr;     { Point at the head of the list	}
    LastPtr := TempPtr;

    while ((TempPtr <> NIL) and (not Found)) do
      begin
	if (not ValidSig(TempPtr,KEYSIG_)) then
	   Exit;
	if (TempPtr^._KChSc._ChScan = ChSc._ChScan) then
	   Found := TRUE
	else
	   Found := FALSE;
	if (not Found) then
	   begin
	     LastPtr := TempPtr;
	     TempPtr := TempPtr^._NextKey
	   end;
      end; { while }

    if (not Found) then 	       { Add the key record to the list }
       begin
	 TempPtr := AddKey(ItemPtr,ChSc,Action,Motion);
	 if (MenuPtr^._MKeysPtr = NIL) then
	    MenuPtr^._MkeysPtr := TempPtr
	 else
	    LastPtr^._NextKey := TempPtr;
	    __KeyMnu := TempPtr
       end
    else			       { Update the key record list	}
       if ((TempPtr^._KeyItem = NIL) and (Motion = _Goto)) then
	  SetMenuError(_InvalidItem)
       else
	  with TempPtr^ do
	    begin
	      _Action	  := Action;	{ Only these fields can 	}
	      _Motion	  := Motion;	{ logically be updated. 	}
	      _KeyItem	  := ItemPtr;
	      __KeyMnu	  := TempPtr
	    end

  end;	{__KeyMnu}
