Страница 1 из 1

Работа с консолью

СообщениеДобавлено: 11.10.2014 13:27:08
vas-vas
FPC 2.6.4 / Windows 7 x64 /
Задача: с экрана (консоль) считать символ и его атрибут.

На BorlandPascal делалось примерно так...
type
TEkr= array[1..2000,1..2] of byte;
var
Ekran : TEkr absolute $B800:$0000;
begin
{ читаем с массива что хотим }
end.

На такую конструкцию идет ошибка: 2.pas(4,29) Fatal: Syntax error, ";" expected but ":" found
как это можно сделать в FPC ? если можно с примером.

Re: Работа с консолью

СообщениеДобавлено: 11.10.2014 15:44:41
Дож
Для начала рекомендую попробовать модуль video:

Код: Выделить всё
uses
  video;

var
  Cell: TVideoCell;

begin
  InitVideo;
  Cell := VideoBuf^[ScreenWidth * (ScreenHeight - 1)];
  Writeln('Char: $',      HexStr(Cell and $FF, 2), ', ',
          'Color: ',      (Cell shr 8) and $F, ', ',
          'Background: ', (Cell shr 8) and $70, ', ',
          'Blinking: ',   (Cell shr 8) and $A0 > 0);
  DoneVideo;
end.

Технически он подходит под задачу, но на практике имеет странности (в частности, в винде предварительно очищает экран после запуска).

Re: Работа с консолью

СообщениеДобавлено: 11.10.2014 21:06:18
vas-vas
Спасибо. Давно в руки паскаль не брал. Как все усложнилось, главное что понятно, то что написано. ;)

Добавлено спустя 21 час 39 минут 16 секунд:
Код: Выделить всё
InitVideo;
  gotoxy(1,1);
  writeln('1');
  Writeln('Char kod:', (VideoBuf^[0] and $FF) );
  DoneVideo;

получаем:
1
Char kod:32 (тут не правильно)

----------------------------------------------
а если
Код: Выделить всё
  InitVideo;
//                           символ     цвет      фон
  VideoBuf^[0]:=byte('1')    +   ((7 +       (0 shl 4)) shl 8);
  UpdateScreen(false);
  Writeln('Char kod:', (VideoBuf^[0] and $FF) );
  DoneVideo;

получаем:
1
Char kod:49 (тут правильно)

На экран выводит то что надо в обоих вариантах. Определяет символ неправильно. Почему?

Re: Работа с консолью

СообщениеДобавлено: 13.10.2014 12:43:22
Дож
На экран выводит то что надо в обоих вариантах. Определяет символ неправильно. Почему?

Во-первых, модуль video не делает чуда и то, что выведено каким-то другим способом, само в VideoBuf не попадёт. Поэтому выводить нужно через video. Если же требуется прочитать что напечатал другой код или уже есть много кода со всякими Writeln, который нет возможности переписать, то придётся использовать чистый WinApi, никуда не деться:
Код: Выделить всё
uses
  windows;

var
  Stdout, ScreenBuffer: HANDLE;
  Buf: array[0..24] of array[0..79] of TCharInfo;
  BufPos, BufSize: TCoord;
  ReadRect: TSmallRect;
  Security: TSecurityAttributes;
  Info: TConsoleScreenBufferInfo;

begin
  Writeln(Char(49));

  FillChar(Security, SizeOf(Security), 0);
  Stdout := GetStdHandle(STD_OUTPUT_HANDLE);
  ScreenBuffer := CreateConsoleScreenBuffer(
    GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE,
    Security, CONSOLE_TEXTMODE_BUFFER, nil);
  GetConsoleScreenBufferInfo(Stdout, @Info);

  ReadRect.Top := Info.srWindow.Bottom - Length(Buf);
  ReadRect.Left := 0;
  ReadRect.Bottom := Info.srWindow.Bottom;
  ReadRect.Right := Length(Buf[0]);

  BufPos.X := 0;
  BufPos.Y := 0;
  BufSize.X := Length(Buf[0]);
  BufSize.Y := Length(Buf);

  if (Stdout = INVALID_HANDLE_VALUE) or
     (ScreenBuffer = INVALID_HANDLE_VALUE) or
    (not SetConsoleActiveScreenBuffer(ScreenBuffer)) or
    (not ReadConsoleOutput(Stdout, @Buf[0][0], BufSize, BufPos, ReadRect)) then
    Halt(5);

  Writeln('Char code: ', Ord(Buf[High(Buf)][0].AsciiChar));
end.


Во-вторых, по той ссылке, которую я дал, прямым текстом написано:
Remark: The video unit should not be used together with the crt unit. Doing so will result in very strange behaviour, possibly program crashes.