crt.inc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1998 - 2005 by the Free Pascal development team.
  4. This file implements platform independent routines for Crt.
  5. It should be modified later to use routines from Keyboard and
  6. Video instead of code in platform-specific crt.pas.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. var
  14. ScanCode: byte;
  15. SpecialKey: boolean;
  16. procedure GotoXY (X: tcrtcoord; Y: tcrtcoord);
  17. begin
  18. GotoXY32 (X, Y);
  19. end;
  20. procedure Window (X1, Y1, X2, Y2: byte);
  21. begin
  22. Window32 (X1, Y1, X2, Y2);
  23. end;
  24. function WhereX: tcrtcoord;
  25. var
  26. X1: dword;
  27. begin
  28. X1 := WhereX32;
  29. if X1 > 255 then
  30. WhereX := 255
  31. else
  32. WhereX := X1;
  33. end;
  34. function WhereY: tcrtcoord;
  35. var
  36. Y1: dword;
  37. begin
  38. Y1 := WhereY32;
  39. if Y1 > 255 then
  40. WhereY := 255
  41. else
  42. WhereY := Y1;
  43. end;
  44. procedure ClrScr;
  45. {Clears the current window.}
  46. begin
  47. RemoveLines (0, Succ (WindMaxY - WindMinY));
  48. GotoXY32 (1, 1);
  49. end;
  50. procedure GotoXY32 (X, Y: dword);
  51. (* Positions cursor on (X, Y) (1-based) relative to window origin; for TP/BP
  52. compatibility call completely ignored in case of incorrect parameters. *)
  53. begin
  54. if (X > 0) and (Y > 0) then
  55. begin
  56. Dec (X);
  57. Dec (Y);
  58. if (X <= WindMaxX - WindMinX) and (Y <= WindMaxY - WindMinY) then
  59. SetScreenCursor (X + WindMinX, Y + WindMinY);
  60. end;
  61. end;
  62. function WhereX32: dword;
  63. (* Returns the X position of the cursor (1-based). *)
  64. var
  65. X, Y: dword;
  66. begin
  67. GetScreenCursor (X, Y);
  68. WhereX32 := Succ (X - WindMinX);
  69. end;
  70. function WhereY32: dword;
  71. (* Returns the Y position of the cursor (1-based). *)
  72. var
  73. X, Y: dword;
  74. begin
  75. GetScreenCursor (X, Y);
  76. WhereY32 := Succ (Y - WindMinY);
  77. end;
  78. procedure ClrEol;
  79. (* Clears the line where cursor is located from current position up to end. *)
  80. var
  81. X, Y: dword;
  82. begin
  83. GetScreenCursor (X, Y);
  84. ClearCells (X, Y, Succ (WindMaxX - X));
  85. end;
  86. procedure DelLine;
  87. (* Deletes the line at cursor. *)
  88. begin
  89. RemoveLines (Pred (WhereY32), 1);
  90. end;
  91. procedure TextMode (Mode: word);
  92. { Use this procedure to set-up a specific text-mode.}
  93. begin
  94. TextAttr := $07;
  95. LastMode := Mode;
  96. SetScreenMode (Mode);
  97. WindMin := 0;
  98. WindMaxX := Pred (ScreenWidth);
  99. WindMaxY := Pred (ScreenHeight);
  100. if WindMaxX >= 255 then
  101. WindMax := 255
  102. else
  103. WindMax := WindMaxX;
  104. if WindMaxY >= 255 then
  105. WindMax := WindMax or $FF00
  106. else
  107. WindMax := WindMax or (WindMaxY shl 8);
  108. ClrScr;
  109. end;
  110. procedure TextColor (Color: byte);
  111. {All text written after calling this will have Color as foreground colour.}
  112. begin
  113. TextAttr := (TextAttr and $70) or (Color and $f);
  114. if Color > 15 then
  115. TextAttr := TextAttr or 128;
  116. end;
  117. procedure TextBackground (Color: byte);
  118. {All text written after calling this will have Color as background colour.}
  119. begin
  120. TextAttr := (TextAttr and $8F) or ((Color and $7) shl 4);
  121. end;
  122. procedure NormVideo;
  123. {Changes the text-background to black and the foreground to white.}
  124. begin
  125. TextAttr := $7;
  126. end;
  127. procedure LowVideo;
  128. {All text written after this will have low intensity.}
  129. begin
  130. TextAttr := TextAttr and $F7;
  131. end;
  132. procedure HighVideo;
  133. {All text written after this will have high intensity.}
  134. begin
  135. TextAttr := TextAttr or $8;
  136. end;
  137. procedure Window32 (X1, Y1, X2, Y2: dword);
  138. {Change the write window to the given coordinates.}
  139. begin
  140. if (X1 > 0) and (Y1 > 0) and (X2 <= ScreenWidth) and (Y2 <= ScreenHeight)
  141. and (X1 <= X2) and (Y1 <= Y2) then
  142. begin
  143. WindMinX := Pred (X1);
  144. WindMinY := Pred (Y1);
  145. if WindMinX >= 255 then
  146. WindMin := 255
  147. else
  148. WindMin := WindMinX;
  149. if WindMinY >= 255 then
  150. WindMin := WindMin or $FF00
  151. else
  152. WindMin := WindMin or (WindMinY shl 8);
  153. WindMaxX := Pred (X2);
  154. WindMaxY := Pred (Y2);
  155. if WindMaxX >= 255 then
  156. WindMax := 255
  157. else
  158. WindMax := WindMaxX;
  159. if WindMaxY >= 255 then
  160. WindMax := WindMax or $FF00
  161. else
  162. WindMax := WindMaxX or (WindMaxY shl 8);
  163. GotoXY32 (1, 1);
  164. end;
  165. end;
  166. threadvar
  167. CurrX, CurrY: dword;
  168. procedure WriteChar (C: char);
  169. begin
  170. case C of
  171. #7: WriteBell;
  172. #8: if CurrX >= WindMinX then
  173. Dec (CurrX);
  174. { #9: x:=(x-lo(windmin)) and $fff8+8+lo(windmin);}
  175. #10: Inc (CurrY);
  176. #13: CurrX := WindMinX;
  177. else
  178. begin
  179. WriteNormal (C, CurrX, CurrY);
  180. Inc (CurrX);
  181. end;
  182. end;
  183. if CurrX > WindMaxX then
  184. begin
  185. CurrX := WindMinX;
  186. Inc (CurrY);
  187. end;
  188. if CurrY > WindMaxY then
  189. begin
  190. RemoveLines (0, 1);
  191. CurrY := WindMaxY;
  192. end;
  193. end;
  194. function CrtWrite (var F: TextRec): integer;
  195. var
  196. I: dword;
  197. {Write a series of characters to the console.}
  198. begin
  199. if F.BufPos > 0 then
  200. begin
  201. GetScreenCursor (CurrX, CurrY);
  202. for I := 0 to Pred (F.BufPos) do
  203. WriteChar ((PChar (F.BufPtr) + I)^);
  204. SetScreenCursor (CurrX, CurrY);
  205. F.BufPos := 0;
  206. end;
  207. CrtWrite := 0;
  208. end;
  209. function CrtRead (var F: TextRec): integer;
  210. {Read a series of characters from the console.}
  211. var
  212. C: char;
  213. begin
  214. GetScreenCursor (CurrX, CurrY);
  215. F.BufPos := 0;
  216. F.BufEnd := 0;
  217. repeat
  218. if F.BufPos > F.BufEnd then
  219. F.BufEnd := F.BufPos;
  220. SetScreenCursor (CurrX, CurrY);
  221. C := ReadKey;
  222. case C of
  223. #0: ReadKey;
  224. (* The following code to support input editing is incomplete anyway
  225. - no handling of line breaks, no possibility to insert characters
  226. or delete characters inside the string, etc.
  227. #0 : case readkey of
  228. #71 : while f.bufpos>0 do
  229. begin
  230. dec(f.bufpos);
  231. WriteChar(#8);
  232. end;
  233. #75 : if f.bufpos>0 then
  234. begin
  235. dec(f.bufpos);
  236. WriteChar(#8);
  237. end;
  238. #77 : if f.bufpos<f.bufend then
  239. begin
  240. WriteChar(f.bufptr^[f.bufpos]);
  241. inc(f.bufpos);
  242. end;
  243. #79 : while f.bufpos<f.bufend do
  244. begin
  245. WriteChar(f.bufptr^[f.bufpos]);
  246. inc(f.bufpos);
  247. end;
  248. end;
  249. *)
  250. #8: if (F.BufPos > 0) and (F.BufPos = F.BufEnd) then
  251. begin
  252. {$WARNING CrtRead doesn't handle line breaks correctly (same bug as TP/BP)!}
  253. WriteChar (#8);
  254. WriteChar (' ');
  255. WriteChar (#8);
  256. Dec (F.BufPos);
  257. Dec (F.BufEnd);
  258. end;
  259. #13: begin
  260. WriteChar(#13);
  261. WriteChar(#10);
  262. F.BufPtr^ [F.BufEnd] := #13;
  263. Inc (F.BufEnd);
  264. F.BufPtr^ [F.BufEnd] := #10;
  265. Inc (F.BufEnd);
  266. break;
  267. end;
  268. #26: if CheckEOF then
  269. begin
  270. F.BufPtr^ [F.BufEnd] := #26;
  271. Inc (F.BufEnd);
  272. break;
  273. end;
  274. #32..#255: if F.BufPos < F.BufSize - 2 then
  275. begin
  276. F.BufPtr^ [F.BufPos] := C;
  277. Inc (F.BufPos);
  278. WriteChar (C);
  279. end;
  280. end
  281. until false;
  282. CrtRead := 0;
  283. end;
  284. function CrtReturn (var F: TextRec): integer;
  285. begin
  286. CrtReturn:=0;
  287. end;
  288. function CrtClose (var F: TextRec): integer;
  289. begin
  290. F.Mode := fmClosed;
  291. CrtClose := 0;
  292. end;
  293. function CrtOpen (var F: TextRec): integer;
  294. begin
  295. if F.Mode = fmOutput then
  296. begin
  297. TextRec(F).InOutFunc := @CrtWrite;
  298. TextRec(F).FlushFunc := @CrtWrite;
  299. end
  300. else
  301. begin
  302. F.Mode := fmInput;
  303. TextRec(F).InOutFunc := @CrtRead;
  304. TextRec(F).FlushFunc := @CrtReturn;
  305. end;
  306. TextRec(F).CloseFunc := @CrtClose;
  307. CrtOpen := 0;
  308. end;
  309. procedure AssignCrt (var F: text);
  310. {Assigns a file to the crt console.}
  311. begin
  312. Assign (F, '');
  313. TextRec (F).OpenFunc := @CrtOpen;
  314. end;
  315. {$IFNDEF HAS_SOUND}
  316. procedure Sound (Hz: word);
  317. (* Dummy Sound implementation - for platforms requiring both frequence
  318. and duration at the beginning instead of start and stop procedures. *)
  319. begin
  320. end;
  321. {$ENDIF HAS_SOUND}
  322. {$IFNDEF HAS_NOSOUND}
  323. procedure NoSound;
  324. (* Dummy NoSound implementation - for platforms requiring both frequence
  325. and duration at the beginning instead of start and stop procedures. *)
  326. begin
  327. end;
  328. {$ENDIF HAS_NOSOUND}
  329. var
  330. PrevCtrlBreakHandler: TCtrlBreakHandler;
  331. function CrtCtrlBreakHandler (CtrlBreak: boolean): boolean;
  332. begin
  333. (* Earlier registered handlers (e.g. FreeVision) have priority. *)
  334. if Assigned (PrevCtrlBreakHandler) then
  335. if PrevCtrlBreakHandler (CtrlBreak) then
  336. begin
  337. CrtCtrlBreakHandler := true;
  338. Exit;
  339. end;
  340. (* If Ctrl-Break was pressed, either ignore it or allow default processing. *)
  341. if CtrlBreak then
  342. CrtCtrlBreakHandler := not (CheckBreak)
  343. else (* Ctrl-C pressed *)
  344. begin
  345. if not (SpecialKey) and (ScanCode = 0) then
  346. ScanCode := 3;
  347. CrtCtrlBreakHandler := true;
  348. end;
  349. end;
  350. procedure CrtInit;
  351. (* Common part of unit initialization. *)
  352. begin
  353. TextAttr := LightGray;
  354. WindMin := 0;
  355. WindMaxX := Pred (ScreenWidth);
  356. WindMaxY := Pred (ScreenHeight);
  357. if WindMaxX >= 255 then
  358. WindMax := 255
  359. else
  360. WindMax := WindMaxX;
  361. if WindMaxY >= 255 then
  362. WindMax := WindMax or $FF00
  363. else
  364. WindMax := WindMax or (WindMaxY shl 8);
  365. ScanCode := 0;
  366. SpecialKey := false;
  367. AssignCrt (Input);
  368. Reset (Input);
  369. AssignCrt (Output);
  370. Rewrite (Output);
  371. PrevCtrlBreakHandler := SysSetCtrlBreakHandler (@CrtCtrlBreakHandler);
  372. if PrevCtrlBreakHandler = TCtrlBreakHandler (pointer (-1)) then
  373. PrevCtrlBreakHandler := nil;
  374. CheckBreak := true;
  375. end;