home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / tptools.zip / BININST.ZIP / BIKEY.INC < prev    next >
Text File  |  1987-12-21  |  29KB  |  900 lines

  1. {                          BIKEY.INC
  2.                            INSTALL 4.0
  3.              Copyright (c) 1985, 87 by Borland International, Inc.            }
  4.  
  5.   procedure KeyInstall;
  6.     {-Install keyboard}
  7.   type
  8.     InstRec = record
  9.                 Len : Integer;
  10.                 PCList1 : PackedCommandList;
  11.                 JunkBytes : array[1..32] of Char;
  12.                 PCList2 : PackedCommandList;
  13.               end;
  14.   var
  15.     OurInstRec : InstRec;
  16.   const
  17.     FirstRow = 4;
  18.     LastRow = 25;
  19.     PrimeCmdCol = 28;
  20.     PrimeMinCol = 31;
  21.     PrimeMaxCol = 52;
  22.     SecndCmdCol = 54;
  23.     SecndMinCol = 57;
  24.     SecndMaxCol = 79;
  25.  
  26.     MaxDisplay = 61;         {Number of editor commands displayed}
  27.     EditPrompt : string[70] =
  28.     '-backspace  C-clear  R-restore  ┘-accept edit  <Scroll Lock> literal';
  29.     BrowsePrompt : string[67] =
  30.     '--scroll  PgUp-PgDn-page  ┘-modify  R-restore defaults  ESC-exit';
  31.  
  32.     OrderMap : array[1..MaxDisplay] of CommandType =
  33.     (
  34.  
  35.      CmdLeftChar,            {1. Left character}
  36.      CmdRightChar,           {2. Right character}
  37.      CmdLeftWord,            {3. Left lexeme}
  38.      CmdRightWord,           {4. Right lexeme}
  39.      CmdUpLine,              {5. Up line}
  40.      CmdDownLine,            {6. Down line}
  41.      CmdScrollUp,            {7. Scroll up}
  42.      CmdScrollDown,          {8. Scroll down}
  43.      CmdUpPage,              {9. Up page}
  44.      CmdDownPage,            {10. Down page}
  45.  
  46.      CmdNull,
  47.  
  48.      CmdLeftLine,            {11. Cursor to left side}
  49.      CmdRightLine,           {12. Cursor to right side}
  50.      CmdTopScreen,           {13. Top of screen}
  51.      CmdBottomScreen,        {14. Bottom of screen}
  52.      CmdWindowTopFile,       {15. Top of window}
  53.      CmdWindowBottomFile,    {16. Bottom of window}
  54.      CmdJumpTopOfBlock,      {21. Top of block}
  55.      CmdJumpBottomBlock,     {22. Bottom of block}
  56.      CmdJumpLastPosition,    {23. Previous cursor position}
  57.  
  58.      CmdNull,
  59.  
  60.      CmdNewLine,             {0. New line in text buffer}
  61.      CmdInsertLine,          {29. Inserting line}
  62.      CmdToggleInsert,        {28. Toggle insert mode}
  63.      CmdDeleteLine,          {30. Delete line}
  64.      CmdDeleteLineRight,     {31. Delete line right of cursor}
  65.      CmdDeleteRightWord,     {32. Delete right lexeme}
  66.      CmdDeleteRightChar,     {33. Delete current character}
  67.      CmdDeleteLeftChar,      {34. Delete left character}
  68.  
  69.      CmdNull,
  70.  
  71.      CmdBlockBegin,          {35. Begin block}
  72.      CmdBlockEnd,            {36. End block}
  73.      CmdBlockWord,           {37. Mark current word as block}
  74.      CmdBlockHide,           {38. Hide/display toggle block}
  75.      CmdBlockCopy,           {43. Copy block}
  76.      CmdBlockMove,           {44. Move block}
  77.      CmdBlockDelete,         {45. Delete block}
  78.      CmdReadBlock,           {46. Read file into window}
  79.      CmdWriteBlock,          {47. Write block to file}
  80.      CmdPrintBlock,          {49. Print block}
  81.  
  82.      CmdNull,
  83.  
  84.      CmdSetMarker0,          {39. Set marker 0}
  85.      CmdSetMarker1,          {40. Set marker 0}
  86.      CmdSetMarker2,          {41. Set marker 0}
  87.      CmdSetMarker3,          {42. Set marker 0}
  88.      CmdJumpMarker0,         {24. Jump to marker 0}
  89.      CmdJumpMarker1,         {25. Jump to marker 1}
  90.      CmdJumpMarker2,         {26. Jump to marker 2}
  91.      CmdJumpMarker3,         {27. Jump to marker 3}
  92.  
  93.      CmdNull,
  94.  
  95.      CmdFind,                {59. Find pattern}
  96.      CmdFindReplace,         {60. Find and replace}
  97.      CmdFindNext,            {61. Find next}
  98.  
  99.      CmdNull,
  100.  
  101.      CmdTab,                 {51. Tab, either fixed or "smart"}
  102.      CmdToggleAutoindent,    {52. Toggle autoindent mode}
  103.      CmdToggleFixedTabs,     {53. Toggle fixed tabs}
  104.  
  105.      CmdNull,
  106.  
  107.      CmdSaveQuit,            {50. Save file and exit}
  108.      CmdRestoreCurrentLine,  {58. Restore line as on entry}
  109.      CmdInsertCtrlChar       {62. Insert control character}
  110.      );
  111.  
  112.   var
  113.     Title : VarString;
  114.     Quitting : Boolean;
  115.     Wrote : Boolean;
  116.     CmdLen : Integer;
  117.     CuPacked, WsPacked : PackedCommandList;
  118.     MinCmd, MaxCmd : CommandType;
  119.     CH : Char;
  120.     KeyOfs : LongInt;
  121.     CmdsRead : Integer;
  122.  
  123.     procedure InitializeScreen;
  124.       {-Set up for full screen key editor}
  125.     begin
  126.       ClrScr;
  127.       GoToXY(1, 1);
  128.       Title := CenterPad(' Installing: '+ProgName+' ', '═', 80);
  129.       Center(1, TiColor, Title);
  130.     end;
  131.  
  132.     function FindKeys(var IRec : InstRec) : LongInt;
  133.       {-Read the command definitions into memory}
  134.     var
  135.       FO : LongInt;
  136.     begin                    {FindKeys}
  137.       {Search the work area}
  138.       FO := FindString(KIDstring, IRec, SizeOf(InstRec));
  139.       if FO = 0 then
  140.         HaltError('Unable to locate keyboard installation area');
  141.  
  142.       {Check the number of bytes in the command list}
  143.       if IRec.Len <> CmdListBytes then
  144.         HaltError('Command list is wrong size. '+ProgName+' may be corrupted.');
  145.  
  146.       {Return the offset of the command list}
  147.       FindKeys := FO;
  148.     end;                     {FindKeys}
  149.  
  150.     procedure InitializeCommands(var Commands : CommandList);
  151.       {-Initialize the titles of each command}
  152.     var
  153.       C : CommandType;
  154.  
  155.     begin                    {InitializeCommands}
  156.  
  157.       for C := MinCmd to CmdNull do
  158.         with Commands[C] do begin
  159.           with Main do begin
  160.             Keys := '';
  161.             Modified := False;
  162.             Conflict := False;
  163.             MinCol := PrimeMinCol;
  164.             MaxCol := PrimeMaxCol;
  165.           end;
  166.           with Alt do begin
  167.             Keys := '';
  168.             Modified := False;
  169.             Conflict := False;
  170.             MinCol := SecndMinCol;
  171.             MaxCol := SecndMaxCol;
  172.           end;
  173.           case C of
  174.             CmdLeftChar : Name := 'Character left';
  175.             CmdRightChar : Name := 'Character right';
  176.             CmdLeftWord : Name := 'Word left';
  177.             CmdRightWord : Name := 'Word right';
  178.             CmdUpLine : Name := 'Line up';
  179.             CmdDownLine : Name := 'Line down';
  180.             CmdScrollUp : Name := 'Scroll up';
  181.             CmdScrollDown : Name := 'Scroll down';
  182.             CmdUpPage : Name := 'Page up';
  183.             CmdDownPage : Name := 'Page down';
  184.  
  185.             CmdLeftLine : Name := 'Cursor to left side';
  186.             CmdRightLine : Name := 'Cursor to right side';
  187.             CmdTopScreen : Name := 'Top of screen';
  188.             CmdBottomScreen : Name := 'Bottom of screen';
  189.             CmdWindowTopFile : Name := 'Top of window';
  190.             CmdWindowBottomFile : Name := 'Bottom of window';
  191.             CmdJumpTopOfBlock : Name := 'Top of block';
  192.             CmdJumpBottomBlock : Name := 'Bottom of block';
  193.             CmdJumpLastPosition : Name := 'Previous cursor position';
  194.  
  195.             CmdNewLine : Name := 'New line';
  196.             CmdInsertLine : Name := 'Insert line';
  197.             CmdToggleInsert : Name := 'Toggle insert mode';
  198.             CmdDeleteLine : Name := 'Delete line';
  199.             CmdDeleteLineRight : Name := 'Delete line right';
  200.             CmdDeleteRightWord : Name := 'Delete right word';
  201.             CmdDeleteRightChar : Name := 'Delete current character';
  202.             CmdDeleteLeftChar : Name := 'Delete left character';
  203.  
  204.             CmdBlockBegin : Name := 'Begin block';
  205.             CmdBlockEnd : Name := 'End block';
  206.             CmdBlockWord : Name := 'Mark current word';
  207.             CmdBlockHide : Name := 'Toggle block display';
  208.             CmdBlockCopy : Name := 'Copy block';
  209.             CmdBlockMove : Name := 'Move block';
  210.             CmdBlockDelete : Name := 'Delete block';
  211.             CmdReadBlock : Name := 'Read file into window';
  212.             CmdWriteBlock : Name := 'Write block to file';
  213.             CmdPrintBlock : Name := 'Print marked block';
  214.  
  215.             CmdSetMarker0 : Name := 'Set marker 0';
  216.             CmdSetMarker1 : Name := 'Set marker 1';
  217.             CmdSetMarker2 : Name := 'Set marker 2';
  218.             CmdSetMarker3 : Name := 'Set marker 3';
  219.             CmdJumpMarker0 : Name := 'Jump to marker 0';
  220.             CmdJumpMarker1 : Name := 'Jump to marker 1';
  221.             CmdJumpMarker2 : Name := 'Jump to marker 2';
  222.             CmdJumpMarker3 : Name := 'Jump to marker 3';
  223.  
  224.             CmdFind : Name := 'Find pattern';
  225.             CmdFindReplace : Name := 'Find and replace';
  226.             CmdFindNext : Name := 'Find next';
  227.  
  228.             CmdTab : Name := 'Tab';
  229.             CmdToggleAutoindent : Name := 'Toggle autoindent mode';
  230.             CmdToggleFixedTabs : Name := 'Toggle fixed tabs';
  231.  
  232.             CmdSaveQuit : Name := 'Exit editor';
  233.             CmdRestoreCurrentLine : Name := 'Restore line';
  234.             CmdInsertCtrlChar : Name := 'Insert control char';
  235.           else
  236.             Name := '';
  237.           end;
  238.         end;
  239.     end;                     {InitializeCommands}
  240.  
  241.     procedure ParsePackedCommands(var CuPacked, WsPacked : PackedCommandList;
  242.                                   var Commands : CommandList);
  243.       {-fill in the structured command array from the packed tables}
  244.     var
  245.       pCu, pWs, Len : Integer;
  246.       C : CommandType;
  247.  
  248.     begin                    {ParsePackedCommands}
  249.       pCu := 1;
  250.       pWs := 1;
  251.  
  252.       for C := MinCmd to MaxCmd do begin
  253.         with Commands[C] do begin
  254.           with Alt do begin
  255.             Len := Succ(Ord(CuPacked[pCu]));
  256.             Move(CuPacked[pCu], Keys[0], Len);
  257.             if Keys = #$FF then
  258.               Keys := '';
  259.             pCu := pCu+Len;
  260.           end;
  261.  
  262.           with Main do begin
  263.             Len := Succ(Ord(WsPacked[pWs]));
  264.             Move(WsPacked[pWs], Keys[0], Len);
  265.             if Keys = #$FF then
  266.               Keys := '';
  267.             pWs := pWs+Len;
  268.           end;
  269.         end;
  270.       end;
  271.     end;                     {ParsePackedCommands}
  272.  
  273.     procedure DisplayKeys(TheColor, R : Byte; K : KeyRec);
  274.       {-display the stored keystrokes}
  275.     var
  276.       Txt, Dis : VarString;
  277.       Len : Byte;
  278.       TxtLen : Byte absolute Txt;
  279.  
  280.     begin                    {DisplayKeys}
  281.       with K do begin
  282.         Len := Succ(MaxCol-MinCol);
  283.         Txt := TextRepresentation(K);
  284.         Dis := Pad(Copy(Txt, 1, Len), Len);
  285.         EdFastWrite(Dis, R, MinCol, TheColor);
  286.         if TxtLen > Len then
  287.           GoToXY(MinCol+Len, R)
  288.         else
  289.           GoToXY(MinCol+Length(Txt), R);
  290.       end;
  291.     end;                     {DisplayKeys}
  292.  
  293.     procedure DisplayCommand(C : CommandType; R : Byte);
  294.       {-display a command and its keys}
  295.  
  296.     begin                    {DisplayCommand}
  297.       if C = CmdNull then
  298.         {Draw a separator bar}
  299.         Center(R, TiColor, '────────────────────────────────────────────────────────────────────────────────')
  300.       else
  301.         with Commands[C] do begin
  302.           ClrEol(1, R, TiColor);
  303.           EdFastWrite(Name, R, 1, TiColor);
  304.  
  305.           {Write WordStar keystrokes}
  306.           EdFastWrite('P:', R, PrimeCmdCol, TiColor);
  307.           if Main.Conflict then
  308.             DisplayKeys(CfColor, R, Main)
  309.           else if Main.Modified then
  310.             DisplayKeys(ChColor, R, Main)
  311.           else
  312.             DisplayKeys(LoColor, R, Main);
  313.  
  314.           {Write custom keystrokes}
  315.           EdFastWrite('S:', R, SecndCmdCol, TiColor);
  316.           if Alt.Conflict then
  317.             DisplayKeys(CfColor, R, Alt)
  318.           else if Alt.Modified then
  319.             DisplayKeys(ChColor, R, Alt)
  320.           else
  321.             DisplayKeys(LoColor, R, Alt);
  322.         end;
  323.     end;                     {DisplayCommand}
  324.  
  325.     function GetKeys(R : Byte; var K : KeyRec; var StopNow : Boolean) : Boolean;
  326.       {-edit a key sequence, default keys as input, keys also return result}
  327.       {-return true if keys were modified in the process}
  328.     const
  329.       ScrollMask = $10;
  330.     var
  331.       Quitting : Boolean;
  332.       CH : Char;
  333.       Buf : KeyString;
  334.       ScrollLock, LastScroll : Byte;
  335.       KbFlag : Byte absolute $0040 : $0017;
  336.  
  337.     begin                    {GetKeys}
  338.       StopNow := False;
  339.       LastScroll := $FF;
  340.  
  341.       with K do begin
  342.  
  343.         {Buffer the keystrokes so they can be restored}
  344.         Buf := Keys;
  345.  
  346.         Quitting := False;
  347.         repeat
  348.           DisplayKeys(EdColor, R, K);
  349.  
  350.           repeat
  351.             {Watch the scroll state while waiting for a keystroke}
  352.             ScrollLock := KbFlag and ScrollMask;
  353.             if ScrollLock <> LastScroll then begin
  354.               if ScrollLock <> 0 then
  355.                 EdFastWrite('Literal', 1, 70, LoColor)
  356.               else
  357.                 EdFastWrite('Command', 1, 70, LoColor);
  358.               LastScroll := ScrollLock;
  359.             end;
  360.           until KeyPressed;
  361.  
  362.           CH := ReadKey;
  363.  
  364.           if ScrollLock <> 0 then begin
  365.             {literal mode}
  366.             if CH = #0 then begin
  367.               CH := ReadKey;
  368.               if Length(Keys) < Pred(KeyLength) then
  369.                 Keys := Keys+#0+CH;
  370.             end else if Length(Keys) < KeyLength then
  371.               Keys := Keys+CH;
  372.  
  373.           end else
  374.             {command mode}
  375.             case Upcase(CH) of
  376.               #0 :
  377.                 begin
  378.                   CH := ReadKey;
  379.                   if Length(Keys) < Pred(KeyLength) then
  380.                     Keys := Keys+#0+CH;
  381.                 end;
  382.  
  383.               ^M :
  384.                 Quitting := True;
  385.  
  386.               ^H :           {backspace}
  387.                 if Length(Keys) > 0 then begin
  388.                   Delete(Keys, Length(Keys), 1);
  389.                   if (Length(Keys) > 0) and (Keys[Length(Keys)] = #0) then
  390.                     Delete(Keys, Length(Keys), 1);
  391.                 end;
  392.  
  393.               'C' :
  394.                 Keys := '';  {erase}
  395.  
  396.               'R' :
  397.                 Keys := Buf; {restore original}
  398.  
  399.               #32..#47,
  400.               #58..#126,
  401.               #128..#255 : {ignore regular characters} ;
  402.  
  403.               Escape :
  404.                 begin
  405.                   StopNow := True;
  406.                   Quitting := True;
  407.                 end;
  408.  
  409.             else
  410.               if Length(Keys) < KeyLength then
  411.                 Keys := Keys+CH;
  412.             end;
  413.         until Quitting;
  414.         GetKeys := (Keys <> Buf);
  415.         EdFastWrite('═══════', 1, 70, TiColor);
  416.  
  417.       end;
  418.     end;                     {GetKeys}
  419.  
  420.     procedure EditKeys(R : Byte; var K : KeyRec);
  421.       {-edit one key record}
  422.     var
  423.       StopNow : Boolean;
  424.  
  425.     begin                    {EditKeys}
  426.       Center(2, EdColor, EditPrompt);
  427.       with K do begin
  428.         Modified := GetKeys(R, K, StopNow);
  429.         if Modified then begin
  430.           DisplayKeys(ChColor, R, K);
  431.           Conflict := False;
  432.         end else if Conflict then
  433.           DisplayKeys(CfColor, R, K)
  434.         else
  435.           DisplayKeys(LoColor, R, K);
  436.       end;
  437.       Center(2, TiColor, BrowsePrompt);
  438.     end;                     {Editkeys}
  439.  
  440.     procedure DrawFullPage(CmdStart : Integer);
  441.       {-write a full page of commands, starting at cmdstart}
  442.     var
  443.       R : Byte;
  444.       C : Integer;
  445.  
  446.     begin                    {DrawFullPage}
  447.       R := FirstRow;
  448.       C := CmdStart;
  449.       while (R <= LastRow) and (C <= MaxDisplay) do begin
  450.         DisplayCommand(OrderMap[C], R);
  451.         Inc(R);
  452.         Inc(C);
  453.       end;
  454.     end;                     {DrawFullPage}
  455.  
  456.     procedure EditCommands;
  457.       {-Allow browsing and changing of command keys in range minc to maxc}
  458.     var
  459.       Quitting : Boolean;
  460.       OldTopC, TopC, CurC : Integer;
  461.       R, Curr : Byte;
  462.       CurCmd : CommandType;
  463.       K : KeyRec;
  464.       OnMain : Boolean;
  465.  
  466.     begin                    {EditCommands}
  467.  
  468.       Center(2, TiColor, BrowsePrompt);
  469.       Center(3, TiColor, '════════════════════════════════════════════════════════════════════════════════');
  470.       TopC := 1;
  471.       CurC := 1;
  472.       Curr := FirstRow;
  473.       DrawFullPage(TopC);
  474.       OnMain := True;
  475.  
  476.       Quitting := False;
  477.       repeat
  478.  
  479.         {Handle display mapping}
  480.         CurCmd := OrderMap[CurC];
  481.  
  482.         if OnMain then
  483.           K := Commands[CurCmd].Main
  484.         else
  485.           K := Commands[CurCmd].Alt;
  486.  
  487.         GoToXY(K.MinCol, Curr);
  488.  
  489.         case GetCursorCommand of
  490.  
  491.           ^M :               {Edit key}
  492.             if (CurCmd <> CmdNull) then begin
  493.               EditKeys(Curr, K);
  494.               if OnMain then
  495.                 Commands[CurCmd].Main := K
  496.               else
  497.                 Commands[CurCmd].Alt := K;
  498.             end;
  499.  
  500.           ^E, ^W :           {Scroll up}
  501.             if CurC > 1 then begin
  502.               Dec(CurC);
  503.               if Curr = FirstRow then begin
  504.                 TopC := CurC;
  505.                 InsLine;
  506.                 DisplayCommand(OrderMap[CurC], FirstRow);
  507.               end else
  508.                 Dec(Curr);
  509.             end;
  510.  
  511.           ^X, ^Z :           {Scroll down}
  512.             if CurC < MaxDisplay then begin
  513.               Inc(CurC);
  514.               if Curr >= LastRow then begin
  515.                 GoToXY(1, FirstRow);
  516.                 DelLine;
  517.                 DisplayCommand(OrderMap[CurC], LastRow);
  518.                 Inc(TopC);
  519.               end else
  520.                 Inc(Curr);
  521.             end;
  522.  
  523.           ^S :               {Move to secondary}
  524.             OnMain := True;
  525.  
  526.           ^D :               {Move to primary}
  527.             OnMain := False;
  528.  
  529.           ^R :               {Page up}
  530.             if CurC > 1 then begin
  531.               OldTopC := TopC;
  532.               R := FirstRow;
  533.               while (CurC > 1) and (R < LastRow) do begin
  534.                 Dec(CurC);
  535.                 Dec(Curr);
  536.                 if Curr < FirstRow then begin
  537.                   TopC := CurC;
  538.                   Curr := FirstRow;
  539.                 end;
  540.                 Inc(R);
  541.               end;
  542.               if TopC <> OldTopC then
  543.                 DrawFullPage(TopC);
  544.             end;
  545.  
  546.           ^C :               {Page down}
  547.             if CurC < MaxDisplay then begin
  548.               R := FirstRow;
  549.               OldTopC := TopC;
  550.               while (CurC < MaxDisplay) and (R < LastRow) do begin
  551.                 Inc(Curr);
  552.                 Inc(CurC);
  553.                 if Curr > LastRow then begin
  554.                   Inc(TopC);
  555.                   Curr := LastRow;
  556.                 end;
  557.                 Inc(R);
  558.               end;
  559.               if TopC <> OldTopC then
  560.                 DrawFullPage(TopC);
  561.             end;
  562.  
  563.           ^T :               {Home}
  564.             if CurC > 1 then begin
  565.               CurC := 1;
  566.               TopC := 1;
  567.               Curr := FirstRow;
  568.               OnMain := True;
  569.               DrawFullPage(TopC);
  570.             end;
  571.  
  572.           ^B :               {End}
  573.             if CurC < MaxDisplay then begin
  574.               Curr := FirstRow;
  575.               CurC := MaxDisplay;
  576.               while Curr < LastRow do begin
  577.                 Inc(Curr);
  578.                 Dec(CurC);
  579.               end;
  580.               TopC := CurC;
  581.               DrawFullPage(TopC);
  582.               CurC := MaxDisplay;
  583.               OnMain := False;
  584.             end;
  585.  
  586.           'R' :              {restore all defaults}
  587.             begin
  588.               Commands := OrigCommands;
  589.               DrawFullPage(TopC);
  590.             end;
  591.  
  592.           Escape :           {done}
  593.             Quitting := True;
  594.  
  595.         end;
  596.       until Quitting;
  597.     end;                     {EditCommands}
  598.  
  599.     procedure FastInstallCommands;
  600.       {-Prompt for commands one by one}
  601.     var
  602.       C : Integer;
  603.       StopNow : Boolean;
  604.       CH : Char;
  605.  
  606.       procedure PromptFor(var keyset : KeyRec);
  607.         {-get the new keyrec for main or alt}
  608.       var
  609.         K : KeyRec;
  610.  
  611.       begin                  {PromptFor}
  612.         K.Keys := '';
  613.         K.MinCol := WhereX;
  614.         K.MaxCol := WhereX+20;
  615.         if GetKeys(WhereY, K, StopNow) then
  616.           {New keystring returned}
  617.           with keyset do begin
  618.             Modified := True;
  619.             Conflict := False;
  620.             Keys := K.Keys;
  621.             DisplayKeys(ChColor, WhereY, K);
  622.           end
  623.         else
  624.           {Accepted default}
  625.           DisplayKeys(LoColor, WhereY, K);
  626.         WriteLn;
  627.       end;                   {PromptFor}
  628.  
  629.     begin                    {FastInstallCommands}
  630.       WriteLn;
  631.       WriteLn('Press <Enter> to accept default');
  632.       WriteLn('Press keys followed by <Enter> for new key sequence');
  633.       WriteLn('Press <Bksp> to back up one keystroke, C to Clear, R to Restore');
  634.       WriteLn('Press <Scroll Lock> to toggle literal mode');
  635.       WriteLn('Press <Escape> to quit entering commands');
  636.       WriteLn('Random access editing is available when you are finished');
  637.       WriteLn;
  638.  
  639.       C := 1;
  640.       StopNow := False;
  641.       while not(StopNow) and (C <= MaxDisplay) do begin
  642.         with Commands[OrderMap[C]] do begin
  643.           Write(Pad(Name, 26), '( Primary ): ', Pad(TextRepresentation(Main), 18), ' ');
  644.           PromptFor(Main);
  645.           if not(StopNow) then begin
  646.             Write(Pad(Name, 26), '(Secondary): ', Pad(TextRepresentation(Alt), 18), ' ');
  647.             PromptFor(Alt);
  648.           end;
  649.         end;
  650.         repeat
  651.           Inc(C);
  652.         until (C > MaxDisplay) or (OrderMap[C] <> CmdNull);
  653.       end;
  654.       WriteLn;
  655.       Write('Press a key to invoke full screen key editor ');
  656.       CH := ReadKey;
  657.     end;                     {FastInstallCommands}
  658.  
  659.     function CheckCommands(var Commands : CommandList) : Boolean;
  660.       {-Return true if no duplicate commands are found, else complain}
  661.     var
  662.       FCmd, TCmd : CommandType;
  663.       Ok : Boolean;
  664.       Cnt : Integer;
  665.       CntStr : VarString;
  666.  
  667.       function Conflicting(FCmd, TCmd : CommandType) : Boolean;
  668.         {-return true, and set appropriate flags if any conflict}
  669.       var
  670.         FMain, Falt, TMain, TAlt : KeyString;
  671.         Ok : Boolean;
  672.  
  673.       begin                  {Conflicting}
  674.         Ok := True;
  675.         with Commands[FCmd] do begin
  676.           FMain := Main.Keys;
  677.           Falt := Alt.Keys;
  678.         end;
  679.         with Commands[TCmd] do begin
  680.           TMain := Main.Keys;
  681.           TAlt := Alt.Keys;
  682.         end;
  683.         if FMain <> '' then begin
  684.           if Pos(FMain, TMain) = 1 then begin
  685.             Ok := False;
  686.             Commands[FCmd].Main.Conflict := True;
  687.             Commands[TCmd].Main.Conflict := True;
  688.           end;
  689.           if Pos(FMain, TAlt) = 1 then begin
  690.             Ok := False;
  691.             Commands[FCmd].Main.Conflict := True;
  692.             Commands[TCmd].Alt.Conflict := True;
  693.           end;
  694.         end;
  695.         if TMain <> '' then begin
  696.           if Pos(TMain, FMain) = 1 then begin
  697.             Ok := False;
  698.             Commands[TCmd].Main.Conflict := True;
  699.             Commands[FCmd].Main.Conflict := True;
  700.           end;
  701.           if Pos(TMain, Falt) = 1 then begin
  702.             Ok := False;
  703.             Commands[TCmd].Main.Conflict := True;
  704.             Commands[FCmd].Alt.Conflict := True;
  705.           end;
  706.         end;
  707.         if TAlt <> '' then begin
  708.           if Pos(TAlt, FMain) = 1 then begin
  709.             Ok := False;
  710.             Commands[TCmd].Alt.Conflict := True;
  711.             Commands[FCmd].Main.Conflict := True;
  712.           end;
  713.           if Pos(TAlt, Falt) = 1 then begin
  714.             Ok := False;
  715.             Commands[TCmd].Alt.Conflict := True;
  716.             Commands[FCmd].Alt.Conflict := True;
  717.           end;
  718.         end;
  719.         if Falt <> '' then begin
  720.           if Pos(Falt, TMain) = 1 then begin
  721.             Ok := False;
  722.             Commands[FCmd].Alt.Conflict := True;
  723.             Commands[TCmd].Main.Conflict := True;
  724.           end;
  725.           if Pos(Falt, TAlt) = 1 then begin
  726.             Ok := False;
  727.             Commands[FCmd].Alt.Conflict := True;
  728.             Commands[TCmd].Alt.Conflict := True;
  729.           end;
  730.         end;
  731.         Conflicting := not(Ok);
  732.       end;                   {Conflicting}
  733.  
  734.     begin                    {CheckCommands}
  735.       {Provide some reassurance}
  736.       ClrEol(1, 1, LoColor);
  737.       EdFastWrite('Checking for conflicts....', 1, 1, LoColor);
  738.  
  739.       {Reset previous conflicts}
  740.       for FCmd := MinCmd to MaxCmd do
  741.         with Commands[FCmd] do begin
  742.           Main.Conflict := False;
  743.           Alt.Conflict := False;
  744.         end;
  745.  
  746.       Ok := True;
  747.       Cnt := 0;
  748.  
  749.       for FCmd := MinCmd to MaxCmd do begin
  750.         {Keep status going}
  751.         Cnt := Succ(Cnt);
  752.         Str(Cnt:4, CntStr);
  753.         EdFastWrite(CntStr, 1, 28, LoColor);
  754.  
  755.         {Don't waste space on duplicate commands}
  756.         with Commands[FCmd] do
  757.           if Main.Keys = Alt.Keys then begin
  758.             Alt.Keys := '';
  759.             Alt.Conflict := False;
  760.             Alt.Modified := False;
  761.           end;
  762.  
  763.         if Commands[FCmd].Main.Modified or Commands[FCmd].Alt.Modified then
  764.           {Now compare for conflicts}
  765.           for TCmd := MinCmd to MaxCmd do
  766.             if (TCmd <> FCmd) then
  767.               if Conflicting(FCmd, TCmd) then
  768.                 Ok := False;
  769.  
  770.       end;
  771.       ClrEol(1, 1, LoColor);
  772.       CheckCommands := Ok;
  773.     end;                     {CheckCommands}
  774.  
  775.     procedure PackCommands(var Commands : CommandList;
  776.                            var CuPacked, WsPacked : PackedCommandList;
  777.                            var CmdLen : Integer);
  778.       {-Rebuild the packed command structure}
  779.     var
  780.       C : CommandType;
  781.       Len, pNew, pCu, pWs : Integer;
  782.  
  783.     begin                    {PackCommands}
  784.       FillChar(CuPacked, SizeOf(CuPacked), 0);
  785.       FillChar(WsPacked, SizeOf(WsPacked), 0);
  786.  
  787.       pCu := 1;
  788.       pWs := 1;
  789.  
  790.       for C := MinCmd to MaxCmd do
  791.         with Commands[C] do begin
  792.  
  793.           {Repack the custom keystrokes}
  794.           with Alt do begin
  795.             {Unused entries are represented by character 255}
  796.             if Keys = '' then
  797.               Keys := #$FF;
  798.             Len := Succ(Length(Keys));
  799.             pNew := pCu+Len;
  800.             {Assure we don't overflow the table}
  801.             if pNew <= CmdListBytes then
  802.               Move(Keys, CuPacked[pCu], Len);
  803.             pCu := pNew;
  804.           end;
  805.  
  806.           {Repack the WordStar keystrokes}
  807.           with Main do begin
  808.             if Keys = '' then
  809.               Keys := #$FF;
  810.             Len := Succ(Length(Keys));
  811.             pNew := pWs+Len;
  812.             if pNew <= CmdListBytes then
  813.               Move(Keys, WsPacked[pWs], Len);
  814.             pWs := pNew;
  815.           end;
  816.         end;
  817.  
  818.       {Return the maximum of the two command buffer lengths}
  819.       CmdLen := pCu;
  820.       if pWs > CmdLen then
  821.         CmdLen := pWs;
  822.     end;                     {PackCommands}
  823.  
  824.   begin
  825.  
  826.     ClrScr;
  827.  
  828.     {commands with the lowest/highest ordinal values}
  829.     MinCmd := CmdNewLine;
  830.     MaxCmd := CmdInsertCtrlChar;
  831.  
  832.     InitializeScreen;
  833.     GoToXY(1, 3);
  834.  
  835.     KeyOfs := FindKeys(OurInstRec);
  836.     CuPacked := OurInstRec.PCList1;
  837.     WsPacked := OurInstRec.PCList2;
  838.  
  839.     InitializeCommands(Commands);
  840.     ParsePackedCommands(CuPacked, WsPacked, Commands);
  841.     OrigCommands := Commands;
  842.  
  843.     if YesNo('Perform fast entry of fully reconfigured keyboard?', 'N') then
  844.       {Sequential installation}
  845.       FastInstallCommands;
  846.  
  847.     InitializeScreen;
  848.  
  849.     Quitting := False;
  850.     repeat
  851.  
  852.       {Random access editing}
  853.       EditCommands;
  854.  
  855.       SetColor(LoColor);
  856.       ClrEol(1, 1, LoColor);
  857.       ClrEol(1, 2, LoColor);
  858.       GoToXY(1, 1);
  859.       CH := Getkey('W to install keyboard, Q to quit: ', 'WQ');
  860.       Write(CH);
  861.       GoToXY(1, 1);
  862.  
  863.       case CH of
  864.         'W' :
  865.           begin
  866.             if CheckCommands(Commands) then begin
  867.               PackCommands(Commands, CuPacked, WsPacked, CmdLen);
  868.               if CmdLen > CmdListBytes then begin
  869.                 ClrEol(1, 1, EdColor);
  870.                 EdFastWrite('Command keys exceed available space. Press a key to continue...', 1, 1, EdColor);
  871.               end else begin
  872.                 Wrote := True;
  873.                 Quitting := True;
  874.               end;
  875.             end else begin
  876.               ClrEol(1, 1, EdColor);
  877.               EdFastWrite('Command conflicts found and marked. Press a key to correct...', 1, 1, EdColor);
  878.               CH := ReadKey;
  879.               Center(1, TiColor, Title);
  880.             end;
  881.           end;
  882.         'Q' :
  883.           begin
  884.             Wrote := False;
  885.             Quitting := True;
  886.           end;
  887.       end;
  888.     until Quitting;
  889.  
  890.     if Wrote then begin
  891.       ClrEol(1, 1, LoColor);
  892.       EdFastWrite('Updating '+ProgName+'...', 1, 1, LoColor);
  893.       OurInstRec.PCList1 := CuPacked;
  894.       OurInstRec.PCList2 := WsPacked;
  895.       if not ModifyDefaults(KeyOfs, OurInstRec, SizeOf(InstRec)) then
  896.         HaltError('Error writing to keyboard installation area');
  897.     end;
  898.  
  899.   end;                       {KeyInstall}
  900.