Консоль + клавиатура

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Консоль + клавиатура

Сообщение still » 21.11.2015 00:05:12

Есть: Lazarus+Linux
Есть консольно приложение, которое выводит содержимое файла, и содержит еще пару рабочих потоков.
Как этим потокам что либо передать с клавиатуры?
Read в потоке - плохой вариант, так как весь мусор появляется на экране.

Каким образом это решается?
Аватара пользователя
still
новенький
 
Сообщения: 40
Зарегистрирован: 01.10.2015 11:11:48

Re: Консоль + клавиатура

Сообщение still » 24.11.2015 00:23:45

Ладно, пока вырезал вот такого кадавра из CRT. Потом разберемся что к чему. Это вроде работает.

Код: Выделить всё
//------------------------------------------------------------------------------
// Cut from CRT.pas
//------------------------------------------------------------------------------

unit KeyboardWork;

{$mode objfpc}{$H+}

interface

uses
BaseUnix ,unix, termio,
Classes, SysUtils;


function ReadKey:char;

implementation



{*************************************************************************
                            KeyBoard
*************************************************************************}

Const
  InSize=256;
  OutSize=1024;
  KeyBufferSize = 20;
  ttyIn=0;  {Handles for stdin/stdout}

var
  KeyBuffer : Array[0..KeyBufferSize-1] of Char;
  KeyPut,
  KeySend   : longint;
  InCnt: longint;
  InHead: longint;
  InTail : longint;
  InBuf  : array[0..InSize-1] of char;


Procedure PushKey(Ch:char);
Var
  Tmp : Longint;
Begin
  Tmp:=KeyPut;
  Inc(KeyPut);
  If KeyPut>=KeyBufferSize Then
   KeyPut:=0;
  If KeyPut<>KeySend Then
   KeyBuffer[Tmp]:=Ch
  Else
   KeyPut:=Tmp;
End;



Function PopKey:char;
Begin
  If KeyPut<>KeySend Then
   Begin
     PopKey:=KeyBuffer[KeySend];
     Inc(KeySend);
     If KeySend>=KeyBufferSize Then
      KeySend:=0;
   End
  Else
   PopKey:=#0;
End;



