xref: /aosp_15_r20/external/coreboot/payloads/libpayload/curses/PDCurses/win32/pdcscrn.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* Public Domain Curses */
2 
3 #include "pdcwin.h"
4 
5 RCSID("$Id: pdcscrn.c,v 1.92 2008/07/20 20:12:04 wmcbrine Exp $")
6 
7 #ifdef CHTYPE_LONG
8 # define PDC_OFFSET 32
9 #else
10 # define PDC_OFFSET  8
11 #endif
12 
13 /* COLOR_PAIR to attribute encoding table. */
14 
15 unsigned char *pdc_atrtab = (unsigned char *)NULL;
16 
17 HANDLE pdc_con_out = INVALID_HANDLE_VALUE;
18 HANDLE pdc_con_in = INVALID_HANDLE_VALUE;
19 
20 DWORD pdc_quick_edit;
21 
22 static short curstoreal[16], realtocurs[16] =
23 {
24     COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED,
25     COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8,
26     COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8,
27     COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8
28 };
29 
30 enum { PDC_RESTORE_NONE, PDC_RESTORE_BUFFER, PDC_RESTORE_WINDOW };
31 
32 /* Struct for storing console registry keys, and for use with the
33    undocumented WM_SETCONSOLEINFO message. Originally by James Brown,
34    www.catch22.net. */
35 
36 static struct
37 {
38     ULONG    Length;
39     COORD    ScreenBufferSize;
40     COORD    WindowSize;
41     ULONG    WindowPosX;
42     ULONG    WindowPosY;
43 
44     COORD    FontSize;
45     ULONG    FontFamily;
46     ULONG    FontWeight;
47     WCHAR    FaceName[32];
48 
49     ULONG    CursorSize;
50     ULONG    FullScreen;
51     ULONG    QuickEdit;
52     ULONG    AutoPosition;
53     ULONG    InsertMode;
54 
55     USHORT   ScreenColors;
56     USHORT   PopupColors;
57     ULONG    HistoryNoDup;
58     ULONG    HistoryBufferSize;
59     ULONG    NumberOfHistoryBuffers;
60 
61     COLORREF ColorTable[16];
62 
63     ULONG    CodePage;
64     HWND     Hwnd;
65 
66     WCHAR    ConsoleTitle[0x100];
67 } console_info;
68 
69 static CONSOLE_SCREEN_BUFFER_INFO orig_scr;
70 
71 static CHAR_INFO *ci_save = NULL;
72 static DWORD old_console_mode = 0;
73 
74 static bool is_nt;
75 
_find_console_handle(void)76 static HWND _find_console_handle(void)
77 {
78     TCHAR orgtitle[1024], temptitle[1024];
79     HWND wnd;
80 
81     GetConsoleTitle(orgtitle, 1024);
82 
83     wsprintf(temptitle, TEXT("%d/%d"), GetTickCount(), GetCurrentProcessId());
84     SetConsoleTitle(temptitle);
85 
86     Sleep(40);
87 
88     wnd = FindWindow(NULL, temptitle);
89 
90     SetConsoleTitle(orgtitle);
91 
92     return wnd;
93 }
94 
95 /* Undocumented console message */
96 
97 #define WM_SETCONSOLEINFO (WM_USER + 201)
98 
99 /* Wrapper around WM_SETCONSOLEINFO. We need to create the necessary
100    section (file-mapping) object in the context of the process which
101    owns the console, before posting the message. Originally by JB. */
102 
_set_console_info(void)103 static void _set_console_info(void)
104 {
105     CONSOLE_SCREEN_BUFFER_INFO csbi;
106     CONSOLE_CURSOR_INFO cci;
107     DWORD dwConsoleOwnerPid;
108     HANDLE hProcess;
109     HANDLE hSection, hDupSection;
110     PVOID ptrView;
111 
112     /* Each-time initialization for console_info */
113 
114     GetConsoleCursorInfo(pdc_con_out, &cci);
115     console_info.CursorSize = cci.dwSize;
116 
117     GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
118     console_info.ScreenBufferSize = csbi.dwSize;
119 
120     console_info.WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
121     console_info.WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
122 
123     console_info.WindowPosX = csbi.srWindow.Left;
124     console_info.WindowPosY = csbi.srWindow.Top;
125 
126     /* Open the process which "owns" the console */
127 
128     GetWindowThreadProcessId(console_info.Hwnd, &dwConsoleOwnerPid);
129 
130     hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
131 
132     /* Create a SECTION object backed by page-file, then map a view of
133        this section into the owner process so we can write the contents
134        of the CONSOLE_INFO buffer into it */
135 
136     hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE,
137                                  0, sizeof(console_info), 0);
138 
139     /* Copy our console structure into the section-object */
140 
141     ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE|FILE_MAP_READ,
142                             0, 0, sizeof(console_info));
143 
144     memcpy(ptrView, &console_info, sizeof(console_info));
145 
146     UnmapViewOfFile(ptrView);
147 
148     /* Map the memory into owner process */
149 
150     DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection,
151                     0, FALSE, DUPLICATE_SAME_ACCESS);
152 
153     /* Send console window the "update" message */
154 
155     SendMessage(console_info.Hwnd, WM_SETCONSOLEINFO, (WPARAM)hDupSection, 0);
156 
157     CloseHandle(hSection);
158     CloseHandle(hProcess);
159 }
160 
161 /* One-time initialization for console_info -- color table and font info
162    from the registry; other values from functions. */
163 
_init_console_info(void)164 static void _init_console_info(void)
165 {
166     DWORD scrnmode, len;
167     HKEY reghnd;
168     int i;
169 
170     console_info.Hwnd = _find_console_handle();
171     console_info.Length = sizeof(console_info);
172 
173     GetConsoleMode(pdc_con_in, &scrnmode);
174     console_info.QuickEdit = !!(scrnmode & 0x0040);
175     console_info.InsertMode = !!(scrnmode & 0x0020);
176 
177     console_info.FullScreen = FALSE;
178     console_info.AutoPosition = 0x10000;
179     console_info.ScreenColors = SP->orig_back << 4 | SP->orig_fore;
180     console_info.PopupColors = 0xf5;
181 
182     console_info.HistoryNoDup = FALSE;
183     console_info.HistoryBufferSize = 50;
184     console_info.NumberOfHistoryBuffers = 4;
185 
186     console_info.CodePage = GetConsoleOutputCP();
187 
188     RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Console"), 0,
189                  KEY_QUERY_VALUE, &reghnd);
190 
191     len = sizeof(DWORD);
192 
193     /* Default color table */
194 
195     for (i = 0; i < 16; i++)
196     {
197         char tname[13];
198 
199         sprintf(tname, "ColorTable%02d", i);
200         RegQueryValueExA(reghnd, tname, NULL, NULL,
201                          (LPBYTE)(&(console_info.ColorTable[i])), &len);
202     }
203 
204     /* Font info */
205 
206     RegQueryValueEx(reghnd, TEXT("FontSize"), NULL, NULL,
207                     (LPBYTE)(&console_info.FontSize), &len);
208     RegQueryValueEx(reghnd, TEXT("FontFamily"), NULL, NULL,
209                     (LPBYTE)(&console_info.FontFamily), &len);
210     RegQueryValueEx(reghnd, TEXT("FontWeight"), NULL, NULL,
211                     (LPBYTE)(&console_info.FontWeight), &len);
212 
213     len = sizeof(WCHAR) * 32;
214     RegQueryValueExW(reghnd, L"FaceName", NULL, NULL,
215                      (LPBYTE)(console_info.FaceName), &len);
216 
217     RegCloseKey(reghnd);
218 }
219 
220 /* close the physical screen -- may restore the screen to its state
221    before PDC_scr_open(); miscellaneous cleanup */
222 
PDC_scr_close(void)223 void PDC_scr_close(void)
224 {
225     COORD origin;
226     SMALL_RECT rect;
227 
228     PDC_LOG(("PDC_scr_close() - called\n"));
229 
230     PDC_reset_shell_mode();
231 
232     if (SP->_restore != PDC_RESTORE_NONE)
233     {
234         if (SP->_restore == PDC_RESTORE_WINDOW)
235         {
236             rect.Top = orig_scr.srWindow.Top;
237             rect.Left = orig_scr.srWindow.Left;
238             rect.Bottom = orig_scr.srWindow.Bottom;
239             rect.Right = orig_scr.srWindow.Right;
240         }
241         else    /* PDC_RESTORE_BUFFER */
242         {
243             rect.Top = rect.Left = 0;
244             rect.Bottom = orig_scr.dwSize.Y - 1;
245             rect.Right = orig_scr.dwSize.X - 1;
246         }
247 
248         origin.X = origin.Y = 0;
249 
250         if (!WriteConsoleOutput(pdc_con_out, ci_save, orig_scr.dwSize,
251                                 origin, &rect))
252             return;
253     }
254 
255     if (SP->visibility != 1)
256         curs_set(1);
257 
258     /* Position cursor to the bottom left of the screen. */
259 
260     PDC_gotoyx(PDC_get_buffer_rows() - 2, 0);
261 }
262 
PDC_scr_free(void)263 void PDC_scr_free(void)
264 {
265     if (SP)
266         free(SP);
267     if (pdc_atrtab)
268         free(pdc_atrtab);
269 
270     pdc_atrtab = (unsigned char *)NULL;
271 }
272 
273 /* open the physical screen -- allocate SP, miscellaneous intialization,
274    and may save the existing screen for later restoration */
275 
PDC_scr_open(int argc,char ** argv)276 int PDC_scr_open(int argc, char **argv)
277 {
278     COORD bufsize, origin;
279     SMALL_RECT rect;
280     const char *str;
281     CONSOLE_SCREEN_BUFFER_INFO csbi;
282     int i;
283 
284     PDC_LOG(("PDC_scr_open() - called\n"));
285 
286     SP = calloc(1, sizeof(SCREEN));
287     pdc_atrtab = calloc(PDC_COLOR_PAIRS * PDC_OFFSET, 1);
288 
289     if (!SP || !pdc_atrtab)
290         return ERR;
291 
292     for (i = 0; i < 16; i++)
293         curstoreal[realtocurs[i]] = i;
294 
295     pdc_con_out = GetStdHandle(STD_OUTPUT_HANDLE);
296     pdc_con_in = GetStdHandle(STD_INPUT_HANDLE);
297 
298     if (GetFileType(pdc_con_in) != FILE_TYPE_CHAR)
299     {
300         fprintf(stderr, "\nRedirection is not supported.\n");
301         exit(1);
302     }
303 
304     is_nt = !(GetVersion() & 0x80000000);
305 
306     GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
307     GetConsoleScreenBufferInfo(pdc_con_out, &orig_scr);
308     GetConsoleMode(pdc_con_in, &old_console_mode);
309 
310     /* preserve QuickEdit Mode setting for use in PDC_mouse_set() when
311        the mouse is not enabled -- other console input settings are
312        cleared */
313 
314     pdc_quick_edit = old_console_mode & 0x0040;
315 
316     SP->lines = (str = getenv("LINES")) ? atoi(str) : PDC_get_rows();
317     SP->cols = (str = getenv("COLS")) ? atoi(str) : PDC_get_columns();
318 
319     SP->mouse_wait = PDC_CLICK_PERIOD;
320     SP->audible = TRUE;
321 
322     if (SP->lines < 2 || SP->lines > csbi.dwMaximumWindowSize.Y)
323     {
324         fprintf(stderr, "LINES value must be >= 2 and <= %d: got %d\n",
325                 csbi.dwMaximumWindowSize.Y, SP->lines);
326 
327         return ERR;
328     }
329 
330     if (SP->cols < 2 || SP->cols > csbi.dwMaximumWindowSize.X)
331     {
332         fprintf(stderr, "COLS value must be >= 2 and <= %d: got %d\n",
333                 csbi.dwMaximumWindowSize.X, SP->cols);
334 
335         return ERR;
336     }
337 
338     SP->orig_fore = csbi.wAttributes & 0x0f;
339     SP->orig_back = (csbi.wAttributes & 0xf0) >> 4;
340 
341     SP->orig_attr = TRUE;
342 
343     SP->_restore = PDC_RESTORE_NONE;
344 
345     if (getenv("PDC_RESTORE_SCREEN"))
346     {
347         /* Attempt to save the complete console buffer */
348 
349         ci_save = malloc(orig_scr.dwSize.X * orig_scr.dwSize.Y *
350                          sizeof(CHAR_INFO));
351 
352         if (!ci_save)
353         {
354             PDC_LOG(("PDC_scr_open() - malloc failure (1)\n"));
355 
356             return ERR;
357         }
358 
359         bufsize.X = orig_scr.dwSize.X;
360         bufsize.Y = orig_scr.dwSize.Y;
361 
362         origin.X = origin.Y = 0;
363 
364         rect.Top = rect.Left = 0;
365         rect.Bottom = orig_scr.dwSize.Y  - 1;
366         rect.Right = orig_scr.dwSize.X - 1;
367 
368         if (!ReadConsoleOutput(pdc_con_out, ci_save, bufsize, origin, &rect))
369         {
370             /* We can't save the complete buffer, so try and save just
371                the displayed window */
372 
373             free(ci_save);
374             ci_save = NULL;
375 
376             bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
377             bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
378 
379             ci_save = malloc(bufsize.X * bufsize.Y * sizeof(CHAR_INFO));
380 
381             if (!ci_save)
382             {
383                 PDC_LOG(("PDC_scr_open() - malloc failure (2)\n"));
384 
385                 return ERR;
386             }
387 
388             origin.X = origin.Y = 0;
389 
390             rect.Top = orig_scr.srWindow.Top;
391             rect.Left = orig_scr.srWindow.Left;
392             rect.Bottom = orig_scr.srWindow.Bottom;
393             rect.Right = orig_scr.srWindow.Right;
394 
395             if (!ReadConsoleOutput(pdc_con_out, ci_save, bufsize,
396                                    origin, &rect))
397             {
398 #ifdef PDCDEBUG
399                 CHAR LastError[256];
400 
401                 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
402                               GetLastError(), MAKELANGID(LANG_NEUTRAL,
403                               SUBLANG_DEFAULT), LastError, 256, NULL);
404 
405                 PDC_LOG(("PDC_scr_open() - %s\n", LastError));
406 #endif
407                 free(ci_save);
408                 ci_save = NULL;
409 
410                 return ERR;
411             }
412 
413             SP->_restore = PDC_RESTORE_WINDOW;
414         }
415         else
416             SP->_restore = PDC_RESTORE_BUFFER;
417     }
418 
419     SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL);
420 
421     PDC_reset_prog_mode();
422 
423     SP->mono = FALSE;
424 
425     return OK;
426 }
427 
428  /* Calls SetConsoleWindowInfo with the given parameters, but fits them
429     if a scoll bar shrinks the maximum possible value. The rectangle
430     must at least fit in a half-sized window. */
431 
_fit_console_window(HANDLE con_out,CONST SMALL_RECT * rect)432 static BOOL _fit_console_window(HANDLE con_out, CONST SMALL_RECT *rect)
433 {
434     SMALL_RECT run;
435     SHORT mx, my;
436 
437     if (SetConsoleWindowInfo(con_out, TRUE, rect))
438         return TRUE;
439 
440     run = *rect;
441     run.Right /= 2;
442     run.Bottom /= 2;
443 
444     mx = run.Right;
445     my = run.Bottom;
446 
447     if (!SetConsoleWindowInfo(con_out, TRUE, &run))
448         return FALSE;
449 
450     for (run.Right = rect->Right; run.Right >= mx; run.Right--)
451         if (SetConsoleWindowInfo(con_out, TRUE, &run))
452             break;
453 
454     if (run.Right < mx)
455         return FALSE;
456 
457     for (run.Bottom = rect->Bottom; run.Bottom >= my; run.Bottom--)
458         if (SetConsoleWindowInfo(con_out, TRUE, &run))
459             return TRUE;
460 
461     return FALSE;
462 }
463 
464 /* the core of resize_term() */
465 
PDC_resize_screen(int nlines,int ncols)466 int PDC_resize_screen(int nlines, int ncols)
467 {
468     SMALL_RECT rect;
469     COORD size, max;
470 
471     if (nlines < 2 || ncols < 2)
472         return ERR;
473 
474     max = GetLargestConsoleWindowSize(pdc_con_out);
475 
476     rect.Left = rect.Top = 0;
477     rect.Right = ncols - 1;
478 
479     if (rect.Right > max.X)
480         rect.Right = max.X;
481 
482     rect.Bottom = nlines - 1;
483 
484     if (rect.Bottom > max.Y)
485         rect.Bottom = max.Y;
486 
487     size.X = rect.Right + 1;
488     size.Y = rect.Bottom + 1;
489 
490     _fit_console_window(pdc_con_out, &rect);
491     SetConsoleScreenBufferSize(pdc_con_out, size);
492     _fit_console_window(pdc_con_out, &rect);
493     SetConsoleScreenBufferSize(pdc_con_out, size);
494     SetConsoleActiveScreenBuffer(pdc_con_out);
495 
496     return OK;
497 }
498 
PDC_reset_prog_mode(void)499 void PDC_reset_prog_mode(void)
500 {
501     PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
502 
503     if (is_nt)
504     {
505         COORD bufsize;
506         SMALL_RECT rect;
507 
508         bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
509         bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
510 
511         rect.Top = rect.Left = 0;
512         rect.Bottom = bufsize.Y - 1;
513         rect.Right = bufsize.X - 1;
514 
515         SetConsoleScreenBufferSize(pdc_con_out, bufsize);
516         SetConsoleWindowInfo(pdc_con_out, TRUE, &rect);
517         SetConsoleScreenBufferSize(pdc_con_out, bufsize);
518         SetConsoleActiveScreenBuffer(pdc_con_out);
519     }
520 
521     PDC_mouse_set();
522 }
523 
PDC_reset_shell_mode(void)524 void PDC_reset_shell_mode(void)
525 {
526     PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
527 
528     if (is_nt)
529     {
530         SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
531         SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
532         SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
533         SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
534         SetConsoleActiveScreenBuffer(pdc_con_out);
535     }
536 
537     SetConsoleMode(pdc_con_in, old_console_mode);
538 }
539 
PDC_restore_screen_mode(int i)540 void PDC_restore_screen_mode(int i)
541 {
542 }
543 
PDC_save_screen_mode(int i)544 void PDC_save_screen_mode(int i)
545 {
546 }
547 
PDC_init_pair(short pair,short fg,short bg)548 void PDC_init_pair(short pair, short fg, short bg)
549 {
550     unsigned char att, temp_bg;
551     chtype i;
552 
553     fg = curstoreal[fg];
554     bg = curstoreal[bg];
555 
556     for (i = 0; i < PDC_OFFSET; i++)
557     {
558         att = fg | (bg << 4);
559 
560         if (i & (A_REVERSE >> PDC_ATTR_SHIFT))
561             att = bg | (fg << 4);
562         if (i & (A_UNDERLINE >> PDC_ATTR_SHIFT))
563             att = 1;
564         if (i & (A_INVIS >> PDC_ATTR_SHIFT))
565         {
566             temp_bg = att >> 4;
567             att = temp_bg << 4 | temp_bg;
568         }
569         if (i & (A_BOLD >> PDC_ATTR_SHIFT))
570             att |= 8;
571         if (i & (A_BLINK >> PDC_ATTR_SHIFT))
572             att |= 128;
573 
574         pdc_atrtab[pair * PDC_OFFSET + i] = att;
575     }
576 }
577 
PDC_pair_content(short pair,short * fg,short * bg)578 int PDC_pair_content(short pair, short *fg, short *bg)
579 {
580     *fg = realtocurs[pdc_atrtab[pair * PDC_OFFSET] & 0x0F];
581     *bg = realtocurs[(pdc_atrtab[pair * PDC_OFFSET] & 0xF0) >> 4];
582 
583     return OK;
584 }
585 
PDC_can_change_color(void)586 bool PDC_can_change_color(void)
587 {
588     return is_nt;
589 }
590 
PDC_color_content(short color,short * red,short * green,short * blue)591 int PDC_color_content(short color, short *red, short *green, short *blue)
592 {
593     DWORD col;
594 
595     if (!console_info.Hwnd)
596         _init_console_info();
597 
598     col = console_info.ColorTable[curstoreal[color]];
599 
600     *red = DIVROUND(GetRValue(col) * 1000, 255);
601     *green = DIVROUND(GetGValue(col) * 1000, 255);
602     *blue = DIVROUND(GetBValue(col) * 1000, 255);
603 
604     return OK;
605 }
606 
PDC_init_color(short color,short red,short green,short blue)607 int PDC_init_color(short color, short red, short green, short blue)
608 {
609     if (!console_info.Hwnd)
610         _init_console_info();
611 
612     console_info.ColorTable[curstoreal[color]] =
613         RGB(DIVROUND(red * 255, 1000),
614             DIVROUND(green * 255, 1000),
615             DIVROUND(blue * 255, 1000));
616 
617     _set_console_info();
618 
619     return OK;
620 }
621