Browse Source

+ Initial implementation, donated by Hans Lunsing

michael 27 years ago
parent
commit
59456d7671
1 changed files with 580 additions and 0 deletions
  1. 580 0
      rtl/win32/crt.pp

+ 580 - 0
rtl/win32/crt.pp

@@ -0,0 +1,580 @@
+unit WinCrt;
+
+interface
+
+Uses Windows;
+
+type
+  WinReadKeyRecord = record
+    KeyStatus: byte;
+    AsciiChar: char;
+    KeyCode: word;
+  end;
+
+const
+
+// Foreground color constants
+
+fBlack        = 0;
+fBlue         = FOREGROUND_BLUE;
+fGreen        = FOREGROUND_GREEN;
+fCyan         = FOREGROUND_BLUE OR FOREGROUND_GREEN;
+fRed          = FOREGROUND_RED;
+fMagenta      = FOREGROUND_BLUE OR FOREGROUND_RED;
+fBrown        = FOREGROUND_GREEN OR FOREGROUND_RED;
+fLightGray    = FOREGROUND_BLUE OR FOREGROUND_GREEN OR FOREGROUND_RED;
+fDarkGray     = fBlack OR FOREGROUND_INTENSITY;
+fLightBlue    = fBlue OR FOREGROUND_INTENSITY;
+fLightGreen   = fGreen OR FOREGROUND_INTENSITY;
+fLightCyan    = fCyan OR FOREGROUND_INTENSITY;
+fLightRed     = fRed OR FOREGROUND_INTENSITY;
+fLightMagenta = fMagenta OR FOREGROUND_INTENSITY;
+fYellow       = fBrown OR FOREGROUND_INTENSITY;
+fWhite        = fLightGray OR FOREGROUND_INTENSITY;
+
+// Background color constants
+
+bBlack        = 0;
+bBlue         = BACKGROUND_BLUE;
+bGreen        = BACKGROUND_GREEN;
+bCyan         = BACKGROUND_BLUE OR BACKGROUND_GREEN;
+bRed          = BACKGROUND_RED;
+bMagenta      = BACKGROUND_BLUE OR BACKGROUND_RED;
+bBrown        = BACKGROUND_GREEN OR BACKGROUND_RED;
+bLightGray    = BACKGROUND_BLUE OR BACKGROUND_GREEN OR BACKGROUND_RED;
+bDarkGray     = bBlack OR BACKGROUND_INTENSITY;
+bLightBlue    = bBlue OR BACKGROUND_INTENSITY;
+bLightGreen   = bGreen OR BACKGROUND_INTENSITY;
+bLightCyan    = bCyan OR BACKGROUND_INTENSITY;
+bLightRed     = bRed OR BACKGROUND_INTENSITY;
+bLightMagenta = bMagenta OR BACKGROUND_INTENSITY;
+bYellow       = bBrown OR BACKGROUND_INTENSITY;
+bWhite        = bLightGray OR BACKGROUND_INTENSITY;
+
+// Constants designating input events
+
+NO_EVENT = 0;
+KEY_EVENT_IN_PROGRESS = $100;
+_MOUSE_EVENT_IN_PROGRESS = $200;
+
+procedure ClrEol;
+{ Clears all characters from cursor position to end of line without
+  moving the cursor  by filling character cells with blanks
+  and attribute cells with the current screen buffer attribute.
+}
+procedure ClrScr;
+{ Clears screen buffer by filling character cells with blanks
+  and attribute cells with the current screen buffer attribute.
+  The cursor is positioned in the top left corner of the screen
+  buffer
+}
+procedure FlushInputBuffer;
+function GetTextBackground: byte;
+function GetTextColor: byte;
+Procedure GotoXY(X, Y: integer);
+Procedure HighVideo;
+Procedure HighVideoBackground;
+Function InputEvent: word;
+{ Returns
+  NO_EVENT if input buffer is empty ;
+  KEY_EVENT if there is a pending key event with
+    key released again,
+    and key is not one of the control keys;
+  KEY_EVENT_IN_PROGRESS if there is another pending key event;
+  _MOUSE_EVENT if there is a pending mouse event
+    without moving the mouse;
+  _MOUSE_EVENT_IN_PROGRESS if there is another pending mouse event;
+  WINDOW_BUFFER_SIZE_EVENT is the user resized the screen buffer
+    and window input is enabled (default mode disabled).
+}
+function KeyPressed: boolean;
+{ Returns
+  TRUE if there is a pending key event with
+    key released again,
+    and key is not one of the control keys;
+  FALSE otherwise.
+}
+Procedure LowVideo;
+Procedure LowVideoBackground;
+Procedure NormVideo;
+Procedure NormVideoBackground;
+Function ReadKey: char;
+Procedure TextBackground (Color: Byte);
+Procedure TextColor (Color: Byte);
+Function WhereX: integer;
+Function WhereY: integer;
+Function WinReadKey: WinReadKeyRecord;
+{ Return value in KeyStatus element:
+  - bit  0: shift key pressed
+  - bit  1: ctrl key pressed
+  - bit  2: alt key pressed
+  The KeyCode element has the virtual key code.
+
+  N.B. nog regelen: extended ASCII via Alt-keypad toetsen.
+}
+
+implementation
+
+type
+  PInputBuffer = ^TInputBuffer;
+  TInputBuffer = array[word] of TInputRecord;
+
+var
+  StartTextIntensity, StartBackgroundIntensity: byte;
+  pCsbi: PConsoleScreenBufferInfo;
+
+function GetScreenInfo: TConsoleScreenBufferInfo; forward;
+Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte): byte; forward;
+
+procedure ClrEol;
+var
+  hConsoleOutput: THandle;
+  cCharacter: Char;
+  wAttribute: word;
+  nLength: dword;
+  dwWriteCoord: TCoord;
+  lpWritten: dword;
+begin
+  hConsoleOutput := GetStdHandle(STD_OUTPUT_HANDLE);
+  cCharacter := ' ';
+  New(pCsbi);
+  GetConsoleScreenBufferInfo(hConsoleOutput, pCsbi^);
+  wAttribute := pCsbi^.wAttributes;
+  nLength := pCsbi^.dwSize.X - pCsbi^.dwCursorPosition.X + 1;
+  dwWriteCoord.X := pCsbi^.dwCursorPosition.X;
+  dwWriteCoord.Y := pCsbi^.dwCursorPosition.Y;
+  Dispose(pCsbi);
+  FillConsoleOutputCharacter(hConsoleOutput, cCharacter, nLength,
+    dwWriteCoord, lpWritten);
+  FillConsoleOutputAttribute(hConsoleOutput, wAttribute, nLength,
+    dwWriteCoord, lpWritten);
+end;
+
+procedure ClrScr;
+var
+  hConsoleOutput: THandle;
+  cCharacter: Char;
+  wAttribute: word;
+  nLength: dword;
+  dwWriteCoord: TCoord;
+  lpWritten: dword;
+begin
+  hConsoleOutput := GetStdHandle(STD_OUTPUT_HANDLE);
+  cCharacter := ' ';
+  New(pCsbi);
+  GetConsoleScreenBufferInfo(hConsoleOutput, pCsbi^);
+  wAttribute := pCsbi^.wAttributes;
+  nLength := pCsbi^.dwSize.X * pCsbi^.dwSize.Y;
+  Dispose(pCsbi);
+  dwWriteCoord.X := 0;
+  dwWriteCoord.Y := 0;
+  FillConsoleOutputCharacter(hConsoleOutput, cCharacter, nLength,
+    dwWriteCoord, lpWritten);
+  FillConsoleOutputAttribute(hConsoleOutput, wAttribute, nLength,
+    dwWriteCoord, lpWritten);
+  SetConsoleCursorPosition(hConsoleOutput, dwWriteCoord);
+end;
+
+procedure FlushInputBuffer;
+begin
+  FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
+end;
+
+function GetTextBackground: byte;
+begin
+  Result := GetScreenInfo.wAttributes AND bWhite;
+end;
+
+function GetTextColor: byte;
+begin
+  Result := GetScreenInfo.wAttributes AND fWhite;
+end;
+
+function GetScreenInfo: TConsoleScreenBufferInfo;
+begin
+  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), Result);
+end;
+
+Procedure GotoXY(X, Y: integer);
+var
+  CoordCursor: TCoord;
+begin
+  CoordCursor.X := X - 1;
+  CoordCursor.Y := Y - 1;
+  SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), CoordCursor);
+end;
+
+Procedure HighVideo;
+var
+  Attribute: word;
+begin
+  Attribute := GetScreenInfo.wAttributes;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Attribute OR FOREGROUND_INTENSITY);
+end;
+
+Procedure HighVideoBackground;
+var
+  Attribute: word;
+begin
+  Attribute := GetScreenInfo.wAttributes;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Attribute OR BACKGROUND_INTENSITY);
+end;
+
+Function InputEvent: word;
+var
+  hConsoleInput: THandle;
+  pInput: pInputBuffer;
+  lpNumberOfEvents: dword;
+  lpNumberRead: integer;
+  i: word;
+
+  const
+  KeysToSkip: set of byte =
+    [VK_SHIFT, VK_CONTROL, VK_MENU, VK_CAPITAL, VK_NUMLOCK, VK_SCROLL];
+
+begin
+  hConsoleInput := GetStdHandle(STD_INPUT_HANDLE);
+  GetNumberOfConsoleInputEvents(hConsoleInput, lpNumberOfEvents);
+  Result := NO_EVENT;
+  if lpNumberOfEvents > 0 then
+  try
+    GetMem(pInput, lpNumberOfEvents * SizeOf(TInputRecord));
+    PeekConsoleInput(hConsoleInput, pInput^[0], lpNumberOfEvents, lpNumberRead);
+    i := 0;
+    repeat
+      with pInput^[i] do begin
+        case EventType of
+          KEY_EVENT:
+            if (KeyEvent.bKeyDown = false) and
+               not (KeyEvent.wVirtualKeyCode in KeysToSkip) then
+               Result := EventType
+             else
+               Result := KEY_EVENT_IN_PROGRESS;
+          _MOUSE_EVENT:
+            if (MouseEvent.dwEventFlags <> MOUSE_MOVED) then
+               Result := EventType
+             else
+               Result := _MOUSE_EVENT_IN_PROGRESS;
+          else
+            Result := EventType;
+        end;
+      end;
+      inc(i);
+    until (Result <> NO_EVENT) or (i >= lpNumberOfEvents);
+  finally
+    FreeMem(pInput);
+  end;
+end;
+
+Function KeyPressed: boolean;
+var
+  hConsoleInput: THandle;
+  pInput: pInputBuffer;
+  lpNumberOfEvents: dword;
+  lpNumberRead: integer;
+  i: word;
+
+  const
+  KeysToSkip: set of byte =
+    [VK_SHIFT, VK_CONTROL, VK_MENU, VK_CAPITAL, VK_NUMLOCK, VK_SCROLL];
+
+begin
+  hConsoleInput := GetStdHandle(STD_INPUT_HANDLE);
+  GetNumberOfConsoleInputEvents(hConsoleInput, lpNumberOfEvents);
+  Result := FALSE;
+  if lpNumberOfEvents > 0 then
+  try
+    GetMem(pInput, lpNumberOfEvents * SizeOf(TInputRecord));
+    PeekConsoleInput(hConsoleInput, pInput^[0], lpNumberOfEvents, lpNumberRead);
+    i := 0;
+    repeat
+      with pInput^[i] do begin
+        if EventType = KEY_EVENT then
+          Result := (KeyEvent.bKeyDown = false) and
+                    not (KeyEvent.wVirtualKeyCode in KeysToSkip);
+      end;
+      inc(i);
+    until (Result = TRUE) or (i >= lpNumberOfEvents);
+  finally
+    FreeMem(pInput);
+  end;
+end;
+
+Procedure LowVideo;
+var
+  Attribute: word;
+begin
+  Attribute := GetScreenInfo.wAttributes;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Attribute AND NOT FOREGROUND_INTENSITY);
+end;
+
+Procedure LowVideoBackground;
+var
+  Attribute: word;
+begin
+  Attribute := GetScreenInfo.wAttributes;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Attribute AND NOT BACKGROUND_INTENSITY);
+end;
+Procedure NormVideo;
+var
+  Attribute: word;
+begin
+  Attribute := GetScreenInfo.wAttributes;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Attribute AND (fLightGray OR bWhite) OR StartTextIntensity);
+end;
+
+Procedure NormVideoBackground;
+var
+  Attribute: word;
+begin
+  Attribute := GetScreenInfo.wAttributes;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Attribute AND (fWhite OR bLightGray) OR StartBackgroundIntensity);
+end;
+
+Function ReadKey: char;
+var
+  hConsoleInput: THandle;
+  pInput: pInputRecord;
+  lpcRead: integer;
+  AltKey, CtrlKey, ShiftKey: boolean;
+
+const
+  ExtendedChar: boolean = false;
+  Scancode: byte = 0;
+  {
+    Scancodes to skip:
+
+      $1D - Ctrl keys
+      $2A - left Shift key
+      $36 - right Shift key
+      $38 - Alt keys
+      $3A - Caps lock key
+      $45 - Num lock key
+      $46 - Scroll lock key
+  }
+  ScanCodesToSkip: set of 0..255 =
+    [$1D, $2A, $36, $38, $3A, $45, $46];
+
+begin
+  if not ExtendedChar then begin
+    hConsoleInput := GetStdHandle(STD_INPUT_HANDLE);
+    try
+      New(pInput);
+      with pInput^.KeyEvent do begin
+        Repeat
+          ReadConsoleInput(hConsoleInput, pInput^, 1, lpcRead);
+        until (pInput^.EventType = KEY_EVENT)
+          and (bKeyDown = false)
+          and not (wVirtualScanCode in ScanCodesToSkip);
+
+        { Get state of control keys }
+
+        AltKey := ((dwControlKeyState AND
+                  (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
+        CtrlKey := ((dwControlKeyState AND
+                  (RIGHT_CTRL_PRESSED OR LEFT_CTRL_PRESSED)) > 0);
+        ShiftKey := ((dwControlKeyState AND SHIFT_PRESSED) > 0);
+
+        { Get key value, making some corrections to comply with MSDOS}
+
+        if AltKey then
+          Result := #0
+        else begin
+          Result := AsciiChar;
+          if CtrlKey then
+            case wVirtualScanCode of
+              $07: Result := #$1E;    // ^_6  (Win32 gives ASCII = 0)
+              $0C: Result := #$1F;    // ^_-  (Win32 gives ASCII = 0)
+            end
+          else if ShiftKey then
+            case wVirtualScanCode of
+              $01: Result := #$1B;    // Shift Esc (Win32 gives ASCII = 0)
+              $0F: Result := #0;      // Shift Tab (Win32 gives ASCII = 9)
+            end;
+        end;
+
+        {Save scancode of non-ASCII keys for second call}
+
+        if (Result = #0) then begin
+          ExtendedChar := true;
+          ScanCode := RemapScanCode(wVirtualScanCode, dwControlKeyState);
+        end;
+      end;
+    finally
+      Dispose(pInput);
+    end;
+  end
+  else begin
+    Result := char(ScanCode);
+    ExtendedChar := false;
+  end;
+end;
+
+Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte): byte;
+
+  { Several remappings of scancodes are necessary to comply with what
+    we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.
+    are excluded }
+
+var
+  AltKey, CtrlKey, ShiftKey: boolean;
+const
+  {
+    Keypad key scancodes:
+
+      Ctrl Norm
+
+      $77  $47 - Home
+      $8D  $48 - Up arrow
+      $84  $49 - PgUp
+      $8E  $4A - -
+      $73  $4B - Left Arrow
+      $8F  $4C - 5
+      $74  $4D - Right arrow
+      $4E  $4E - +
+      $75  $4F - End
+      $91  $50 - Down arrow
+      $76  $51 - PgDn
+      $92  $52 - Ins
+      $93  $53 - Del
+  }
+  CtrlKeypadKeys: array[$47..$53] of byte =
+    ($77, $8D, $84, $8E, $73, $8F, $74, $4E, $75, $91, $76, $92, $93);
+
+begin
+  AltKey := ((CtrlKeyState AND
+            (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0);
+  CtrlKey := ((CtrlKeyState AND
+            (RIGHT_CTRL_PRESSED OR LEFT_CTRL_PRESSED)) > 0);
+  ShiftKey := ((CtrlKeyState AND SHIFT_PRESSED) > 0);
+  if AltKey then
+    case ScanCode of
+    // Digits, -, =
+    $02..$0D: inc(ScanCode, $76);
+    // Function keys
+    $3B..$44: inc(Scancode, $2D);
+    $57..$58: inc(Scancode, $34);
+    // Extended cursor block keys
+    $47..$49, $4B, $4D, $4F..$53:
+              inc(Scancode, $50);
+    // Other keys
+    $1C:      Scancode := $A6;   // Enter
+    $35:      Scancode := $A4;   // / (keypad and normal!)
+    end
+  else if CtrlKey then
+    case Scancode of
+    // Tab key
+    $0F:      Scancode := $94;
+    // Function keys
+    $3B..$44: inc(Scancode, $23);
+    $57..$58: inc(Scancode, $32);
+    // Keypad keys
+    $35:      Scancode := $95;   // \
+    $37:      Scancode := $96;   // *
+    $47..$53: Scancode := CtrlKeypadKeys[Scancode];
+    end
+  else if ShiftKey then
+    case Scancode of
+    // Function keys
+    $3B..$44: inc(Scancode, $19);
+    $57..$58: inc(Scancode, $30);
+    end
+  else
+    case Scancode of
+    // Function keys
+    $57..$58: inc(Scancode, $2E); // F11 and F12
+  end;
+  Result := ScanCode;
+end;
+
+
+Procedure TextBackground (Color: Byte);
+var
+  Background, Foreground: byte;
+begin
+  Background := Color AND bWhite;
+  Foreground := GetScreenInfo.wAttributes AND fWhite;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Background OR Foreground);
+end;
+
+Procedure TextColor (Color: Byte);
+var
+  Background, Foreground: byte;
+begin
+  Background := GetScreenInfo.wAttributes AND bWhite;
+  Foreground := Color AND fWhite;
+  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+    Background OR Foreground);
+end;
+
+Function WhereX: integer;
+begin
+  Result := GetScreenInfo.dwCursorPosition.X + 1;
+end;
+
+Function WhereY: integer;
+begin
+  Result := GetScreenInfo.dwCursorPosition.Y + 1;
+end;
+
+Function WinReadKey: WinReadKeyRecord;
+var
+  hConsoleInput: THandle;
+  pInput: pInputRecord;
+  lpcRead: integer;
+
+  const
+  KeysToSkip: set of byte =
+    [VK_SHIFT, VK_CONTROL, VK_MENU, VK_CAPITAL, VK_NUMLOCK, VK_SCROLL];
+
+begin
+  hConsoleInput := GetStdHandle(STD_INPUT_HANDLE);
+  try
+    New(pInput);
+    with pInput^.KeyEvent do begin
+      Repeat
+        ReadConsoleInput(hConsoleInput, pInput^, 1, lpcRead);
+      until (pInput^.EventType = KEY_EVENT)
+        and (bKeyDown = TRUE)
+        and not (wVirtualKeyCode in KeysToSkip);
+
+      { Get key value }
+
+      with Result do begin
+
+        KeyStatus := 0;
+        AsciiChar := pInput^.KeyEvent.AsciiChar;
+        KeyCode := wVirtualKeyCode;
+
+      { Set bits 0..2 of KeyStatus to indicate control key state}
+
+      if ((dwControlKeyState AND SHIFT_PRESSED) > 0) then
+        KeyStatus := (KeyStatus OR $01);
+      if ((dwControlKeyState AND
+          (RIGHT_CTRL_PRESSED OR LEFT_CTRL_PRESSED)) > 0) then
+        KeyStatus := (KeyStatus OR $02);
+      if ((dwControlKeyState AND
+          (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0) then
+        KeyStatus := (KeyStatus OR $04);
+
+      end;
+    end;
+  finally
+    Dispose(pInput);
+  end;
+end;
+
+begin
+  New(pCsbi);
+  pCsbi^ := GetScreenInfo;
+  StartTextIntensity := pCsbi^.wAttributes AND FOREGROUND_INTENSITY;
+  StartBackgroundIntensity := pCsbi^.wAttributes AND BACKGROUND_INTENSITY;
+  Dispose(pCsbi);
+end.