Procedure PushExt(b:byte);
begin
  PushKey(#0);
  PushKey(chr(b));
end;



{Get Char from Remote}
function ttyRecvChar:char;
var
  Readed,i : longint;
begin
{Buffer Empty? Yes, Input from StdIn}
  if (InHead=InTail) then
   begin
   {Calc Amount of Chars to Read}
     i:=InSize-InHead;
     if InTail>InHead then
      i:=InTail-InHead;
   {Read}
     Readed:=fpread(TTYIn, InBuf[InHead],i);
   {Increase Counters}
     inc(InCnt,Readed);
     inc(InHead,Readed);
   {Wrap if End has Reached}
     if InHead>=InSize then
      InHead:=0;
   end;
{Check Buffer}
  if (InCnt=0) then
   ttyRecvChar:=#0
  else
   begin
     ttyRecvChar:=InBuf[InTail];
     dec(InCnt);
     inc(InTail);
     if InTail>=InSize then
      InTail:=0;
   end;
end;


const
  AltKeyStr  : string[38]='qwertyuiopasdfghjklzxcvbnm1234567890-=';
  AltCodeStr : string[38]=#016#017#018#019#020#021#022#023#024#025#030#031#032#033#034#035#036#037#038+
                          #044#045#046#047#048#049#050#120#121#122#123#124#125#126#127#128#129#130#131;
Function FAltKey(ch:char):byte;
var
  Idx : longint;
Begin
  Idx:=Pos(ch,AltKeyStr);
  if Idx>0 then
   FAltKey:=byte(AltCodeStr[Idx])
  else
   FAltKey:=0;
End;

{ This one doesn't care about keypresses already processed by readkey  }
{ and waiting in the KeyBuffer, only about waiting keypresses at the   }
{ TTYLevel (including ones that are waiting in the TTYRecvChar buffer) }
function sysKeyPressed: boolean;
var
  fdsin : tfdSet;
begin
  if (InCnt>0) then
   sysKeyPressed:=true
  else
   begin
     fpFD_ZERO(fdsin);
     fpFD_SET(TTYin,fdsin);
     sysKeypressed:=(fpSelect(TTYIn+1,@fdsin,nil,nil,0)>0);
   end;
end;

Function KeyPressed:Boolean;
Begin
  Keypressed := (KeySend<>KeyPut) or sysKeyPressed;
End;

function ReadKey:char;
Var
  ch       : char;
  OldState,
  State    : longint;
  FDS      : TFDSet;
Begin
{Check Buffer first}
  if KeySend<>KeyPut then
   begin
     ReadKey:=PopKey;
     exit;
   end;
{Wait for Key}
{ Only if none are waiting! (JM) }
  if not sysKeyPressed then
    begin
      FpFD_ZERO (FDS);
      fpFD_SET (0,FDS);
      fpSelect (1,@FDS,nil,nil,nil);
    end;

  ch:=ttyRecvChar;
{Esc Found ?}
  CASE ch OF
  #27: begin
     State:=1;
     Sleep(10);
     { This has to be sysKeyPressed and not "keyPressed", since after }
     { one iteration keyPressed will always be true because of the    }
     { pushKey commands (JM)                                          }
     while (State<>0) and (sysKeyPressed) do
      begin
        ch:=ttyRecvChar;
        OldState:=State;
        State:=0;
        case OldState of
        1 : begin {Esc}
              case ch of
          'a'..'z',
          '0'..'9',
           '-','=' : PushExt(FAltKey(ch));
               #10 : PushKey(#10);
               '[' : State:=2;
{$IFDEF Unix}
              'O': State:=7;
{$ENDIF}
               else
                begin
                  PushKey(ch);
                  PushKey(#27);
                end;
               end;
            end;
        2 : begin {Esc[}
              case ch of
               '[' : State:=3;
               'A' : PushExt(72);
               'B' : PushExt(80);
               'C' : PushExt(77);
               'D' : PushExt(75);
               {$IFDEF FREEBSD}
               {'E' - Center key, not handled in DOS TP7}
               'F' : PushExt(79); {End}
               'G': PushExt(81); {PageDown}
               {$ELSE}
               'G' : PushKey('5'); {Center key, Linux}
               {$ENDIF}
               'H' : PushExt(71);
               {$IFDEF FREEBSD}
               'I' : PushExt(73); {PageUp}
               {$ENDIF}
               'K' : PushExt(79);
               {$IFDEF FREEBSD}
               'L' : PushExt(82);   {Insert - Deekoo}
               'M' : PushExt(59);   {F1-F10 - Deekoo}
               'N' : PushExt(60);   {F2}
               'O' : PushExt(61);   {F3}
               'P' : PushExt(62);   {F4}
               'Q' : PushExt(63);   {F5}
               'R' : PushExt(64);   {F6}
               'S' : PushExt(65);   {F7}
               'T' : PushExt(66);   {F8}
               'U' : PushExt(67);   {F9}
               'V' : PushExt(68);   {F10}
               {Not sure if TP/BP handles F11 and F12 like this normally;
                   In pcemu, a TP7 executable handles 'em this way, though.}
               'W' : PushExt(133);   {F11}
               'X' : PushExt(134);   {F12}
               'Y' : PushExt(84);   {Shift-F1}
               'Z' : PushExt(85);   {Shift-F2}
               'a' : PushExt(86);   {Shift-F3}
               'b' : PushExt(87);   {Shift-F4}
               'c' : PushExt(88);   {Shift-F5}
               'd' : PushExt(89);   {Shift-F6}
               'e' : PushExt(90);   {Shift-F7}
               'f' : PushExt(91);   {Shift-F8}
               'g' : PushExt(92);   {Shift-F9}
               'h' : PushExt(93);   {Shift-F10}
               'i' : PushExt(135);   {Shift-F11}
               'j' : PushExt(136);   {Shift-F12}
               'k' : PushExt(94);        {Ctrl-F1}
               'l' : PushExt(95);
               'm' : PushExt(96);
               'n' : PushExt(97);
               'o' : PushExt(98);
               'p' : PushExt(99);
               'q' : PushExt(100);
               'r' : PushExt(101);
               's' : PushExt(102);
               't' : PushExt(103);   {Ctrl-F10}
               'u' : PushExt(137);   {Ctrl-F11}
               'v' : PushExt(138);   {Ctrl-F12}
               {$ENDIF}
               '1' : State:=4;
               '2' : State:=5;
               '3' : State:=6;
               '4' : PushExt(79);
               '5' : PushExt(73);
               '6' : PushExt(81);
              else
               begin
                 PushKey(ch);
                 PushKey('[');
                 PushKey(#27);
               end;
              end;
              if ch in ['4'..'6'] then
               State:=255;
            end;
        3 : begin {Esc[[}
              case ch of
               'A' : PushExt(59);
               'B' : PushExt(60);
               'C' : PushExt(61);
               'D' : PushExt(62);
               'E' : PushExt(63);
              end;
            end;
        4 : begin {Esc[1}
              case ch of
               '~' : PushExt(71);
               '5' : State := 8;
               '7' : PushExt(64);
               '8' : PushExt(65);
               '9' : PushExt(66);
              end;
              if not (Ch in ['~', '5']) then
               State:=255;
            end;
        5 : begin {Esc[2}
              case ch of
               '~' : PushExt(82);
               '0' : pushExt(67);
               '1' : PushExt(68);
               '3' : PushExt(133); {F11}
                {Esc[23~ is also shift-F1,shift-F11}
               '4' : PushExt(134); {F12}
                {Esc[24~ is also shift-F2,shift-F12}
               '5' : PushExt(86); {Shift-F3}
               '6' : PushExt(87); {Shift-F4}
               '8' : PushExt(88); {Shift-F5}
               '9' : PushExt(89); {Shift-F6}
              end;
              if (Ch<>'~') then
               State:=255;
            end;
        6 : begin {Esc[3}
              case ch of
               '~' : PushExt(83); {Del}
               '1' : PushExt(90); {Shift-F7}
               '2' : PushExt(91); {Shift-F8}
               '3' : PushExt(92); {Shift-F9}
               '4' : PushExt(93); {Shift-F10}
              end;
              if (Ch<>'~') then
               State:=255;
            end;
{$ifdef Unix}
        7 : begin {Esc[O}
              case ch of
               'A' : PushExt(72);
               'B' : PushExt(80);
               'C' : PushExt(77);
               'D' : PushExt(75);
               'P' : PushExt(59);
               'Q' : PushExt(60);
               'R' : PushExt(61);
               'S' : PushExt(62);
              end;
          end;
{$endif}
        8 : begin {Esc[15}
            case ch of
              '~' : PushExt(63);
            end;
          end;
      255 : ;
        end;
        if State<>0 then
         Sleep(10);
      end;
     if State=1 then
      PushKey(ch);
   end;
  #127: PushKey(#8);
  else PushKey(ch);
  End;
  ReadKey:=PopKey;
End;


Procedure Delay(MS: Word);
{
  Wait for DTime milliseconds.
}
Begin
  fpSelect(0,nil,nil,nil,MS);
End;

end.
Аватара пользователя
still
новенький
 
Сообщения: 40
Зарегистрирован: 01.10.2015 11:11:48

Re: Консоль + клавиатура

Сообщение Mirage » 24.11.2015 02:35:26

А где здесь синхронизация? Как это может работать, будучи вызываемым в разных потоках? Тут же data race будет.
А одно лишь то, что оно "вроде работает" еще не значит, что оно работает.

И почему бы не читать с клавиатуры в одном потоке, а затем раздавать прочитанное другим, не забывая синхронизировать доступ?
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Консоль + клавиатура

Сообщение still » 24.11.2015 16:49:16

Mirage писал(а):А где здесь синхронизация? Как это может работать, будучи вызываемым в разных потоках? Тут же data race будет.
А одно лишь то, что оно "вроде работает" еще не значит, что оно работает.

Оно работает. В пустом потоке читаю состояние ReadKey, и раздаю остальным. Собственно и все.

Mirage писал(а):И почему бы не читать с клавиатуры в одном потоке, а затем раздавать прочитанное другим, не забывая синхронизировать доступ

Как это сделать? Чем клаву читать?

Добавлено спустя 2 часа 41 минуту 9 секунд:
Еще вопрос, возможно у TApplication есть какие то методы борьбы с клавиатурой. Должны же быть.

Добавлено спустя 3 минуты 24 секунды:
Точнее у TCustomApplication.
TApplication потянет за собой GUI.
Аватара пользователя
still
новенький
 
Сообщения: 40
Зарегистрирован: 01.10.2015 11:11:48


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 243

Рейтинг@Mail.ru