ODScrn.c 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library 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. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *
  19. * File: ODScrn.c
  20. *
  21. * Description: Functions used to access the local display screen buffer, which
  22. * keeps a copy of the text that is displayed on the remote
  23. * terminal. The local display screen buffer also displays the
  24. * OpenDoors status lines on some platforms. In addition to
  25. * maintaining the current screen buffer, the odscrn.c module
  26. * also contains the code to display this buffer on the screen.
  27. *
  28. * Revisions: Date Ver Who Change
  29. * ---------------------------------------------------------------
  30. * Oct 13, 1994 6.00 BP New file header format.
  31. * Dec 09, 1994 6.00 BP Standardized coding style.
  32. * Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
  33. * Dec 31, 1994 6.00 BP Use new multitasker variable.
  34. * Nov 11, 1995 6.00 BP Removed register keyword.
  35. * Nov 14, 1995 6.00 BP 32-bit portability.
  36. * Nov 14, 1995 6.00 BP Created odscrn.h.
  37. * Nov 14, 1995 6.00 BP Make screen size configurable.
  38. * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
  39. * Nov 21, 1995 6.00 BP Port to Win32.
  40. * Jan 20, 1996 6.00 BP Prompt for user name if force_local.
  41. * Jan 21, 1996 6.00 BP Added ODScrnShowMessage() and related.
  42. * Jan 27, 1996 6.00 BP Expand tab ('\t') characters.
  43. * Jan 27, 1996 6.00 BP Added ODScrollUpAndInvalidate().
  44. * Jan 27, 1996 6.00 BP Made text-mode window f'ns static.
  45. * Jan 31, 1996 6.00 BP Made them non-static again.
  46. * Jan 31, 1996 6.00 BP Added ODScrnLocalInput().
  47. * Feb 06, 1996 6.00 BP Added od_silent_mode.
  48. * Feb 16, 1996 6.00 BP Make caret visible after local login.
  49. * Feb 17, 1996 6.00 BP Recognize non-ASCII keys under Win32.
  50. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  51. * Feb 21, 1996 6.00 BP Forward SC_KEYMENU to frame thread.
  52. * Feb 21, 1996 6.00 BP Don't beep in "silent mode".
  53. * Mar 03, 1996 6.10 BP Begin version 6.10.
  54. * Mar 13, 1996 6.10 BP Added od_local_win_col.
  55. * Mar 17, 1996 6.10 BP Terminate string in ODScrnLocalInput()
  56. * Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
  57. * Aug 10, 2003 6.23 SH *nix support
  58. */
  59. #define BUILDING_OPENDOORS
  60. #include <stdarg.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <stdio.h>
  64. #include <time.h>
  65. #include "OpenDoor.h"
  66. #include "ODCore.h"
  67. #include "ODGen.h"
  68. #include "ODPlat.h"
  69. #include "ODScrn.h"
  70. #include "ODUtil.h"
  71. #include "ODFrame.h"
  72. #include "ODInEx.h"
  73. #ifdef ODPLAT_WIN32
  74. #include "ODKrnl.h"
  75. #include "ODRes.h"
  76. #endif /* ODPLAT_WIN32 */
  77. /* ========================================================================= */
  78. /* Definitions of variables used by the local screen module. */
  79. /* ========================================================================= */
  80. /* Manifest constants used in this module. */
  81. #define SCREEN_BUFFER_SIZE (OD_SCREEN_WIDTH * OD_SCREEN_HEIGHT * 2)
  82. #define SCREEN_BUFFER_SEGMENT_SIZE (SCREEN_BUFFER_SIZE / 16)
  83. #define BYTES_PER_CHAR 2
  84. #define BUFFER_LINE_BYTES (OD_SCREEN_WIDTH * BYTES_PER_CHAR)
  85. #define LINE_BUFFER_SIZE (OD_SCREEN_WIDTH + 1)
  86. /* Private variables used by the screen I/O functions. */
  87. #if defined(ODPLAT_DOS) || defined(ODPLAT_NIX)
  88. static void *pAllocatedBufferMemory;
  89. #endif /* ODPLAT_DOS */
  90. /* Far pointer to video buffer. */
  91. static void ODFAR *pScrnBuffer;
  92. /* Current cursor position. */
  93. static BYTE btCursorColumn;
  94. static BYTE btCursorRow;
  95. /* Current output boundaries. */
  96. static BYTE btLeftBoundary;
  97. static BYTE btTopBoundary;
  98. static BYTE btRightBoundary;
  99. static BYTE btBottomBoundary;
  100. /* Current display color. */
  101. static BYTE btCurrentAttribute;
  102. /* Is scrolling enabled. */
  103. static BOOL bScrollEnabled;
  104. #ifdef ODPLAT_DOS
  105. /* Segment address of video buffer. */
  106. static WORD wBufferSegment;
  107. /* Display page to use. */
  108. static BYTE btDisplayPage;
  109. #endif
  110. /* Is cursor currently on. */
  111. static BYTE bCaretOn;
  112. /* Static temporary working buffer. */
  113. static char szBuffer[LINE_BUFFER_SIZE];
  114. /* Private function prototypes. */
  115. static void ODScrnGetCursorPos(void);
  116. static void ODScrnUpdateCaretPos(void);
  117. static void ODScrnScrollUpOneLine(void);
  118. static void ODScrnScrollUpAndInvalidate(void);
  119. /* ========================================================================= */
  120. /* Implementation of the local screen window for the Win32 platform. */
  121. /* ========================================================================= */
  122. #ifdef ODPLAT_WIN32
  123. /* Screen thread startup information. */
  124. typedef struct
  125. {
  126. HWND hwndFrame;
  127. HANDLE hInstance;
  128. } tODScrnThreadInfo;
  129. /* Handle to the screen window. */
  130. static HWND hwndScreenWindow;
  131. /* Does the screen window currently have input focus? */
  132. BOOL bScreenHasFocus;
  133. /* Current font-related information. */
  134. static HFONT hCurrentFont;
  135. static INT nFontCellWidth;
  136. static INT nFontCellHeight;
  137. /* Table to translate from PC text color values used in the screen buffer */
  138. /* to their corresponding RGB values. */
  139. COLORREF acrPCTextColors[] =
  140. {
  141. RGB(0x00, 0x00, 0x00),
  142. RGB(0x00, 0x00, 0xc0),
  143. RGB(0x00, 0xc0, 0x00),
  144. RGB(0x00, 0xc0, 0xc0),
  145. RGB(0xc0, 0x00, 0x00),
  146. RGB(0xc0, 0x00, 0xc0),
  147. RGB(0xc0, 0xc0, 0x00),
  148. RGB(0xc0, 0xc0, 0xc0),
  149. RGB(0x7f, 0x7f, 0x7f),
  150. RGB(0x00, 0x00, 0xff),
  151. RGB(0x00, 0xff, 0x00),
  152. RGB(0x00, 0xff, 0xff),
  153. RGB(0xff, 0x00, 0x00),
  154. RGB(0xff, 0x00, 0xff),
  155. RGB(0xff, 0xff, 0x00),
  156. RGB(0xff, 0xff, 0xff),
  157. };
  158. /* Table to translate from Windows key codes to OpenDoors key codes. */
  159. typedef struct
  160. {
  161. int nVirtKey;
  162. BYTE btODKey;
  163. } tWinKeyToODKey;
  164. tWinKeyToODKey aWinKeyToODKey[] =
  165. {
  166. {VK_UP, OD_KEY_UP},
  167. {VK_DOWN, OD_KEY_DOWN},
  168. {VK_LEFT, OD_KEY_LEFT},
  169. {VK_RIGHT, OD_KEY_RIGHT},
  170. {VK_INSERT, OD_KEY_INSERT},
  171. {VK_DELETE, OD_KEY_DELETE},
  172. {VK_END, OD_KEY_END},
  173. {VK_HOME, OD_KEY_HOME},
  174. {VK_PRIOR, OD_KEY_PGUP},
  175. {VK_NEXT, OD_KEY_PGDN},
  176. {VK_F1, OD_KEY_F1},
  177. {VK_F2, OD_KEY_F2},
  178. {VK_F3, OD_KEY_F3},
  179. {VK_F4, OD_KEY_F4},
  180. {VK_F5, OD_KEY_F5},
  181. {VK_F6, OD_KEY_F6},
  182. {VK_F7, OD_KEY_F7},
  183. {VK_F8, OD_KEY_F8},
  184. {VK_F9, OD_KEY_F9},
  185. {VK_F10, OD_KEY_F10},
  186. };
  187. /* Utility macros. */
  188. #define COLUMN_AS_XPIXEL(nColumn) (((INT)(nColumn)) * nFontCellWidth)
  189. #define ROW_AS_YPIXEL(nRow) (((INT)(nRow)) * nFontCellHeight)
  190. #define XPIXEL_AS_COLUMN(nX) (((INT)(nX)) / nFontCellWidth)
  191. #define YPIXEL_AS_ROW(nY) (((INT)(nY)) / nFontCellHeight)
  192. /* User defined messages. */
  193. #define WM_MOVE_YOUR_CARET (WM_USER + 1)
  194. #define WM_KEYDOWN_RELAY (WM_USER + 2)
  195. /* Height of the flashing caret, in pixels. */
  196. #define CARET_HEIGHT 3
  197. /* Local function prototypes. */
  198. LRESULT CALLBACK ODScrnWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  199. LPARAM lParam);
  200. static HWND ODScrnCreateWin(HWND hwndFrame, HANDLE hInstance);
  201. static void ODScrnMessageLoop(HANDLE hInstance, HWND hwndScreen);
  202. DWORD OD_THREAD_FUNC ODScrnThreadProc(void *pParam);
  203. static void ODScrnPaint(HDC hdc, INT nLeft, INT nTop, INT nRight, INT nBottom);
  204. static void ODScrnInvalidate(BYTE btLeft, BYTE btTop, BYTE btRight,
  205. BYTE btBottom);
  206. static void ODScrnSetCurrentFont(HWND hwndScreen, HFONT hNewFont);
  207. static void ODScrnSetWinCaretPos(void);
  208. /* ----------------------------------------------------------------------------
  209. * ODScrnCreateWin() *** PRIVATE FUNCTION ***
  210. *
  211. * Creates the local screen window, which covers the client area of the
  212. * OpenDoors frame window.
  213. *
  214. * Parameters: hwndFrame - Handle to the frame window.
  215. *
  216. * hInstance - Handle to application instance.
  217. *
  218. * Return: A handle to the newly created window, or NULL on failure.
  219. */
  220. static HWND ODScrnCreateWin(HWND hwndFrame, HANDLE hInstance)
  221. {
  222. HWND hwndScreen = NULL;
  223. WNDCLASS wcScreenWindow;
  224. ASSERT(hwndFrame != NULL);
  225. ASSERT(hInstance != NULL);
  226. /* Register the screen window's window class. */
  227. memset(&wcScreenWindow, 0, sizeof(wcScreenWindow));
  228. wcScreenWindow.style = CS_HREDRAW | CS_VREDRAW;
  229. wcScreenWindow.lpfnWndProc = ODScrnWindowProc;
  230. wcScreenWindow.cbClsExtra = 0;
  231. wcScreenWindow.cbWndExtra = 0;
  232. wcScreenWindow.hInstance = hInstance;
  233. wcScreenWindow.hIcon = NULL;
  234. wcScreenWindow.hCursor = LoadCursor(NULL, IDC_ARROW);
  235. wcScreenWindow.hbrBackground = NULL;
  236. wcScreenWindow.lpszMenuName = NULL;
  237. wcScreenWindow.lpszClassName = "ODScreen";
  238. RegisterClass(&wcScreenWindow);
  239. /* Create the screen window. */
  240. if((hwndScreen = CreateWindowEx(
  241. WS_EX_CLIENTEDGE,
  242. wcScreenWindow.lpszClassName,
  243. "",
  244. WS_CHILD | WS_BORDER,
  245. 0,
  246. 0,
  247. 500,
  248. 300,
  249. hwndFrame,
  250. NULL,
  251. hInstance,
  252. (LPVOID)hInstance)) == NULL)
  253. {
  254. /* On window creation failure, return NULL. */
  255. return(NULL);
  256. }
  257. /* Store handle to screen window for access from screen. */
  258. hwndScreenWindow = hwndScreen;
  259. return(hwndScreen);
  260. }
  261. /* ----------------------------------------------------------------------------
  262. * ODScrnWindowProc() *** PRIVATE FUNCTION ***
  263. *
  264. * The local screen window proceedure.
  265. *
  266. * Parameters: hwnd - Handle to the local screen window.
  267. *
  268. * uMsg - Specifies the message.
  269. *
  270. * wParam - Specifies additional message information. The content
  271. * of this parameter depends on the value of the uMsg
  272. * parameter.
  273. *
  274. * lParam - Specifies additional message information. The content
  275. * of this parameter depends on the value of the uMsg
  276. * parameter.
  277. *
  278. * Return: The return value is the result of the message processing and
  279. * depends on the message.
  280. */
  281. LRESULT CALLBACK ODScrnWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  282. LPARAM lParam)
  283. {
  284. HINSTANCE hInstance;
  285. ASSERT(hwnd != NULL);
  286. hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_USERDATA);
  287. switch(uMsg)
  288. {
  289. case WM_SYSCOMMAND:
  290. /* We move any SC_KEYMENU WM_SYSCOMMAND messages to the frame */
  291. /* window's message queue so that the screen window thread */
  292. /* can continue to process messages when the menu is */
  293. /* activated from the keyboard when the screen window has */
  294. /* the keyboard focus. If this isn't done, the menu will not */
  295. /* behave correctly when activated this way. */
  296. if(wParam == SC_KEYMENU)
  297. {
  298. PostMessage(GetParent(hwnd), uMsg, wParam, lParam);
  299. }
  300. else
  301. {
  302. return(DefWindowProc(hwnd, uMsg, wParam, lParam));
  303. }
  304. break;
  305. case WM_CREATE:
  306. {
  307. CREATESTRUCT *pCreateStruct = (CREATESTRUCT *)lParam;
  308. hInstance = (HINSTANCE)pCreateStruct->lpCreateParams;
  309. SetWindowLong(hwnd, GWL_USERDATA, (LONG)hInstance);
  310. break;
  311. }
  312. case WM_PAINT:
  313. {
  314. PAINTSTRUCT PaintStruct;
  315. HDC hdc;
  316. /* Obtain device context and paint information. */
  317. hdc = BeginPaint(hwnd, &PaintStruct);
  318. if(hdc != NULL)
  319. {
  320. /* Redraw the portion of the window that has been invalidated. */
  321. ODScrnPaint(hdc,
  322. XPIXEL_AS_COLUMN(PaintStruct.rcPaint.left),
  323. YPIXEL_AS_ROW(PaintStruct.rcPaint.top),
  324. XPIXEL_AS_COLUMN(PaintStruct.rcPaint.right),
  325. YPIXEL_AS_ROW(PaintStruct.rcPaint.bottom));
  326. /* Release device context. */
  327. EndPaint(hwnd, &PaintStruct);
  328. }
  329. break;
  330. }
  331. case WM_MOVE_YOUR_CARET:
  332. ODScrnSetWinCaretPos();
  333. break;
  334. case WM_LBUTTONDOWN:
  335. SetFocus(hwnd);
  336. break;
  337. case WM_SETFOCUS:
  338. /* Turn on the caret when we receive the input focus. */
  339. /* First, create the caret. */
  340. CreateCaret(hwnd, NULL, nFontCellWidth, CARET_HEIGHT);
  341. /* Remember that we now have the input focus. */
  342. bScreenHasFocus = TRUE;
  343. /* Update the position of the caret. */
  344. ODScrnSetWinCaretPos();
  345. /* Now, make the caret visible. */
  346. ShowCaret(hwnd);
  347. break;
  348. case WM_KILLFOCUS:
  349. /* Remember that we no longer have the input focus. */
  350. bScreenHasFocus = FALSE;
  351. /* Turn off the caret when we loose the input focus. */
  352. DestroyCaret();
  353. break;
  354. case WM_KEYDOWN_RELAY:
  355. {
  356. int nVirtKeyPressed = (int)wParam;
  357. WORD wRepeatCount = LOWORD(lParam);
  358. int nKeyTableIndex;
  359. WORD wKey = 0;
  360. /* Look for a matching key in the OpenDoors key table. */
  361. for(nKeyTableIndex = 0; nKeyTableIndex < DIM(aWinKeyToODKey);
  362. ++nKeyTableIndex)
  363. {
  364. if(aWinKeyToODKey[nKeyTableIndex].nVirtKey == nVirtKeyPressed)
  365. {
  366. wKey = MAKEWORD(0, aWinKeyToODKey[nKeyTableIndex].btODKey);
  367. break;
  368. }
  369. }
  370. /* If a matching key was found, then add it to the queue. */
  371. if(wKey != 0)
  372. {
  373. while(wRepeatCount--)
  374. {
  375. ODKrnlHandleLocalKey(wKey);
  376. }
  377. }
  378. break;
  379. }
  380. case WM_CHAR:
  381. {
  382. WORD wRepeatCount = LOWORD(lParam);
  383. BYTE btScanCode = LOBYTE(HIWORD(lParam));
  384. TCHAR chCharCode = (TCHAR)wParam;
  385. WORD wKey;
  386. wKey = MAKEWORD(chCharCode, btScanCode);
  387. /* Loop for each repitition of this key. */
  388. while(wRepeatCount--)
  389. {
  390. ODKrnlHandleLocalKey(wKey);
  391. }
  392. break;
  393. }
  394. default:
  395. /* Pass messages that we don't explicitly handle on to the */
  396. /* default window proc. */
  397. return(DefWindowProc(hwnd, uMsg, wParam, lParam));
  398. }
  399. return(0);
  400. }
  401. /* ----------------------------------------------------------------------------
  402. * ODScrnPaint() *** PRIVATE FUNCTION ***
  403. *
  404. * Draws the specified portion of the screen on the provided device context.
  405. *
  406. * Parameters: hdc - Handle to the device context to draw on.
  407. *
  408. * nLeft - Left column to draw.
  409. *
  410. * nTop - Top row to draw.
  411. *
  412. * nRight - Right column to draw.
  413. *
  414. * nBottom - Bottom row to draw.
  415. *
  416. * Return: void.
  417. */
  418. static void ODScrnPaint(HDC hdc, INT nLeft, INT nTop, INT nRight, INT nBottom)
  419. {
  420. INT nIDSavedState;
  421. INT nCurrentLine;
  422. INT nStartColumn;
  423. INT nEndColumn;
  424. BYTE *pbtBufferContents;
  425. char achStringToOutput[OD_SCREEN_WIDTH];
  426. char *pchNextChar;
  427. BYTE btCurrentAttribute;
  428. ASSERT(hdc != NULL);
  429. ASSERT(nLeft >= 0);
  430. ASSERT(nTop >= 0);
  431. ASSERT(nRight >= nLeft);
  432. ASSERT(nBottom >= nTop);
  433. /* Ensure that parameters are within valid range. */
  434. if(nRight >= OD_SCREEN_WIDTH) nRight = OD_SCREEN_WIDTH - 1;
  435. if(nBottom >= OD_SCREEN_HEIGHT) nBottom = OD_SCREEN_HEIGHT - 1;
  436. /* Save the current state of the device context so that we can restore */
  437. /* it before returning. */
  438. nIDSavedState = SaveDC(hdc);
  439. /* Setup device context for displaying text from the screen buffer. */
  440. SetBkMode(hdc, OPAQUE);
  441. SelectObject(hdc, hCurrentFont);
  442. /* Loop through each line that is to be painted. */
  443. for(nCurrentLine = nTop; nCurrentLine <= nBottom; ++nCurrentLine)
  444. {
  445. /* Obtain a pointer to the first byte representing this line in */
  446. /* the screen buffer. */
  447. pbtBufferContents = (BYTE *)(pScrnBuffer) +
  448. ((nCurrentLine * OD_SCREEN_WIDTH) + nLeft) * 2;
  449. /* Loop for each portion of this line that can be drawn in a single */
  450. /* TextOut() call. */
  451. for(nStartColumn = nLeft; nStartColumn <= nRight;
  452. nStartColumn = nEndColumn)
  453. {
  454. /* Begin constructing a string containing the text to output */
  455. /* in this call to TextOut(). */
  456. pchNextChar = achStringToOutput;
  457. /* Determine the color of this portion. */
  458. btCurrentAttribute = pbtBufferContents[1];
  459. /* Loop, finding the first column that has an incompatible color. */
  460. for(nEndColumn = nStartColumn; nEndColumn <= nRight; ++nEndColumn)
  461. {
  462. /* Stop looping if we come to a non-equivalent color */
  463. /* attribute. */
  464. if(btCurrentAttribute != pbtBufferContents[1])
  465. {
  466. break;
  467. }
  468. /* Otherwise, add this character to the string to output. */
  469. *pchNextChar++ = *pbtBufferContents;
  470. /* Move to the next position in the buffer. */
  471. pbtBufferContents += 2;
  472. }
  473. /* Change current display colors to match the current color */
  474. /* attribute. */
  475. SetTextColor(hdc, acrPCTextColors[btCurrentAttribute & 0x0f]);
  476. SetBkColor(hdc, acrPCTextColors[(btCurrentAttribute & 0xf0) >> 4]);
  477. /* Output the string. */
  478. TextOut(hdc,
  479. COLUMN_AS_XPIXEL(nStartColumn),
  480. ROW_AS_YPIXEL(nCurrentLine),
  481. achStringToOutput,
  482. (nEndColumn - nStartColumn));
  483. }
  484. }
  485. /* Restore the device context to its original state before this function */
  486. /* was called. */
  487. RestoreDC(hdc, nIDSavedState);
  488. }
  489. /* ----------------------------------------------------------------------------
  490. * ODScrnInvalidate() *** PRIVATE FUNCTION ***
  491. *
  492. * Marks the specified area of the screen window as invalid, forcing the
  493. * screen thread to redraw it.
  494. *
  495. * Parameters: btLeft - The left most column to invalidate.
  496. *
  497. * btTop - The top most row to invalidate.
  498. *
  499. * btRight - The right most column to invalidate.
  500. *
  501. * btBottom - The bottom most row to invalidate.
  502. *
  503. * Return: void.
  504. */
  505. static void ODScrnInvalidate(BYTE btLeft, BYTE btTop, BYTE btRight,
  506. BYTE btBottom)
  507. {
  508. RECT rcToInvalidate;
  509. /* If the screen window has not been created yet, then return without */
  510. /* doing anything. */
  511. if(hwndScreenWindow == NULL) return;
  512. /* Obtain rectangle in client window coordinates, to be invalidated. */
  513. rcToInvalidate.left = COLUMN_AS_XPIXEL(btLeft);
  514. rcToInvalidate.top = ROW_AS_YPIXEL(btTop);
  515. rcToInvalidate.right = COLUMN_AS_XPIXEL(btRight + 1);
  516. rcToInvalidate.bottom = ROW_AS_YPIXEL(btBottom + 1);
  517. /* Mark this rectangle as invalid. */
  518. InvalidateRect(hwndScreenWindow, &rcToInvalidate, FALSE);
  519. }
  520. /* ----------------------------------------------------------------------------
  521. * ODScrnSetCurrentFont() *** PRIVATE FUNCTION ***
  522. *
  523. * Changes the current font to be used for drawing, updating anything that
  524. * needs updating.
  525. *
  526. * Parameters: hwndScreen - Handle to the screen window.
  527. *
  528. * nNewFont - Handle to the font to switch to.
  529. *
  530. * Return: void.
  531. */
  532. static void ODScrnSetCurrentFont(HWND hwndScreen, HFONT hNewFont)
  533. {
  534. HDC hdc;
  535. INT nIDSavedState;
  536. TEXTMETRIC TextMetrics;
  537. /* Obtain a handle to the a device context for the screen window. */
  538. hdc = GetDC(hwndScreen);
  539. /* If we are unable to obtian a device context, then return without */
  540. /* doing anything. */
  541. if(hdc == NULL)
  542. {
  543. return;
  544. }
  545. /* Change the current font. */
  546. hCurrentFont = hNewFont;
  547. /* Obtain text metrics from the device context, and then release the */
  548. /* device context. */
  549. nIDSavedState = SaveDC(hdc);
  550. SelectObject(hdc, hCurrentFont);
  551. GetTextMetrics(hdc, &TextMetrics);
  552. RestoreDC(hdc, nIDSavedState);
  553. ReleaseDC(hwndScreen, hdc);
  554. /* Determine the new size of a character cell. */
  555. nFontCellWidth = TextMetrics.tmMaxCharWidth;
  556. nFontCellHeight = TextMetrics.tmHeight;
  557. /* Force window sizes to be adjusted for the new font size. */
  558. ODScrnAdjustWindows();
  559. ODScrnAdjustWindows();
  560. }
  561. /* ----------------------------------------------------------------------------
  562. * ODScrnAdjustWindows()
  563. *
  564. * Resizes and repositions the screen window to the appropriate size based
  565. * on the current font, portions of the frame window's client area that are
  566. * in use, etc. Other windows whose size depends on the size of the screen
  567. * window are also updated.
  568. *
  569. * Parameters: None.
  570. *
  571. * Return: void.
  572. */
  573. void ODScrnAdjustWindows(void)
  574. {
  575. INT nNewClientWidth;
  576. INT nNewClientHeight;
  577. RECT rcClient;
  578. RECT rcWindow;
  579. INT nNonClientWidth;
  580. INT nNonClientHeight;
  581. INT nScreenWindowWidth;
  582. INT nScreenWindowHeight;
  583. HWND hwndFrame;
  584. INT nTopFrameUsed;
  585. INT nBottomFrameUsed;
  586. HWND hwndScreen;
  587. hwndScreen = hwndScreenWindow;
  588. ASSERT(hwndScreen != NULL);
  589. hwndFrame = GetParent(hwndScreen);
  590. ASSERT(hwndFrame != NULL);
  591. /* Determine areas of the frame window's client area that are already */
  592. /* in use. */
  593. nTopFrameUsed = ODFrameGetUsedClientAtTop(hwndFrame);
  594. nBottomFrameUsed = ODFrameGetUsedClientAtBottom(hwndFrame);
  595. /* Determine the new required size of the window's client area. */
  596. nNewClientWidth = nFontCellWidth * OD_SCREEN_WIDTH;
  597. nNewClientHeight = nFontCellHeight * OD_SCREEN_HEIGHT;
  598. /* Determine the size of the window's non-client area. */
  599. GetClientRect(hwndScreen, &rcClient);
  600. GetWindowRect(hwndScreen, &rcWindow);
  601. nNonClientWidth = (rcWindow.right - rcWindow.left)
  602. - (rcClient.right - rcClient.left);
  603. nNonClientHeight = (rcWindow.bottom - rcWindow.top)
  604. - (rcClient.bottom - rcClient.top);
  605. /* Determine the overall size required for the screen window. */
  606. nScreenWindowWidth = nNewClientWidth + nNonClientWidth;
  607. nScreenWindowHeight = nNewClientHeight + nNonClientHeight;
  608. /* Resize the screen window accordingly. */
  609. SetWindowPos(hwndScreen, NULL, 0, nTopFrameUsed, nScreenWindowWidth,
  610. nScreenWindowHeight, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER);
  611. /* Resize the OpenDoors frame window (which is the screen window's */
  612. /* parent) so that the screen window just fill's the frame window's */
  613. /* remaining client area. */
  614. GetClientRect(hwndFrame, &rcClient);
  615. GetWindowRect(hwndFrame, &rcWindow);
  616. nNonClientWidth = (rcWindow.right - rcWindow.left)
  617. - (rcClient.right - rcClient.left);
  618. nNonClientHeight = (rcWindow.bottom - rcWindow.top)
  619. - (rcClient.bottom - rcClient.top);
  620. SetWindowPos(hwndFrame, NULL, 0, 0, nScreenWindowWidth + nNonClientWidth,
  621. nScreenWindowHeight + nNonClientHeight + nTopFrameUsed
  622. + nBottomFrameUsed,
  623. SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER);
  624. }
  625. /* ----------------------------------------------------------------------------
  626. * ODScrnMessageLoop() *** PRIVATE FUNCTION ***
  627. *
  628. * Message loop for OpenDoors screen window thread.
  629. *
  630. * Parameters: hInstance - Handle to current instance.
  631. *
  632. * hwndScreen - Handle to the screen window.
  633. *
  634. * Return: void.
  635. */
  636. static void ODScrnMessageLoop(HANDLE hInstance, HWND hwndScreen)
  637. {
  638. MSG msg;
  639. HWND hwndFrame;
  640. ASSERT(hInstance != NULL);
  641. ASSERT(hwndScreen != NULL);
  642. /* Obtain a handle to the OpenDoors main frame window. */
  643. hwndFrame = GetParent(hwndScreen);
  644. /* Loop, fetching, translating and dispatching messages for any windows */
  645. /* created by this thread. (GetMessage() blocks when no messages are */
  646. /* available.) */
  647. while(GetMessage(&msg, NULL, 0, 0))
  648. {
  649. if(!ODFrameTranslateAccelerator(hwndFrame, &msg))
  650. {
  651. TranslateMessage(&msg);
  652. if(msg.message == WM_KEYDOWN)
  653. {
  654. PostMessage(hwndScreen, WM_KEYDOWN_RELAY, msg.wParam, msg.lParam);
  655. }
  656. DispatchMessage(&msg);
  657. }
  658. }
  659. }
  660. /* ----------------------------------------------------------------------------
  661. * ODScrnThreadProc() *** PRIVATE FUNCTION ***
  662. *
  663. * Function that execute the OpenDoors screen window thread. This thread's
  664. * primary task is to draw the screen window contents, when needed.
  665. *
  666. * Parameters: pParam - The thread parameter, which is a pointer to a
  667. * tODScrnThreadInfo structure.
  668. *
  669. * Return: TRUE on success, or FALSE on failure.
  670. */
  671. DWORD OD_THREAD_FUNC ODScrnThreadProc(void *pParam)
  672. {
  673. tODScrnThreadInfo *pScrnThreadInfo = (tODScrnThreadInfo *)pParam;
  674. HWND hwndScreen;
  675. HANDLE hInstance = pScrnThreadInfo->hInstance;
  676. HWND hwndFrame = pScrnThreadInfo->hwndFrame;
  677. /* We are now done with the thread startup information structure, */
  678. /* so deallocate it. */
  679. free(pScrnThreadInfo);
  680. /* Create the screen window. */
  681. hwndScreen = ODScrnCreateWin(hwndFrame, hInstance);
  682. if(hwndScreen == NULL)
  683. {
  684. return(FALSE);
  685. }
  686. /* Set the current font for the window. This, in turn will force the */
  687. /* window to be adjusted to the appropriate size, and will adjust the */
  688. /* size of the OpenDoors frame window accordingly. */
  689. ODScrnSetCurrentFont(hwndScreen, GetStockObject(OEM_FIXED_FONT));
  690. /* Prompt for the user's name before showing the windows, if required. */
  691. #ifdef ODPLAT_WIN32
  692. if(bPromptForUserName)
  693. {
  694. if(DialogBox(hInstance, MAKEINTRESOURCE(IDD_LOGIN), hwndFrame,
  695. ODInitLoginDlgProc) == IDCANCEL)
  696. {
  697. exit(od_control.od_errorlevel[1]);
  698. }
  699. PostMessage(hwndScreen, WM_SETFOCUS, 0, 0L);
  700. }
  701. #endif /* ODPLAT_WIN32 */
  702. /* Now, we can make the frame window visible. */
  703. if(od_control.od_cmd_show == SW_MINIMIZE ||
  704. od_control.od_cmd_show == SW_SHOWMINIMIZED ||
  705. od_control.od_cmd_show == SW_SHOWMINNOACTIVE)
  706. {
  707. ShowWindow(hwndFrame, SW_SHOWMINNOACTIVE);
  708. }
  709. else
  710. {
  711. ShowWindow(hwndFrame, SW_RESTORE);
  712. }
  713. /* Now, show the screen window. */
  714. ShowWindow(hwndScreen, SW_SHOW);
  715. /* Loop, processing messages for the screen window. */
  716. ODScrnMessageLoop(hInstance, hwndScreen);
  717. /* Destroy the screen window. */
  718. DestroyWindow(hwndScreen);
  719. return(TRUE);
  720. }
  721. /* ----------------------------------------------------------------------------
  722. * ODScrnStartWindow()
  723. *
  724. * Function that starts up the screen window thread, which in turn creates
  725. * and manages the screen window.
  726. *
  727. * Parameters: hInstance - Handle to the current application instance.
  728. *
  729. * phScreenThread - Pointer to location where screen thread handle
  730. * should be stored.
  731. *
  732. * hwndFrame - Handle to already created frame window.
  733. *
  734. * Return: kODRCSuccess on success, or an error code on failure.
  735. */
  736. tODResult ODScrnStartWindow(HANDLE hInstance, tODThreadHandle *phScreenThread,
  737. HWND hwndFrame)
  738. {
  739. tODScrnThreadInfo *pScrnThreadInfo;
  740. ASSERT(hInstance != NULL);
  741. ASSERT(phScreenThread != NULL);
  742. ASSERT(hwndFrame != NULL);
  743. /* Setup thread information to pass into the screen thread at startup. */
  744. if((pScrnThreadInfo = malloc(sizeof(tODScrnThreadInfo))) == NULL)
  745. {
  746. return(kODRCNoMemory);
  747. }
  748. pScrnThreadInfo->hInstance = hInstance;
  749. pScrnThreadInfo->hwndFrame = hwndFrame;
  750. /* Create the screen thread. */
  751. return(ODThreadCreate(phScreenThread, ODScrnThreadProc,
  752. pScrnThreadInfo));
  753. }
  754. /* ----------------------------------------------------------------------------
  755. * ODScrnSetFocusToWindow()
  756. *
  757. * Sets the current input focus to the screen window.
  758. *
  759. * Parameters: none
  760. *
  761. * Return: void
  762. */
  763. void ODScrnSetFocusToWindow(void)
  764. {
  765. if(hwndScreenWindow != NULL)
  766. {
  767. SetFocus(hwndScreenWindow);
  768. }
  769. }
  770. /* ----------------------------------------------------------------------------
  771. * ODScrnSetWinCaretPos()
  772. *
  773. * Repositions the Windows caret to the position of our cursor, if
  774. * appropriate.
  775. *
  776. * Parameters: none
  777. *
  778. * Return: void
  779. */
  780. static void ODScrnSetWinCaretPos(void)
  781. {
  782. /* Only move the caret if we have focus, and thus we are the one who */
  783. /* owns the caret. */
  784. if(bScreenHasFocus)
  785. {
  786. SetCaretPos(COLUMN_AS_XPIXEL(btCursorColumn + btLeftBoundary),
  787. ROW_AS_YPIXEL(btCursorRow + btTopBoundary + 1) - CARET_HEIGHT);
  788. }
  789. }
  790. #endif /* ODPLAT_WIN32 */
  791. /* ========================================================================= */
  792. /* Functions used throughout OpenDoors to manipulate local screen buffer. */
  793. /* ========================================================================= */
  794. /* ----------------------------------------------------------------------------
  795. * ODScrnInitialize()
  796. *
  797. * Initializes the local screen module.
  798. *
  799. * Parameters: none
  800. *
  801. * Return: kODRCSuccess on success, or an error code on failure.
  802. */
  803. tODResult ODScrnInitialize(void)
  804. {
  805. BOOL bClear = TRUE;
  806. #if defined(ODPLAT_DOS) || defined(ODPLAT_NIX)
  807. /* In silent mode, we perform all output in a block of memory that is */
  808. /* never displayed. */
  809. /* *nix is always in "silent mode" */
  810. #ifndef ODPLAT_NIX
  811. if(od_control.od_silent_mode)
  812. {
  813. #endif
  814. /* Allocate memory for screen buffer, using standard pointer type */
  815. /* for current memory model. */
  816. pAllocatedBufferMemory = malloc(SCREEN_BUFFER_SIZE);
  817. if(pAllocatedBufferMemory == NULL)
  818. {
  819. return(kODRCNoMemory);
  820. }
  821. /* Set the screen buffer far pointer to point to the allocated */
  822. /* buffer. */
  823. pScrnBuffer = pAllocatedBufferMemory;
  824. #ifndef ODPLAT_NIX
  825. }
  826. else
  827. {
  828. BYTE btDisplayMode;
  829. /* Get current video mode. */
  830. ASM push si
  831. ASM push di
  832. ASM mov ah, 0x0f
  833. ASM int 0x10
  834. ASM mov btDisplayMode, al
  835. ASM pop di
  836. ASM pop si
  837. switch(btDisplayMode & 0x7f)
  838. {
  839. /* No need to change mode, already colour 80x25. */
  840. case 0x02:
  841. case 0x03:
  842. wBufferSegment = 0xb800;
  843. pScrnBuffer = (void ODFAR *)0xb8000000L;
  844. bClear = TRUE;
  845. break;
  846. /* No need to change mode, already monochrome 80x25. */
  847. case 0x07:
  848. wBufferSegment = 0xb000;
  849. pScrnBuffer = (void ODFAR *)0xb0000000L;
  850. bClear = TRUE;
  851. break;
  852. /* Must change mode to monochrome 80x25. */
  853. case 0x21:
  854. wBufferSegment = 0xb000;
  855. pScrnBuffer = (void ODFAR *)0xb0000000L;
  856. bClear = FALSE;
  857. /* set mode to 0x07 */
  858. ASM push si
  859. ASM push di
  860. ASM mov ax, 0x0007
  861. ASM int 0x10
  862. ASM pop di
  863. ASM pop si
  864. break;
  865. /* Must change mode to colour 80x25. */
  866. default:
  867. wBufferSegment = 0xb800;
  868. pScrnBuffer = (void ODFAR *)0xb8000000L;
  869. bClear = FALSE;
  870. /* set mode to 0x03. */
  871. ASM push si
  872. ASM push di
  873. ASM mov ax, 0x0003
  874. ASM int 0x10
  875. ASM pop di
  876. ASM pop si
  877. }
  878. /* Adjust address for display page which is being used. */
  879. ASM push si
  880. ASM push di
  881. ASM mov ah, 0x0f
  882. ASM int 0x10
  883. ASM mov btDisplayPage, bh
  884. ASM pop di
  885. ASM pop si
  886. if(btDisplayPage!=0)
  887. {
  888. wBufferSegment += (SCREEN_BUFFER_SEGMENT_SIZE * btDisplayPage);
  889. ((char ODFAR *)pScrnBuffer) += (SCREEN_BUFFER_SIZE * btDisplayPage);
  890. }
  891. if(ODMultitasker == kMultitaskerDV)
  892. {
  893. /* Determine address of DV screen buffer. */
  894. /* This doesn't check rows, bh = rows, bl = columns. */
  895. ASM mov ax, 0x2b02
  896. ASM mov cx, 0x4445
  897. ASM mov dx, 0x5351
  898. ASM int 0x21
  899. ASM cmp bx, 0x1950
  900. ASM jne no_change
  901. ASM mov wBufferSegment, dx
  902. (long)pScrnBuffer = ODDWordShiftLeft((long)wBufferSegment, 16);
  903. no_change: ;
  904. }
  905. }
  906. #endif /* ODPLAT_DOS */
  907. #endif /* ODPLAT_DOS/NIX */
  908. #ifdef ODPLAT_WIN32
  909. /* Allocate memory for screen buffer. */
  910. pScrnBuffer = malloc(SCREEN_BUFFER_SIZE);
  911. if(pScrnBuffer == NULL)
  912. {
  913. return(kODRCNoMemory);
  914. }
  915. #endif /* ODPLAT_WIN32 */
  916. /* Initialize display system variables. */
  917. btLeftBoundary = 0;
  918. btRightBoundary = 79;
  919. btTopBoundary = 0;
  920. btBottomBoundary = 24;
  921. btCurrentAttribute = 0x07;
  922. bScrollEnabled = 1;
  923. /* Clear local screen. */
  924. if(bClear)
  925. {
  926. ODScrnClear();
  927. }
  928. /* Enable flashing cursor. */
  929. bCaretOn = FALSE;
  930. ODScrnEnableCaret(TRUE);
  931. /* Return with success. */
  932. return(kODRCSuccess);
  933. }
  934. /* ----------------------------------------------------------------------------
  935. * ODScrnShutdown()
  936. *
  937. * De-initializes the screen module.
  938. *
  939. * Parameters: none
  940. *
  941. * Return: void
  942. */
  943. void ODScrnShutdown(void)
  944. {
  945. #ifdef ODPLAT_WIN32
  946. /* Deallocate screen buffer memory. */
  947. if(pScrnBuffer != NULL)
  948. {
  949. free(pScrnBuffer);
  950. pScrnBuffer = NULL;
  951. }
  952. #else /* !ODPLAT_WIN32 */
  953. /* In silent mode, we must deallocate screen buffer memory. */
  954. /* *nix is always in silent mode */
  955. #ifndef ODPLAT_NIX
  956. if(od_control.od_silent_mode && pAllocatedBufferMemory != NULL)
  957. {
  958. #endif
  959. free(pAllocatedBufferMemory);
  960. pAllocatedBufferMemory = NULL;
  961. pScrnBuffer = NULL;
  962. #ifndef ODPLAT_NIX
  963. }
  964. #endif
  965. #endif
  966. }
  967. /* ----------------------------------------------------------------------------
  968. * ODScrnSetBoundary()
  969. *
  970. * Sets the current boundary area on the screen. All output is constrained
  971. * within this boundary area.
  972. *
  973. * Parameters: btLeft - 1-based column number of the left edge of the area.
  974. *
  975. * btTop - 1-based row number of the top edge of the area.
  976. *
  977. * btRight - 1-based column number of the right edge of the area.
  978. *
  979. * btBottom - 1-based row number of the bottom edge of the area.
  980. *
  981. * Return: void
  982. */
  983. void ODScrnSetBoundary(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom)
  984. {
  985. /* Set internal window location variables. */
  986. btLeftBoundary = btLeft - 1;
  987. btRightBoundary = btRight - 1;
  988. btTopBoundary = btTop - 1;
  989. btBottomBoundary = btBottom - 1;
  990. /* Ensure that the cursor is located within the new window boundaries. */
  991. if(btCursorColumn > btRightBoundary - btLeftBoundary)
  992. {
  993. btCursorColumn = btRightBoundary - btLeftBoundary;
  994. }
  995. else if(btCursorColumn < btLeftBoundary)
  996. {
  997. btCursorColumn = btLeftBoundary;
  998. }
  999. if(btCursorRow > btBottomBoundary - btTopBoundary)
  1000. {
  1001. btCursorRow = btBottomBoundary - btTopBoundary;
  1002. }
  1003. else if(btCursorRow < btTopBoundary)
  1004. {
  1005. btCursorRow = btTopBoundary;
  1006. }
  1007. /* Execute the position flashing cursor primitive. */
  1008. ODScrnUpdateCaretPos();
  1009. }
  1010. /* ----------------------------------------------------------------------------
  1011. * ODScrnSetCursorPos()
  1012. *
  1013. * Sets the current cursor position. The cursor position is where the caret
  1014. * (flashing cursor) appears (if it is currently turned on), and is the
  1015. * location where ODScrnDisplayChar(), ODScrnDisplayString() and ODScrnPrintf()
  1016. * will perform their output. Each of these functions, update the cursor
  1017. * position to the next character cell after the end of their output. Other
  1018. * ODScrn...() functions may also change the current cursor position.
  1019. *
  1020. * Parameters: btColumn - The 1-based column number where the cursor will
  1021. * be placed.
  1022. *
  1023. * Return: void
  1024. */
  1025. void ODScrnSetCursorPos(BYTE btColumn, BYTE btRow)
  1026. {
  1027. /* Set internal cursor position values. */
  1028. btCursorColumn = btColumn - 1;
  1029. btCursorRow = btRow - 1;
  1030. /* Ensure that cursor falls within the current output window. */
  1031. if(btCursorColumn > btRightBoundary - btLeftBoundary)
  1032. btCursorColumn = btRightBoundary - btLeftBoundary;
  1033. if(btCursorRow > btBottomBoundary - btTopBoundary)
  1034. btCursorRow = btBottomBoundary - btTopBoundary;
  1035. /* Execute the position flashing cursor primitive. */
  1036. ODScrnUpdateCaretPos();
  1037. }
  1038. /* ----------------------------------------------------------------------------
  1039. * ODScrnSetAttribute()
  1040. *
  1041. * Sets the current display attribute, to be used by ODScrnDisplayChar(),
  1042. * ODScrnDisplayString(), ODScrnPrintf() and ODScrnClear(). The display
  1043. * attribute byte is always in the IBM color attribute format, with the
  1044. * lower 4 bits indicating the foreground color, and the next 3 bits
  1045. * indicating the background color. The upper bit specifies whether the text
  1046. * is flashing, although this code may not actually show flashing text on
  1047. * all platforms.
  1048. *
  1049. * Parameters: btAttribute - The new color attribute to use.
  1050. *
  1051. * Return: void
  1052. */
  1053. void ODScrnSetAttribute(BYTE btAttribute)
  1054. {
  1055. /* Set internal display colour attribute. */
  1056. btCurrentAttribute = btAttribute;
  1057. }
  1058. /* ----------------------------------------------------------------------------
  1059. * ODScrnEnableScrolling()
  1060. *
  1061. * Enables or disables scrolling of text within the currently defined boundary
  1062. * area when a carriage return is sent with the cursor located on the bottom
  1063. * line of bounary area.
  1064. *
  1065. * Parameters: bEnable - TRUE to enable scrolling, FALSE to disable scrolling.
  1066. *
  1067. * Return: void
  1068. */
  1069. void ODScrnEnableScrolling(BOOL bEnable)
  1070. {
  1071. /* Stores the current scrolling setting. */
  1072. bScrollEnabled = bEnable;
  1073. }
  1074. /* ----------------------------------------------------------------------------
  1075. * ODScrnEnableCaret()
  1076. *
  1077. * Turns the caret (flashing indicator of the current cursor location) on or
  1078. * off. Under the Win32 platform, the caret is always active when the
  1079. * window has input focus, and inactive at any other time. Hene, under
  1080. * Win32, this function has no effect.
  1081. *
  1082. * Parameters: bEnable - TRUE to turn on the flashing caret, FALSE to turn it
  1083. * off.
  1084. *
  1085. * Return: void
  1086. */
  1087. void ODScrnEnableCaret(BOOL bEnable)
  1088. {
  1089. #ifdef ODPLAT_DOS
  1090. if(bCaretOn == bEnable) return;
  1091. bCaretOn = bEnable;
  1092. /* Execute the cursor on / off primitive. */
  1093. ASM push si
  1094. ASM push di
  1095. ASM mov ah, 0x03
  1096. ASM mov bh, btDisplayPage
  1097. ASM int 0x10
  1098. /* ch = start line, cl = end line. */
  1099. ASM push cx
  1100. ASM mov ah, 0x0f
  1101. ASM int 0x10
  1102. ASM pop cx
  1103. /* al = video mode. */
  1104. ASM push ax
  1105. ASM and ch, 0x1f
  1106. ASM mov al, bCaretOn
  1107. ASM and al, al
  1108. ASM jnz set_cursor
  1109. /* ch bits 5-6 = blink attr */
  1110. /* 00 = normal */
  1111. /* 01 = invisible */
  1112. ASM or ch, 0x20
  1113. set_cursor:
  1114. ASM pop ax
  1115. ASM mov bh, btDisplayPage
  1116. ASM mov ah, 0x01
  1117. ASM int 0x10
  1118. ASM pop di
  1119. ASM pop si
  1120. if(bCaretOn)
  1121. {
  1122. /* Turn on the local caret, updating its position. */
  1123. ODScrnUpdateCaretPos();
  1124. }
  1125. else
  1126. {
  1127. /* Turn off the local caret. */
  1128. ASM mov ah, 0x02
  1129. ASM mov bh, btDisplayPage
  1130. ASM mov dh, OD_SCREEN_HEIGHT
  1131. ASM mov dl, OD_SCREEN_WIDTH
  1132. ASM push si
  1133. ASM push di
  1134. ASM int 0x10
  1135. ASM pop di
  1136. ASM pop si
  1137. }
  1138. #endif /* ODPLAT_DOS */
  1139. }
  1140. /* ----------------------------------------------------------------------------
  1141. * ODScrnGetTextInfo()
  1142. *
  1143. * Fills a structure with information about the current display settings,
  1144. * including the position of the current boundary area (output window),
  1145. * color attribute and cursor location.
  1146. *
  1147. * Parameters: pTextInfo - Pointer to the structure to store the current text
  1148. * settings information in.
  1149. *
  1150. * Return: void
  1151. */
  1152. void ODScrnGetTextInfo(tODScrnTextInfo *pTextInfo)
  1153. {
  1154. pTextInfo->wintop = btTopBoundary + 1;
  1155. pTextInfo->winleft = btLeftBoundary + 1;
  1156. pTextInfo->winright = btRightBoundary + 1;
  1157. pTextInfo->winbottom = btBottomBoundary + 1;
  1158. pTextInfo->attribute = btCurrentAttribute;
  1159. pTextInfo->curx = btCursorColumn + 1;
  1160. pTextInfo->cury = btCursorRow + 1;
  1161. }
  1162. /* ----------------------------------------------------------------------------
  1163. * ODScrnPrintf()
  1164. *
  1165. * Performs formatted output within the current boundary area.
  1166. *
  1167. * Parameters: pszFormat - Format string, which is in the same format as is
  1168. * used by the standard C printf() function.
  1169. *
  1170. * The semantics of additional parameters is specified by the
  1171. * contents of the pszFormat string.
  1172. *
  1173. * Return: The standard printf() return value.
  1174. */
  1175. INT ODScrnPrintf(char *pszFormat, ...)
  1176. {
  1177. va_list pArgumentList;
  1178. INT nToReturn;
  1179. /* Generate string to display. */
  1180. va_start(pArgumentList, pszFormat);
  1181. nToReturn = vsprintf(szBuffer, pszFormat, pArgumentList);
  1182. va_end(pArgumentList);
  1183. /* Ensure that we didn't overrun the buffer. */
  1184. ASSERT(strlen(szBuffer) <= sizeof(szBuffer) - 1);
  1185. /* Display generated string. */
  1186. ODScrnDisplayString(szBuffer);
  1187. /* Return appropriate value. */
  1188. return (nToReturn);
  1189. }
  1190. /* ----------------------------------------------------------------------------
  1191. * ODScrnDisplayChar()
  1192. *
  1193. * Writes a single character within the current boundary area, advancing the
  1194. * cursor.
  1195. *
  1196. * Parameters: chToOutput - The character to display.
  1197. *
  1198. * Return: void
  1199. */
  1200. void ODScrnDisplayChar(unsigned char chToOutput)
  1201. {
  1202. BYTE ODFAR *pbtDest;
  1203. ODScrnGetCursorPos();
  1204. if(btCursorColumn > btRightBoundary - btLeftBoundary)
  1205. {
  1206. btCursorColumn = btRightBoundary - btLeftBoundary;
  1207. }
  1208. if(btCursorRow > btBottomBoundary - btTopBoundary)
  1209. {
  1210. btCursorRow = btBottomBoundary - btTopBoundary;
  1211. }
  1212. switch(chToOutput)
  1213. {
  1214. /* If character is a carriage return. */
  1215. case '\r':
  1216. btCursorColumn = 0;
  1217. break;
  1218. /* If character is a line feed. */
  1219. case '\n':
  1220. /* If cursor is at bottom of output window. */
  1221. if(btCursorRow == btBottomBoundary - btTopBoundary)
  1222. {
  1223. /* Scroll the screen up by one line. */
  1224. ODScrnScrollUpAndInvalidate();
  1225. }
  1226. /* If cursor is not at bottom of output window. */
  1227. else
  1228. {
  1229. /* Move the cursor down one line. */
  1230. ++btCursorRow;
  1231. }
  1232. break;
  1233. case '\b':
  1234. /* If backspace. */
  1235. if(btCursorColumn != 0) --btCursorColumn;
  1236. break;
  1237. case '\t':
  1238. /* If tab character. */
  1239. btCursorColumn = ((btCursorColumn / 8) + 1) * 8;
  1240. if(btCursorColumn > btRightBoundary - btLeftBoundary)
  1241. {
  1242. btCursorColumn = 0;
  1243. /* If moving cursor down one line advances past end of window. */
  1244. if(++btCursorRow > btBottomBoundary - btTopBoundary)
  1245. {
  1246. /* Move cursor back to bottom line of window. */
  1247. btCursorRow = btBottomBoundary - btTopBoundary;
  1248. /* Scroll the screen up by one line. */
  1249. ODScrnScrollUpAndInvalidate();
  1250. }
  1251. }
  1252. break;
  1253. case '\a':
  1254. /* If bell. */
  1255. if(!od_control.od_silent_mode)
  1256. {
  1257. #ifdef ODPLAT_DOS
  1258. ASM mov ah, 0x02
  1259. ASM mov dl, 7
  1260. ASM int 0x21
  1261. #endif /* ODPLAT_DOS */
  1262. #ifdef ODPLAT_WIN32
  1263. MessageBeep(0xffffffff);
  1264. #endif /* ODPLAT_WIN32 */
  1265. }
  1266. break;
  1267. /* If character is not a control character. */
  1268. default:
  1269. /* Output character to display buffer. */
  1270. pbtDest = (BYTE ODFAR *)pScrnBuffer
  1271. + ((btTopBoundary + btCursorRow) * BUFFER_LINE_BYTES
  1272. + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR);
  1273. *pbtDest++ = chToOutput;
  1274. *pbtDest = btCurrentAttribute;
  1275. ASSERT(pbtDest >= (BYTE ODFAR *)pScrnBuffer);
  1276. ASSERT(pbtDest < (BYTE ODFAR *)pScrnBuffer + SCREEN_BUFFER_SIZE);
  1277. #ifdef ODPLAT_WIN32
  1278. /* Force the updated area of the screen window to be redrawn. */
  1279. ODScrnInvalidate((BYTE)(btCursorColumn + btLeftBoundary),
  1280. (BYTE)(btCursorRow + btTopBoundary),
  1281. (BYTE)(btCursorColumn + btLeftBoundary),
  1282. (BYTE)(btCursorRow + btTopBoundary));
  1283. #endif /* ODPLAT_WIN32 */
  1284. /* Advance cursor. If at end of line ... */
  1285. if(++btCursorColumn > btRightBoundary - btLeftBoundary)
  1286. {
  1287. /* Wrap cursor if necessary. */
  1288. btCursorColumn = 0;
  1289. /* If moving cursor down one line advances past end of window. */
  1290. if(++btCursorRow > btBottomBoundary - btTopBoundary)
  1291. {
  1292. /* Move cursor back to bottom line of window. */
  1293. btCursorRow = btBottomBoundary - btTopBoundary;
  1294. /* Scroll the screen up by one line. */
  1295. ODScrnScrollUpAndInvalidate();
  1296. }
  1297. }
  1298. }
  1299. /* Execute the update flashing cursor primitive. */
  1300. ODScrnUpdateCaretPos();
  1301. }
  1302. /* ----------------------------------------------------------------------------
  1303. * ODScrnGetCursorPos() *** PRIVATE FUNCTION ***
  1304. *
  1305. * Updates the current cursor position (output position) from the location of
  1306. * the caret (flashing cursor). This function doesn't do anything on the
  1307. * Win32 platform, since we nobody else can reposition the cursor.
  1308. *
  1309. * Parameters: none
  1310. *
  1311. * Return: void
  1312. */
  1313. static void ODScrnGetCursorPos(void)
  1314. {
  1315. #ifdef ODPLAT_DOS
  1316. if(!bCaretOn) return;
  1317. ASM mov ah, 0x03
  1318. ASM mov bh, btDisplayPage
  1319. ASM push si
  1320. ASM push di
  1321. ASM int 0x10
  1322. ASM pop di
  1323. ASM pop si
  1324. ASM sub dh, btTopBoundary
  1325. ASM mov btCursorRow, dh
  1326. ASM sub dl, btLeftBoundary
  1327. ASM mov btCursorColumn, dl
  1328. #endif /* ODPLAT_DOS */
  1329. }
  1330. /* ----------------------------------------------------------------------------
  1331. * ODScrnUpdateCaretPos() *** PRIVATE FUNCTION ***
  1332. *
  1333. * Updates the position of the caret (flashing cursor) from the current cursor
  1334. * location (output position).
  1335. *
  1336. * Parameters: none
  1337. *
  1338. * Return: void
  1339. */
  1340. static void ODScrnUpdateCaretPos(void)
  1341. {
  1342. #ifdef ODPLAT_DOS
  1343. if(!bCaretOn) return;
  1344. /* Update position of flashing cursor on screen */
  1345. ASM mov ah, 0x02
  1346. ASM mov bh, btDisplayPage
  1347. ASM mov dh, btCursorRow
  1348. ASM add dh, btTopBoundary
  1349. ASM mov dl, btCursorColumn
  1350. ASM add dl, btLeftBoundary
  1351. ASM push si
  1352. ASM push di
  1353. ASM int 0x10
  1354. ASM pop di
  1355. ASM pop si
  1356. #endif /* ODPLAT_DOS */
  1357. #ifdef ODPLAT_WIN32
  1358. if(hwndScreenWindow != NULL)
  1359. {
  1360. PostMessage(hwndScreenWindow, WM_MOVE_YOUR_CARET, 0, 0);
  1361. }
  1362. #endif /* ODPLAT_WIN32 */
  1363. }
  1364. /* ----------------------------------------------------------------------------
  1365. * ODScrnClear()
  1366. *
  1367. * Clears the text within the currently defined boundary area, setting the
  1368. * display attribute of the entire boundary area to the current display
  1369. * color.
  1370. *
  1371. * Parameters: none
  1372. *
  1373. * Return: void
  1374. */
  1375. void ODScrnClear(void)
  1376. {
  1377. WORD ODFAR *pDest = (WORD ODFAR *)pScrnBuffer +
  1378. ((btTopBoundary * OD_SCREEN_WIDTH) + btLeftBoundary);
  1379. WORD wBlank = (((WORD)btCurrentAttribute) << 8) | 32;
  1380. BYTE btCurColumn;
  1381. BYTE btCurLine = (btBottomBoundary - btTopBoundary) + 1;
  1382. BYTE btColumnStart = (btRightBoundary - btLeftBoundary) + 1;
  1383. BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart;
  1384. /* Clear contents of current window. */
  1385. do
  1386. {
  1387. btCurColumn = btColumnStart;
  1388. do
  1389. {
  1390. ASSERT(pDest >= (WORD ODFAR *)pScrnBuffer);
  1391. ASSERT(pDest <= (WORD ODFAR *)pScrnBuffer + 2000);
  1392. *(pDest++) = wBlank;
  1393. } while ((--btCurColumn) != 0);
  1394. pDest += btSkip;
  1395. } while((--btCurLine) != 0);
  1396. /* Move cursor to top left-hand corner of current window. */
  1397. btCursorColumn = btCursorRow = 0;
  1398. /* Execute the update flashing cursor primitive. */
  1399. ODScrnUpdateCaretPos();
  1400. #ifdef ODPLAT_WIN32
  1401. /* Force the updated area of the screen window to be redrawn. */
  1402. ODScrnInvalidate(btLeftBoundary, btTopBoundary, btRightBoundary,
  1403. btBottomBoundary);
  1404. #endif /* ODPLAT_WIN32 */
  1405. }
  1406. /* ----------------------------------------------------------------------------
  1407. * ODScrnScrollUpAndInvalidate() *** PRIVATE FUNCTION ***
  1408. *
  1409. * Scrolls the entire screen up by one line, only if scrolling is enabled.
  1410. * If scrolling is performed, invalidates area that was scrolled. Scrolling
  1411. * is accomplished using ODScrnScrollUpOneLine().
  1412. *
  1413. * Parameters: none
  1414. *
  1415. * Return: void
  1416. */
  1417. static void ODScrnScrollUpAndInvalidate(void)
  1418. {
  1419. /* If scrolling is enabled. */
  1420. if(bScrollEnabled)
  1421. {
  1422. /* Execute the scroll primitive. */
  1423. ODScrnScrollUpOneLine();
  1424. #ifdef ODPLAT_WIN32
  1425. /* Force the updated area of the screen window to be redrawn. */
  1426. ODScrnInvalidate(btLeftBoundary, btTopBoundary, btRightBoundary,
  1427. btBottomBoundary);
  1428. #endif /* ODPLAT_WIN32 */
  1429. }
  1430. }
  1431. /* ----------------------------------------------------------------------------
  1432. * ODScrnScrollUpOneLine() *** PRIVATE FUNCTION ***
  1433. *
  1434. * Scrolls the area within the current output boundary up one line, leaving the
  1435. * newly created line at the bottom of the area blank, with the current display
  1436. * attribute.
  1437. *
  1438. * Parameters: none
  1439. *
  1440. * Return: void
  1441. */
  1442. static void ODScrnScrollUpOneLine(void)
  1443. {
  1444. WORD ODFAR *pwDest = (WORD ODFAR *)pScrnBuffer
  1445. + (btTopBoundary * OD_SCREEN_WIDTH + btLeftBoundary);
  1446. WORD ODFAR *pwSource;
  1447. BYTE btCurColumn;
  1448. BYTE btCurLine = btBottomBoundary - btTopBoundary;
  1449. BYTE btColumnStart = btRightBoundary - btLeftBoundary + 1;
  1450. BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart;
  1451. WORD wBlank = (((WORD)btCurrentAttribute) << 8) | 32;
  1452. pwSource = pwDest + OD_SCREEN_WIDTH;
  1453. ASSERT(btSkip >= 0 && btSkip <= OD_SCREEN_WIDTH);
  1454. /* Move text in area of window up one line. */
  1455. do
  1456. {
  1457. btCurColumn = btColumnStart;
  1458. do
  1459. {
  1460. ASSERT(pwDest >= (WORD ODFAR *)pScrnBuffer);
  1461. ASSERT(pwDest <= (WORD ODFAR *)pScrnBuffer + 2000);
  1462. ASSERT(pwSource >= (WORD ODFAR *)pScrnBuffer);
  1463. ASSERT(pwSource <= (WORD ODFAR *)pScrnBuffer+2000);
  1464. *(pwDest++) = *(pwSource++);
  1465. } while((--btCurColumn) != 0);
  1466. pwDest += btSkip;
  1467. pwSource += btSkip;
  1468. } while ((--btCurLine) != 0);
  1469. /* Clear newly created line at bottom of window. */
  1470. btCurColumn = btColumnStart;
  1471. do
  1472. {
  1473. ASSERT(pwDest >= (WORD ODFAR *)pScrnBuffer);
  1474. ASSERT(pwDest <= (WORD ODFAR *)pScrnBuffer + 2000);
  1475. *(pwDest++) = wBlank;
  1476. } while((--btCurColumn) != 0);
  1477. }
  1478. /* ----------------------------------------------------------------------------
  1479. * ODScrnGetText()
  1480. *
  1481. * Copies a portion of the currently displayed text and corresponding color
  1482. * attributes to a buffer provided by the caller.
  1483. *
  1484. * Parameters: btLeft - Column number of the left edge of the area to copy
  1485. * from.
  1486. *
  1487. * btTop - Row number of the top edge of the area to copy from.
  1488. *
  1489. * btRight - Column number of the right edge of the area to copy
  1490. * from.
  1491. *
  1492. * btBottom - Row number of the bottom edge of the area to copy
  1493. * from.
  1494. *
  1495. * pbtBuffer - A pointer to the buffer to copy to. It is the
  1496. * caller's responsibility to ensure that this buffer
  1497. * is large enough. This buffer must be at least
  1498. * 2 x (Width of area) x (Height of area) bytes in size.
  1499. *
  1500. * Return: TRUE on success, or FALSE on failure.
  1501. */
  1502. BOOL ODScrnGetText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom,
  1503. void *pbtBuffer)
  1504. {
  1505. WORD *pwBuffer = (WORD *)pbtBuffer;
  1506. WORD ODFAR *pSource = (WORD ODFAR *)pScrnBuffer
  1507. + ((((--btTop) + btTopBoundary)
  1508. * OD_SCREEN_WIDTH) + btLeftBoundary + (--btLeft));
  1509. BYTE btCurColumn;
  1510. BYTE btCurLine = (--btBottom) - btTop + 1;
  1511. BYTE btColumnStart = (--btRight) - btLeft + 1;
  1512. BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart;
  1513. ASSERT(btLeft >= 0);
  1514. ASSERT(btTop >= 0);
  1515. ASSERT(btRight <= btRightBoundary - btLeftBoundary);
  1516. ASSERT(btBottom <= btBottomBoundary - btTopBoundary);
  1517. ASSERT(pbtBuffer);
  1518. /* Copy contents of screen block to buffer */
  1519. do
  1520. {
  1521. btCurColumn = btColumnStart;
  1522. do
  1523. {
  1524. ASSERT(pSource >= (WORD ODFAR *)pScrnBuffer);
  1525. ASSERT(pSource <= (WORD ODFAR *)pScrnBuffer + 2000);
  1526. ASSERT(pwBuffer >= (WORD *)pbtBuffer);
  1527. ASSERT(pwBuffer <= (WORD *)pbtBuffer + 2000);
  1528. *(pwBuffer++) = *(pSource++);
  1529. } while ((--btCurColumn) != 0);
  1530. pSource += btSkip;
  1531. } while((--btCurLine) != 0);
  1532. return(TRUE);
  1533. }
  1534. /* ----------------------------------------------------------------------------
  1535. * ODScrnPutText()
  1536. *
  1537. * Changes the currently displayed text and corresponding color attributes in
  1538. * the specified area, to the values taken from the buffer. This buffer is in
  1539. * the same format as is produce by the ODScrnGetText() function.
  1540. *
  1541. * Parameters: btLeft - Column number of the left edge of the area to copy
  1542. * to.
  1543. *
  1544. * btTop - Row number of the top edge of the area to copy to.
  1545. *
  1546. * btRight - Column number of the right edge of the area to copy
  1547. * to.
  1548. *
  1549. * btBottom - Row number of the bottom edge of the area to copy
  1550. * to.
  1551. *
  1552. * pbtBuffer - A pointer to the buffer to copy from.
  1553. *
  1554. * Return: TRUE on success, or FALSE on failure.
  1555. */
  1556. BOOL ODScrnPutText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom,
  1557. void *pbtBuffer)
  1558. {
  1559. WORD *pwBuffer = (WORD *)pbtBuffer;
  1560. WORD ODFAR *pDest = (WORD ODFAR *)pScrnBuffer
  1561. + ((((--btTop) + btTopBoundary)
  1562. * OD_SCREEN_WIDTH) + btLeftBoundary + (--btLeft));
  1563. BYTE btCurColumn;
  1564. BYTE btCurLine = (--btBottom) - btTop + 1;
  1565. BYTE btColumnStart = (--btRight) - btLeft + 1;
  1566. BYTE btSkip = OD_SCREEN_WIDTH - btColumnStart;
  1567. ASSERT(btLeft >= 0 && btTop >= 0);
  1568. ASSERT(btLeft <= btRightBoundary - btLeftBoundary);
  1569. ASSERT(btTop <= btBottomBoundary - btTopBoundary);
  1570. ASSERT(btRight >= 0 && btBottom >= 0);
  1571. ASSERT(btRight <= btRightBoundary - btLeftBoundary);
  1572. ASSERT(btBottom <= btBottomBoundary - btTopBoundary);
  1573. ASSERT(pbtBuffer != NULL);
  1574. /* Copy contents of screen block to buffer. */
  1575. do
  1576. {
  1577. btCurColumn = btColumnStart;
  1578. do
  1579. {
  1580. ASSERT(pDest >= (WORD ODFAR *)pScrnBuffer);
  1581. ASSERT(pDest <= (WORD ODFAR *)pScrnBuffer + 2000);
  1582. ASSERT(pwBuffer >= (WORD *)pbtBuffer);
  1583. ASSERT(pwBuffer <= (WORD *)pbtBuffer + 2000);
  1584. *(pDest++) = *(pwBuffer++);
  1585. } while ((--btCurColumn) != 0);
  1586. pDest += btSkip;
  1587. } while((--btCurLine) != 0);
  1588. #ifdef ODPLAT_WIN32
  1589. /* Force the updated area of the screen window to be redrawn. */
  1590. ODScrnInvalidate((BYTE)(btLeftBoundary + btLeft),
  1591. (BYTE)(btTopBoundary + btTop),
  1592. (BYTE)(btRightBoundary + btRight),
  1593. (BYTE)(btBottomBoundary + btBottom));
  1594. #endif /* ODPLAT_WIN32 */
  1595. return(TRUE);
  1596. }
  1597. /* ----------------------------------------------------------------------------
  1598. * ODScrnDisplayString()
  1599. *
  1600. * Copies the contents of a string to the display, using the currently set
  1601. * color attributes. The cursor location is updated to the end of the string
  1602. * on the screen.
  1603. *
  1604. * Parameters: pszString - Pointer to the string to display.
  1605. *
  1606. * Return: void.
  1607. */
  1608. void ODScrnDisplayString(const char *pszString)
  1609. {
  1610. ODScrnDisplayBuffer(pszString, strlen(pszString));
  1611. }
  1612. /* ----------------------------------------------------------------------------
  1613. * ODScrnDisplayBuffer()
  1614. *
  1615. * Copies the contents of a buffer to the display, using the currently set
  1616. * color attributes. The cursor location is updated to the end of the text
  1617. * displayed to the screen.
  1618. *
  1619. * Parameters: pBuffer - Pointer to a buffer containing the
  1620. * character(s) to display.
  1621. *
  1622. * nCharsToDisplay - Count of number of characters to display from
  1623. * the buffer.
  1624. *
  1625. * Return: void.
  1626. */
  1627. void ODScrnDisplayBuffer(const char *pBuffer, INT nCharsToDisplay)
  1628. {
  1629. const char *pchCurrentChar = pBuffer;
  1630. INT nCharsLeft = nCharsToDisplay;
  1631. BYTE ODFAR *pDest;
  1632. BYTE btLeftColumn;
  1633. BYTE btAttribute = btCurrentAttribute;
  1634. BYTE btCurrentColumn;
  1635. BYTE btBottom = btBottomBoundary - btTopBoundary;
  1636. #ifdef ODPLAT_WIN32
  1637. BOOL bAnythingInvalid = FALSE;
  1638. BYTE btLeftMost;
  1639. BYTE btRightMost;
  1640. BYTE btTopMost;
  1641. BYTE btBottomMost;
  1642. #endif /* ODPLAT_WIN32 */
  1643. ASSERT(pBuffer != NULL);
  1644. ASSERT(nCharsToDisplay >= 0);
  1645. ODScrnGetCursorPos();
  1646. if(btCursorColumn > btRightBoundary - btLeftBoundary)
  1647. {
  1648. btCursorColumn = btRightBoundary - btLeftBoundary;
  1649. }
  1650. if(btCursorRow > btBottomBoundary - btTopBoundary)
  1651. {
  1652. btCursorRow = btBottomBoundary - btTopBoundary;
  1653. }
  1654. btCurrentColumn = btCursorColumn;
  1655. btLeftColumn = btRightBoundary - (btCurrentColumn + btLeftBoundary);
  1656. pDest = (BYTE ODFAR *) pScrnBuffer + (((btTopBoundary + btCursorRow)
  1657. * BUFFER_LINE_BYTES)
  1658. + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR);
  1659. while(nCharsLeft--)
  1660. {
  1661. ASSERT(pDest >= (BYTE ODFAR *)pScrnBuffer);
  1662. ASSERT(pDest <= (BYTE ODFAR *)pScrnBuffer + SCREEN_BUFFER_SIZE);
  1663. switch(*pchCurrentChar)
  1664. {
  1665. case '\r':
  1666. btCurrentColumn = 0;
  1667. btLeftColumn = btRightBoundary - btLeftBoundary;
  1668. pDest = (BYTE ODFAR *)pScrnBuffer + ((btTopBoundary + btCursorRow)
  1669. * BUFFER_LINE_BYTES + btLeftBoundary * BYTES_PER_CHAR);
  1670. pchCurrentChar++;
  1671. break;
  1672. case '\n':
  1673. if (btCursorRow < btBottom)
  1674. {
  1675. ++btCursorRow;
  1676. pDest += BUFFER_LINE_BYTES;
  1677. }
  1678. else if(bScrollEnabled)
  1679. {
  1680. ODScrnScrollUpOneLine();
  1681. #ifdef ODPLAT_WIN32
  1682. /* Entire boundary area is now invalid. */
  1683. bAnythingInvalid = TRUE;
  1684. btLeftMost = btLeftBoundary;
  1685. btRightMost = btRightBoundary;
  1686. btTopMost = btTopBoundary;
  1687. btBottomMost = btBottomBoundary;
  1688. #endif /* ODPLAT_WIN32 */
  1689. }
  1690. pchCurrentChar++;
  1691. break;
  1692. case '\a':
  1693. /* If bell */
  1694. if(!od_control.od_silent_mode)
  1695. {
  1696. #ifdef ODPLAT_DOS
  1697. ASM mov ah, 0x02
  1698. ASM mov dl, 7
  1699. ASM int 0x21
  1700. #endif /* ODPLAT_DOS */
  1701. #ifdef ODPLAT_WIN32
  1702. MessageBeep(0xffffffff);
  1703. #endif /* ODPLAT_WIN32 */
  1704. pchCurrentChar++;
  1705. }
  1706. break;
  1707. case '\t':
  1708. /* If tab character. */
  1709. btCurrentColumn = ((btCurrentColumn / 8) + 1) * 8;
  1710. if(btCurrentColumn > btRightBoundary - btLeftBoundary)
  1711. {
  1712. btCurrentColumn = 0;
  1713. /* If moving cursor down one line advances past end of window. */
  1714. if(++btCursorRow > btBottomBoundary - btTopBoundary)
  1715. {
  1716. /* Move cursor back to bottom line of window. */
  1717. btCursorRow = btBottomBoundary - btTopBoundary;
  1718. /* If scrolling is enabled. */
  1719. if(bScrollEnabled)
  1720. {
  1721. /* Execute the scroll primitive .*/
  1722. ODScrnScrollUpOneLine();
  1723. #ifdef ODPLAT_WIN32
  1724. /* Entire boundary area is now invalid. */
  1725. bAnythingInvalid = TRUE;
  1726. btLeftMost = btLeftBoundary;
  1727. btRightMost = btRightBoundary;
  1728. btTopMost = btTopBoundary;
  1729. btBottomMost = btBottomBoundary;
  1730. #endif /* ODPLAT_WIN32 */
  1731. }
  1732. }
  1733. }
  1734. /* Determine new buffer destination address. */
  1735. pDest = (BYTE ODFAR *) pScrnBuffer
  1736. + (((btTopBoundary + btCursorRow) * BUFFER_LINE_BYTES)
  1737. + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR);
  1738. break;
  1739. case '\b':
  1740. if(btCurrentColumn > 0)
  1741. {
  1742. --btCurrentColumn;
  1743. pDest-=2;
  1744. btLeftColumn++;
  1745. }
  1746. pchCurrentChar++;
  1747. break;
  1748. default:
  1749. *(pDest++) = *(pchCurrentChar++);
  1750. *(pDest++) = btAttribute;
  1751. #ifdef ODPLAT_WIN32
  1752. /* Expand area to invalidate, if needed. */
  1753. if(!bAnythingInvalid)
  1754. {
  1755. bAnythingInvalid = TRUE;
  1756. btLeftMost = btLeftBoundary + btCurrentColumn;
  1757. btRightMost = btLeftBoundary + btCurrentColumn;
  1758. btTopMost = btTopBoundary + btCursorRow;
  1759. btBottomMost = btTopBoundary + btCursorRow;
  1760. }
  1761. else
  1762. {
  1763. BYTE btColumn = btLeftBoundary + btCurrentColumn;
  1764. BYTE btRow = btTopBoundary + btCursorRow;
  1765. if(btColumn < btLeftMost) btLeftMost = btColumn;
  1766. if(btColumn > btRightMost) btRightMost = btColumn;
  1767. if(btRow < btTopMost) btTopMost = btRow;
  1768. if(btRow > btBottomMost) btBottomMost = btRow;
  1769. }
  1770. #endif /* ODPLAT_WIN32 */
  1771. if(btLeftColumn--)
  1772. {
  1773. ++btCurrentColumn;
  1774. }
  1775. else
  1776. {
  1777. btCurrentColumn = 0;
  1778. btLeftColumn = btRightBoundary - btLeftBoundary;
  1779. if(btCursorRow < btBottom)
  1780. {
  1781. ++btCursorRow;
  1782. }
  1783. else if(bScrollEnabled)
  1784. {
  1785. ODScrnScrollUpOneLine();
  1786. #ifdef ODPLAT_WIN32
  1787. /* Entire boundary area is now invalid. */
  1788. bAnythingInvalid = TRUE;
  1789. btLeftMost = btLeftBoundary;
  1790. btRightMost = btRightBoundary;
  1791. btTopMost = btTopBoundary;
  1792. btBottomMost = btBottomBoundary;
  1793. #endif /* ODPLAT_WIN32 */
  1794. }
  1795. pDest = (BYTE ODFAR *)pScrnBuffer
  1796. + ((btTopBoundary + btCursorRow)
  1797. * BUFFER_LINE_BYTES + btLeftBoundary * BYTES_PER_CHAR);
  1798. }
  1799. }
  1800. }
  1801. btCursorColumn = btCurrentColumn;
  1802. ODScrnUpdateCaretPos();
  1803. #ifdef ODPLAT_WIN32
  1804. if(bAnythingInvalid)
  1805. {
  1806. /* Force the updated area of the screen window to be redrawn. */
  1807. ODScrnInvalidate(btLeftMost, btTopMost, btRightMost,
  1808. btBottomMost);
  1809. }
  1810. #endif /* ODPLAT_WIN32 */
  1811. }
  1812. /* ----------------------------------------------------------------------------
  1813. * ODScrnCopyText()
  1814. *
  1815. * Copies the contents of the specified area on the screen to another location
  1816. * on the screen. The destination location must be such that the entire area
  1817. * specified as the source can be displayed without falling off the edge of the
  1818. * screen.
  1819. *
  1820. * Parameters: btLeft - Column number of the left edge of the area to
  1821. * copy from.
  1822. *
  1823. * btTop - Row number of the top edge of the area to copy
  1824. * from.
  1825. *
  1826. * btRight - Column number of the right edge of the area to
  1827. * copy from.
  1828. *
  1829. * btBottom - Row number of the bottom edge of the area to
  1830. * copy from.
  1831. *
  1832. * btDestColumn - Column number where the upper right corner of
  1833. * the area should be copied to.
  1834. *
  1835. * btDestRow - Row number where the upper right cornder of the
  1836. * area should be copied to.
  1837. *
  1838. * Return: TRUE on success, or FALSE on failure. May fail due to
  1839. * insufficient available memory.
  1840. */
  1841. BOOL ODScrnCopyText(BYTE btLeft, BYTE btTop, BYTE btRight, BYTE btBottom,
  1842. BYTE btDestColumn, BYTE btDestRow)
  1843. {
  1844. void *pScrnBuffer;
  1845. ASSERT(btLeft >= 0 && btTop >= 0);
  1846. ASSERT(btLeft <= btRightBoundary - btLeftBoundary);
  1847. ASSERT(btTop <= btBottomBoundary - btTopBoundary);
  1848. ASSERT(btRight >= 0 && btBottom >= 0);
  1849. ASSERT(btRight <= btRightBoundary - btLeftBoundary);
  1850. ASSERT(btBottom <= btBottomBoundary - btTopBoundary);
  1851. ASSERT(btDestColumn >= 0 && btDestRow >= 0);
  1852. ASSERT(btDestColumn <= btRightBoundary - btLeftBoundary);
  1853. ASSERT(btDestRow <= btBottomBoundary - btTopBoundary);
  1854. if( !(btLeft <= btRightBoundary - btLeftBoundary
  1855. && btTop <= btBottomBoundary - btTopBoundary)
  1856. || !(btRight <= btRightBoundary - btLeftBoundary
  1857. && btBottom <= btBottomBoundary - btTopBoundary)
  1858. || !(btDestColumn <= btRightBoundary - btLeftBoundary
  1859. && btDestRow <= btBottomBoundary - btTopBoundary))
  1860. {
  1861. return(FALSE);
  1862. }
  1863. if((pScrnBuffer = malloc((btRight - btLeft + 1) * (btBottom - btTop + 1)
  1864. * BYTES_PER_CHAR)) == NULL)
  1865. {
  1866. /* Insufficient memory, return with failure. */
  1867. return (FALSE);
  1868. }
  1869. ODScrnGetText(btLeft, btTop, btRight, btBottom, pScrnBuffer);
  1870. ODScrnPutText(btDestColumn, btDestRow,
  1871. (BYTE)(btRight + (btDestColumn - btLeft)),
  1872. (BYTE)(btBottom + (btDestRow - btTop)), pScrnBuffer);
  1873. free(pScrnBuffer);
  1874. return(TRUE);
  1875. }
  1876. /* ----------------------------------------------------------------------------
  1877. * ODScrnClearToEndOfLine()
  1878. *
  1879. * Clears the contents of the current line, from the current cursor location
  1880. * to the end of the line.
  1881. *
  1882. * Parameters: none
  1883. *
  1884. * Return: void
  1885. */
  1886. void ODScrnClearToEndOfLine(void)
  1887. {
  1888. unsigned char btCharsToDelete = btRightBoundary
  1889. - (btLeftBoundary + btCursorColumn);
  1890. BYTE ODFAR *pDest = (BYTE ODFAR *) pScrnBuffer
  1891. + (((btTopBoundary + btCursorRow) * BUFFER_LINE_BYTES)
  1892. + (btLeftBoundary + btCursorColumn) * BYTES_PER_CHAR);
  1893. BYTE btAttribute = btCurrentAttribute;
  1894. while(btCharsToDelete--)
  1895. {
  1896. *(pDest++) = ' ';
  1897. *(pDest++) = btAttribute;
  1898. }
  1899. #ifdef ODPLAT_WIN32
  1900. /* Force the updated area of the screen window to be redrawn. */
  1901. ODScrnInvalidate((BYTE)(btLeftBoundary + btCursorColumn),
  1902. (BYTE)(btTopBoundary + btCursorRow), btRightBoundary,
  1903. (BYTE)(btTopBoundary + btCursorRow));
  1904. #endif /* ODPLAT_WIN32 */
  1905. }
  1906. /* ----------------------------------------------------------------------------
  1907. * ODScrnCreateWindow()
  1908. *
  1909. * Creates a text-based window on the local terminal.
  1910. *
  1911. * Parameters: btLeft - Column numebr of the left of the window.
  1912. *
  1913. * btTop - Row number of the top of the window.
  1914. *
  1915. * btRight - Column number of the right of the window.
  1916. *
  1917. * btBottom - Row number of the bottom of the window.
  1918. *
  1919. * btAttribute - Display attribute for the window boarder and
  1920. * the area inside the window.
  1921. *
  1922. * pszTitle - Pointer to a string containing the title to
  1923. * display, or "" for none.
  1924. *
  1925. * btTitleAttribute - Display attribute for the title text.
  1926. *
  1927. * Return: void
  1928. */
  1929. #ifdef OD_TEXTMODE
  1930. void *ODScrnCreateWindow(BYTE btLeft, BYTE btTop, BYTE btRight,
  1931. BYTE btBottom, BYTE btAttribute, char *pszTitle, BYTE btTitleAttribute)
  1932. {
  1933. void *pUnder;
  1934. INT nBetween;
  1935. INT nCount;
  1936. INT nFirst;
  1937. char *pszString;
  1938. int nTitleWidth;
  1939. ASSERT(pszTitle != NULL);
  1940. /* Alocate space to store screen contents "under" window. */
  1941. if((pUnder = malloc((btRight - btLeft + 1) * (btBottom - btTop + 1)
  1942. * BYTES_PER_CHAR + 4 * sizeof(BYTE))) == NULL)
  1943. {
  1944. return(NULL);
  1945. }
  1946. /* Store the window's position in the buffer. */
  1947. ((BYTE *)pUnder)[0] = btLeft;
  1948. ((BYTE *)pUnder)[1] = btTop;
  1949. ((BYTE *)pUnder)[2] = btRight;
  1950. ((BYTE *)pUnder)[3] = btBottom;
  1951. /* Retrieve screen contents in window area. */
  1952. ODScrnGetText(btLeft, btTop, btRight, btBottom, ((BYTE *)pUnder) + 4);
  1953. /* Determine area between left & right of window, distance of line before */
  1954. /* title, and distance of line after title. */
  1955. if(strlen(pszTitle) == 0)
  1956. {
  1957. nTitleWidth = 0;
  1958. }
  1959. else
  1960. {
  1961. nTitleWidth = strlen(pszTitle) + 2;
  1962. }
  1963. nCount = (nBetween = btRight - btLeft - 1) - nTitleWidth;
  1964. nCount -= (nFirst = nCount / 2);
  1965. /* Prepare to begin drawing window at upper left corner */
  1966. ODScrnSetCursorPos(btLeft, btTop);
  1967. ODScrnSetAttribute(btAttribute);
  1968. /* Draw first line of window */
  1969. ODScrnDisplayChar((unsigned char)214);
  1970. while(nFirst--) ODScrnDisplayChar((unsigned char)196);
  1971. if(strlen(pszTitle) != 0)
  1972. {
  1973. ODScrnSetAttribute(btTitleAttribute);
  1974. ODScrnDisplayChar(' ');
  1975. ODScrnDisplayString(pszTitle);
  1976. ODScrnDisplayChar(' ');
  1977. ODScrnSetAttribute(btAttribute);
  1978. }
  1979. while(nCount--) ODScrnDisplayChar((unsigned char)196);
  1980. ODScrnDisplayChar((unsigned char)183);
  1981. /* Build string for working lines */
  1982. pszString = szBuffer;
  1983. *pszString++ = (unsigned char)186;
  1984. nCount = nBetween;
  1985. while(nCount--) *pszString++ = ' ';
  1986. *pszString++ = (unsigned char)186;
  1987. *pszString++ = '\0';
  1988. /* Draw working lines of window */
  1989. for(nCount = btTop + 1; nCount < btBottom; ++nCount)
  1990. {
  1991. ODScrnSetCursorPos(btLeft, (BYTE)nCount);
  1992. ODScrnDisplayString(szBuffer);
  1993. }
  1994. /* Draw last line of window */
  1995. ODScrnSetCursorPos(btLeft, btBottom);
  1996. ODScrnDisplayChar((unsigned char)211);
  1997. while(nBetween--) ODScrnDisplayChar((unsigned char)196);
  1998. ODScrnDisplayChar((unsigned char)189);
  1999. /* return pointer to buffer */
  2000. return(pUnder);
  2001. }
  2002. #endif /* OD_TEXTMODE */
  2003. /* ----------------------------------------------------------------------------
  2004. * ODScrnDestroyWindow()
  2005. *
  2006. * Removes a text-based window that was created by ODScrnCreateWindow().
  2007. *
  2008. * Parameters: pWindow - Pointer to the buffer returned by the corresponding
  2009. * call to ODScrnCreateWindow().
  2010. *
  2011. * Return: void
  2012. */
  2013. #ifdef OD_TEXTMODE
  2014. void ODScrnDestroyWindow(void *pWindow)
  2015. {
  2016. BYTE btLeft;
  2017. BYTE btTop;
  2018. BYTE btRight;
  2019. BYTE btBottom;
  2020. BYTE *pabtWindow = (BYTE *)pWindow;
  2021. ASSERT(pWindow != NULL);
  2022. /* Determine the location of the window. */
  2023. btLeft = pabtWindow[0];
  2024. btTop = pabtWindow[1];
  2025. btRight = pabtWindow[2];
  2026. btBottom = pabtWindow[3];
  2027. /* Restore original screen contents under the window. */
  2028. ODScrnPutText(btLeft, btTop, btRight, btBottom, ((BYTE *)pWindow) + 4);
  2029. /* Deallocate window buffer. */
  2030. free(pWindow);
  2031. }
  2032. #endif /* OD_TEXTMODE */
  2033. /* ----------------------------------------------------------------------------
  2034. * ODScrnLocalInput()
  2035. *
  2036. * Inputs a string, only displaying input on local screen.
  2037. *
  2038. * Parameters: btLeft - Column number of the left end of the input
  2039. * field.
  2040. *
  2041. * btRow - Row number where the input field appears.
  2042. *
  2043. * pszString - Location where user's input should be stored. Must
  2044. * be initialized.
  2045. *
  2046. * nMaxChars - The maximum number of characters that may be
  2047. * accepted for input into the string.
  2048. *
  2049. * Return: void
  2050. */
  2051. #ifdef OD_TEXTMODE
  2052. void ODScrnLocalInput(BYTE btLeft, BYTE btRow, char *pszString,
  2053. BYTE btMaxChars)
  2054. {
  2055. BYTE btCount;
  2056. BYTE btCurrentPos;
  2057. BOOL bAnyKeysPressed = FALSE;
  2058. tODInputEvent InputEvent;
  2059. /* Draw initial input field. */
  2060. ODScrnSetCursorPos(btLeft, btRow);
  2061. ODScrnDisplayString(pszString);
  2062. for(btCount = strlen(pszString); btCount <= btMaxChars; ++btCount)
  2063. {
  2064. ODScrnDisplayChar(177);
  2065. }
  2066. /* Start with the cursor at the end of the input field. */
  2067. btCurrentPos = strlen(pszString);
  2068. /* Loop until the user presses enter. */
  2069. for(;;)
  2070. {
  2071. /* Position the cursor at the appropriate location. */
  2072. ODScrnSetCursorPos((BYTE)(btLeft + btCurrentPos), btRow);
  2073. /* Obtain the next input event. */
  2074. ODInQueueGetNextEvent(hODInputQueue, &InputEvent, OD_NO_TIMEOUT);
  2075. switch(InputEvent.chKeyPress)
  2076. {
  2077. case '\b':
  2078. /* If user presses [Backspace], then move back if we are not at */
  2079. /* the left of the input field. */
  2080. if(btCurrentPos > 0)
  2081. {
  2082. /* Backspace, removing last character from string. */
  2083. btCurrentPos--;
  2084. ODScrnSetCursorPos((BYTE)(btLeft + btCurrentPos), btRow);
  2085. ODScrnDisplayChar(177);
  2086. pszString[btCurrentPos] = '\0';
  2087. }
  2088. break;
  2089. case '\n':
  2090. case '\r':
  2091. /* If user presses [Enter], then exit from the function. */
  2092. return;
  2093. case '\0':
  2094. /* In the case of a multi-character sequence, skip the next */
  2095. /* character from the input queue. */
  2096. ODInQueueGetNextEvent(hODInputQueue, &InputEvent, OD_NO_TIMEOUT);
  2097. break;
  2098. default:
  2099. /* If this is a valid string character for the string. */
  2100. if(InputEvent.chKeyPress >= ' ')
  2101. {
  2102. /* If no keys have been pressed yet, then erase the entire */
  2103. /* string first. */
  2104. if(!bAnyKeysPressed)
  2105. {
  2106. btCurrentPos = 0;
  2107. ODScrnSetCursorPos(btLeft, btRow);
  2108. for(btCount = 0; btCount <= btMaxChars; ++btCount)
  2109. {
  2110. ODScrnDisplayChar(177);
  2111. }
  2112. ODScrnSetCursorPos(btLeft, btRow);
  2113. }
  2114. /* If we are not at the end of the string, then add the */
  2115. /* character to the string. */
  2116. if(btCurrentPos < btMaxChars)
  2117. {
  2118. /* Display the new character. */
  2119. ODScrnDisplayChar(InputEvent.chKeyPress);
  2120. /* Add the character to the string. */
  2121. pszString[btCurrentPos] = InputEvent.chKeyPress;
  2122. /* Update the current cursor position. */
  2123. ++btCurrentPos;
  2124. /* Terminate the string. */
  2125. pszString[btCurrentPos] = '\0';
  2126. }
  2127. }
  2128. }
  2129. /* Note that a key has now been pressed. */
  2130. bAnyKeysPressed = TRUE;
  2131. }
  2132. }
  2133. #endif /* OD_TEXTMODE */
  2134. /* ----------------------------------------------------------------------------
  2135. * ODScrnShowMessage()
  2136. *
  2137. * Displays a message window with the specified message text. Unlike the
  2138. * Windows MessageBox() function, this message box is removed by the caller
  2139. * of the function rather than the user.
  2140. *
  2141. * Parameters: pszText - Pointer to message text to be displayed. This string
  2142. * must continue to exist until after the
  2143. * ODScrnRemoveMessage() function is called.
  2144. *
  2145. * nFlags - Currently unused, must be 0.
  2146. *
  2147. * Return: A pointer which must be passed to ODScrnRemoveMessage() in
  2148. * order to remove this message from the screen. A return value
  2149. * of NULL does not necessarily indicate window creation failure,
  2150. * and should still be passed to a corresponding call to
  2151. * ODScrnRemoveMessage().
  2152. */
  2153. void *ODScrnShowMessage(char *pszText, int nFlags)
  2154. {
  2155. ASSERT(pszText != NULL);
  2156. ASSERT(nFlags == 0);
  2157. /* In silent mode, this function does nothing. */
  2158. if(od_control.od_silent_mode) return(NULL);
  2159. #ifdef ODPLAT_WIN32
  2160. /* Place a message in the frame window's message queue, asking it to */
  2161. /* create the message window. */
  2162. PostMessage(GetParent(hwndScreenWindow), WM_SHOW_MESSAGE, (WPARAM)nFlags,
  2163. (LPARAM)pszText);
  2164. return(NULL);
  2165. #else /* !ODPLAT_WIN32 */
  2166. {
  2167. int nWindowWidth;
  2168. int nLeftColumn;
  2169. char szMessage[74];
  2170. void *pWindow;
  2171. UNUSED(nFlags);
  2172. ODStringCopy(szMessage, pszText, sizeof(szMessage));
  2173. ODStoreTextInfo();
  2174. nWindowWidth = strlen(szMessage) + 4;
  2175. nLeftColumn = 40 - (nWindowWidth / 2);
  2176. if((pWindow = ODScrnCreateWindow((BYTE)nLeftColumn, 10,
  2177. (BYTE)(nLeftColumn + (nWindowWidth - 1)), 14,
  2178. od_control.od_local_win_col, "", od_control.od_local_win_col))
  2179. == NULL)
  2180. {
  2181. return(NULL);
  2182. }
  2183. ODScrnSetCursorPos((BYTE)(42 - (nWindowWidth / 2)), 12);
  2184. ODScrnDisplayString(szMessage);
  2185. ODRestoreTextInfo();
  2186. ODScrnEnableCaret(FALSE);
  2187. return(pWindow);
  2188. }
  2189. #endif /* !ODPLAT_WIN32 */
  2190. }
  2191. /* ----------------------------------------------------------------------------
  2192. * ODScrnRemoveMessage()
  2193. *
  2194. * Removes a message that was shown by a previous call to ODScrnShowMessage().
  2195. *
  2196. * Parameters: pMessageInfo - Pointer to the buffer returned by the
  2197. * corresponding call to ODScrnShowMessage().
  2198. *
  2199. * Return: void
  2200. */
  2201. void ODScrnRemoveMessage(void *pMessageInfo)
  2202. {
  2203. /* In silent mode, this function does nothing. */
  2204. if(od_control.od_silent_mode) return;
  2205. #ifdef ODPLAT_WIN32
  2206. /* Place a message in the frame window's message queue, asking it to */
  2207. /* remove the message window. */
  2208. SendMessage(GetParent(hwndScreenWindow), WM_REMOVE_MESSAGE, 0, 0L);
  2209. #else /* !ODPLAT_WIN32 */
  2210. /* If pMessageInfo is NULL, then we do nothing. */
  2211. if(pMessageInfo == NULL) return;
  2212. ODStoreTextInfo();
  2213. ODScrnDestroyWindow(pMessageInfo);
  2214. ODRestoreTextInfo();
  2215. ODScrnEnableCaret(TRUE);
  2216. #endif /* !ODPLAT_WIN32 */
  2217. }