1 /****************************************************************************
2 * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Juergen Pfeifer *
32 ****************************************************************************/
34 #include <curses.priv.h>
36 MODULE_ID("$Id: win_driver.c,v 1.5 2010/01/16 22:42:30 tom Exp $")
38 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
40 #define AssertTCB() assert(TCB!=0 && TCB->magic==WINMAGIC)
41 #define SetSP() assert(TCB->csp!=0); sp = TCB->csp
43 #define GenMap(vKey,key) MAKELONG(key, vKey)
45 static const LONG keylist[] =
47 GenMap(VK_PRIOR, KEY_PPAGE),
48 GenMap(VK_NEXT, KEY_NPAGE),
49 GenMap(VK_END, KEY_END),
50 GenMap(VK_HOME, KEY_HOME),
51 GenMap(VK_LEFT, KEY_LEFT),
52 GenMap(VK_UP, KEY_UP),
53 GenMap(VK_RIGHT, KEY_RIGHT),
54 GenMap(VK_DOWN, KEY_DOWN),
55 GenMap(VK_DELETE, KEY_DC),
56 GenMap(VK_INSERT, KEY_IC)
58 #define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
60 #define MAPSIZE (FKEYS + N_INI)
63 typedef struct props {
64 CONSOLE_SCREEN_BUFFER_INFO SBI;
71 #define PropOf(TCB) ((Properties*)TCB->prop)
74 _nc_mingw_ioctl(int fd GCC_UNUSED,
75 long int request GCC_UNUSED,
76 struct termios *arg GCC_UNUSED)
80 fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
85 MapColor(bool fore, int color)
87 static const int _cmap[] =
88 {0, 4, 2, 6, 1, 5, 3, 7};
90 if (color < 0 || color > 7)
100 MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
109 if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
111 a = PropOf(TCB)->pairs[p];
112 res = (res & 0xff00) | a;
117 res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4)));
120 res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4))
121 | BACKGROUND_INTENSITY);
124 res |= FOREGROUND_INTENSITY;
127 res |= BACKGROUND_INTENSITY;
133 con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
144 if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
149 for (i = 0; i < n; i++) {
151 ci[i].Char.AsciiChar = ChCharOf(ch);
152 ci[i].Attributes = MapAttr(TCB,
153 PropOf(TCB)->SBI.wAttributes,
155 if (ChAttrOf(ch) & A_ALTCHARSET) {
157 ci[i].Char.AsciiChar =
158 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
167 rec.Left = (short) x;
169 rec.Right = (short) (x + n - 1);
170 rec.Bottom = rec.Top;
172 return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
175 #define MARK_NOCHANGE(win,row) \
176 win->_line[row].firstchar = _NOCHANGE; \
177 win->_line[row].lastchar = _NOCHANGE
180 drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
182 int y, nonempty, n, x0, x1, Width, Height;
188 Width = screen_columns(sp);
189 Height = screen_lines(sp);
190 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
192 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
196 for (x = 0; x < Width; x++)
199 for (y = 0; y < nonempty; y++) {
200 con_write(TCB, y, 0, empty, Width);
202 CurScreen(sp)->_line[y].text,
203 Width * sizeof(chtype));
205 CurScreen(sp)->_clear = FALSE;
206 NewScreen(sp)->_clear = FALSE;
207 touchwin(NewScreen(sp));
210 for (y = 0; y < nonempty; y++) {
211 x0 = NewScreen(sp)->_line[y].firstchar;
212 if (x0 != _NOCHANGE) {
213 x1 = NewScreen(sp)->_line[y].lastchar;
216 memcpy(CurScreen(sp)->_line[y].text + x0,
217 NewScreen(sp)->_line[y].text + x0,
222 ((chtype *) CurScreen(sp)->_line[y].text) + x0, n);
224 /* mark line changed successfully */
225 if (y <= NewScreen(sp)->_maxy) {
226 MARK_NOCHANGE(NewScreen(sp), y);
228 if (y <= CurScreen(sp)->_maxy) {
229 MARK_NOCHANGE(CurScreen(sp), y);
235 /* put everything back in sync */
236 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
237 MARK_NOCHANGE(NewScreen(sp), y);
239 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
240 MARK_NOCHANGE(CurScreen(sp), y);
243 if (!NewScreen(sp)->_leaveok) {
244 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
245 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
247 TCB->drv->hwcur(TCB, 0, 0, CurScreen(sp)->_cury, CurScreen(sp)->_curx);
249 SetConsoleActiveScreenBuffer(TCB->hdl);
254 drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
256 int *errret GCC_UNUSED)
260 T((T_CALLED("drv_CanHandle(%p)"), TCB));
265 TCB->magic = WINMAGIC;
266 if (*tname == 0 || *tname == 0 || strcmp(tname, "unknown") == 0) {
268 if ((TCB->term.type.Booleans) == 0) {
269 _nc_init_entry(&(TCB->term.type));
277 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
278 bool beepFlag GCC_UNUSED)
290 drv_print(TERMINAL_CONTROL_BLOCK * TCB,
291 char *data GCC_UNUSED,
303 drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
317 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
320 int (*outc) (SCREEN *, int) GCC_UNUSED)
324 if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
325 WORD a = MapColor(fore, color);
326 a = ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)) | a;
327 SetConsoleTextAttribute(TCB->hdl, a);
328 GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
333 drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
338 if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
339 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
340 SetConsoleTextAttribute(TCB->hdl, a);
341 GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
348 drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
360 drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
364 if (TCB == NULL || Lines == NULL || Cols == NULL || InvalidConsoleHandle(TCB->hdl))
367 *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
368 *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
373 drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
382 drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
390 if (TCB == 0 || buf == NULL)
394 iflag = buf->c_iflag;
395 lflag = buf->c_lflag;
397 GetConsoleMode(TCB->inp, &dwFlag);
400 dwFlag |= ENABLE_LINE_INPUT;
402 dwFlag &= ~ENABLE_LINE_INPUT;
405 dwFlag |= ENABLE_ECHO_INPUT;
407 dwFlag &= ~ENABLE_ECHO_INPUT;
410 dwFlag |= ENABLE_PROCESSED_INPUT;
412 dwFlag &= ~ENABLE_PROCESSED_INPUT;
414 /* we disable that for now to focus on keyboard. */
415 dwFlag &= ~ENABLE_MOUSE_INPUT;
417 buf->c_iflag = iflag;
418 buf->c_lflag = lflag;
419 SetConsoleMode(TCB->inp, dwFlag);
420 TCB->term.Nttyb = *buf;
422 iflag = TCB->term.Nttyb.c_iflag;
423 lflag = TCB->term.Nttyb.c_lflag;
424 GetConsoleMode(TCB->inp, &dwFlag);
426 if (dwFlag & ENABLE_LINE_INPUT)
431 if (dwFlag & ENABLE_ECHO_INPUT)
436 if (dwFlag & ENABLE_PROCESSED_INPUT)
441 TCB->term.Nttyb.c_iflag = iflag;
442 TCB->term.Nttyb.c_lflag = lflag;
444 *buf = TCB->term.Nttyb;
450 drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
453 TERMINAL *_term = (TERMINAL *) TCB;
459 PropOf(TCB)->progMode = progFlag;
460 SetConsoleActiveScreenBuffer(progFlag ? TCB->hdl : TCB->out);
462 if (progFlag) /* prog mode */ {
464 if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
465 _term->Nttyb.c_oflag &= ~OFLAGS_TABS;
469 /* reset_prog_mode */
470 if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
473 _nc_keypad(sp, TRUE);
474 NC_BUFFERED(sp, TRUE);
479 } else { /* shell mode */
482 if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
486 /* reset_shell_mode */
488 _nc_keypad(sp, FALSE);
489 NCURSES_SP_NAME(_nc_flush) (sp);
490 NC_BUFFERED(sp, FALSE);
492 code = drv_sgmode(TCB, TRUE, &(_term->Ottyb));
500 drv_screen_init(SCREEN *sp GCC_UNUSED)
505 drv_wrap(SCREEN *sp GCC_UNUSED)
510 rkeycompare(const void *el1, const void *el2)
512 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
513 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
515 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
519 keycompare(const void *el1, const void *el2)
521 WORD key1 = HIWORD((*((const LONG *) el1)));
522 WORD key2 = HIWORD((*((const LONG *) el2)));
524 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
528 MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
532 LONG key = GenMap(vKey, 0);
539 (size_t) (N_INI + FKEYS),
543 key = *((LONG *) res);
545 code = (int) (nKey & 0x7fff);
553 drv_release(TERMINAL_CONTROL_BLOCK * TCB)
555 T((T_CALLED("drv_release(%p)"), TCB));
565 drv_init(TERMINAL_CONTROL_BLOCK * TCB)
567 T((T_CALLED("drv_init(%p)"), TCB));
572 BOOL b = AllocConsole();
577 b = AttachConsole(ATTACH_PARENT_PROCESS);
579 TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
580 TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
585 TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
588 CONSOLE_TEXTMODE_BUFFER,
591 if (!InvalidConsoleHandle(TCB->hdl)) {
592 TCB->prop = typeCalloc(Properties, 1);
593 GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
596 TCB->info.initcolor = TRUE;
597 TCB->info.canchange = FALSE;
598 TCB->info.hascolor = TRUE;
599 TCB->info.caninit = TRUE;
601 TCB->info.maxpairs = NUMPAIRS;
602 TCB->info.maxcolors = 8;
603 TCB->info.numlabels = 0;
604 TCB->info.labelwidth = 0;
605 TCB->info.labelheight = 0;
606 TCB->info.nocolorvideo = 1;
607 TCB->info.tabsize = 8;
609 TCB->info.defaultPalette = _nc_cga_palette;
611 for (i = 0; i < (N_INI + FKEYS); i++) {
613 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = keylist[i];
615 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
616 GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
618 qsort(PropOf(TCB)->map,
622 qsort(PropOf(TCB)->rmap,
627 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
628 for (i = 0; i < NUMPAIRS; i++)
629 PropOf(TCB)->pairs[i] = a;
635 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
645 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
646 && (b >= 0) && (b < 8)) {
647 PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
652 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
653 short color GCC_UNUSED,
665 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
666 short old_pair GCC_UNUSED,
667 short pair GCC_UNUSED,
668 bool reverse GCC_UNUSED,
669 int (*outc) (SCREEN *, int) GCC_UNUSED
679 drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
688 drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
689 int yold GCC_UNUSED, int xold GCC_UNUSED,
693 if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
697 SetConsoleCursorPosition(TCB->hdl, loc);
704 drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
705 int labnum GCC_UNUSED,
706 char *text GCC_UNUSED)
715 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
716 bool OnFlag GCC_UNUSED)
725 drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
727 chtype res = A_NORMAL;
728 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
733 drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
742 drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
743 chtype *real_map GCC_UNUSED,
744 chtype *fake_map GCC_UNUSED)
746 #define DATA(a,b) { a, b }
751 DATA('a', 0xb1), /* ACS_CKBOARD */
752 DATA('f', 0xf8), /* ACS_DEGREE */
753 DATA('g', 0xf1), /* ACS_PLMINUS */
754 DATA('j', 0xd9), /* ACS_LRCORNER */
755 DATA('l', 0xda), /* ACS_ULCORNER */
756 DATA('k', 0xbf), /* ACS_URCORNER */
757 DATA('m', 0xc0), /* ACS_LLCORNER */
758 DATA('n', 0xc5), /* ACS_PLUS */
759 DATA('q', 0xc4), /* ACS_HLINE */
760 DATA('t', 0xc3), /* ACS_LTEE */
761 DATA('u', 0xb4), /* ACS_RTEE */
762 DATA('v', 0xc1), /* ACS_BTEE */
763 DATA('w', 0xc2), /* ACS_TTEE */
764 DATA('x', 0xb3), /* ACS_VLINE */
765 DATA('y', 0xf3), /* ACS_LEQUAL */
766 DATA('z', 0xf2), /* ACS_GEQUAL */
767 DATA('0', 0xdb), /* ACS_BLOCK */
768 DATA('{', 0xe3), /* ACS_PI */
769 DATA('}', 0x9c), /* ACS_STERLING */
770 DATA(',', 0xae), /* ACS_LARROW */
771 DATA('+', 0xaf), /* ACS_RARROW */
772 DATA('~', 0xf9), /* ACS_BULLET */
781 for (n = 0; n < SIZEOF(table); ++n) {
782 real_map[table[n].acs_code] = table[n].use_code | A_ALTCHARSET;
784 sp->_screen_acs_map[table[n].acs_code] = TRUE;
789 tdiff(FILETIME fstart, FILETIME fend)
791 ULARGE_INTEGER ustart;
795 ustart.LowPart = fstart.dwLowDateTime;
796 ustart.HighPart = fstart.dwHighDateTime;
797 uend.LowPart = fend.dwLowDateTime;
798 uend.HighPart = fend.dwHighDateTime;
800 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
805 Adjust(int milliseconds, int diff)
807 if (milliseconds == INFINITY)
809 milliseconds -= diff;
810 if (milliseconds < 0)
816 drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
820 EVENTLIST_2nd(_nc_eventlist * evl))
825 DWORD nRead = 0, rc = -1;
830 bool isImmed = (milliseconds == 0);
832 #define CONSUME() ReadConsoleInput(TCB->inp,&inp,1,&nRead)
837 if (milliseconds < 0)
838 milliseconds = INFINITY;
840 memset(&inp, 0, sizeof(inp));
843 GetSystemTimeAsFileTime(&fstart);
844 rc = WaitForSingleObject(TCB->inp, milliseconds);
845 GetSystemTimeAsFileTime(&fend);
846 diff = (int) tdiff(fstart, fend);
847 milliseconds = Adjust(milliseconds, diff);
849 if (!isImmed && milliseconds == 0)
852 if (rc == WAIT_OBJECT_0) {
854 b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
855 if (b && nRead > 0) {
856 b = PeekConsoleInput(TCB->inp, &inp, 1, &nRead);
857 if (b && nRead > 0) {
858 switch (inp.EventType) {
860 if (mode & TW_INPUT) {
861 WORD vk = inp.Event.KeyEvent.wVirtualKeyCode;
862 char ch = inp.Event.KeyEvent.uChar.AsciiChar;
864 if (inp.Event.KeyEvent.bKeyDown) {
866 int nKey = MapKey(TCB, vk);
867 if ((nKey < 0) || FALSE == sp->_keypad_on) {
880 if (0 && mode & TW_MOUSE) {
886 SetConsoleActiveScreenBuffer(!PropOf(TCB)->progMode ?
887 TCB->hdl : TCB->out);
895 if (rc != WAIT_TIMEOUT) {
906 *timeleft = milliseconds;
912 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
926 memset(&inp, 0, sizeof(inp));
928 while ((b = ReadConsoleInput(TCB->inp, &inp, 1, &nRead))) {
929 if (b && nRead > 0) {
930 if (inp.EventType == KEY_EVENT) {
931 if (!inp.Event.KeyEvent.bKeyDown)
933 *buf = (int) inp.Event.KeyEvent.uChar.AsciiChar;
934 vk = inp.Event.KeyEvent.wVirtualKeyCode;
935 sc = inp.Event.KeyEvent.wVirtualScanCode;
937 if (sp->_keypad_on) {
938 *buf = MapKey(TCB, vk);
945 } else { /* *buf != 0 */
948 } else if (0 && inp.EventType == MOUSE_EVENT) {
959 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
966 drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
972 LONG key = GenMap(0, (WORD) keycode);
981 (size_t) (N_INI + FKEYS),
985 key = *((LONG *) res);
987 if (!(nKey & 0x8000))
994 drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag GCC_UNUSED)
1009 drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
1016 LONG key = GenMap(0, (WORD) keycode);
1024 (size_t) (N_INI + FKEYS),
1028 key = *((LONG *) res);
1030 nKey = (LOWORD(key)) & 0x7fff;
1033 *(LONG *) res = GenMap(vKey, nKey);
1039 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1041 drv_CanHandle, /* CanHandle */
1042 drv_init, /* init */
1043 drv_release, /* release */
1044 drv_size, /* size */
1045 drv_sgmode, /* sgmode */
1046 drv_conattr, /* conattr */
1047 drv_mvcur, /* hwcur */
1048 drv_mode, /* mode */
1049 drv_rescol, /* rescol */
1050 drv_rescolors, /* rescolors */
1051 drv_setcolor, /* color */
1052 drv_dobeepflash, /* DoBeepFlash */
1053 drv_initpair, /* initpair */
1054 drv_initcolor, /* initcolor */
1055 drv_do_color, /* docolor */
1056 drv_initmouse, /* initmouse */
1057 drv_setfilter, /* setfilter */
1058 drv_hwlabel, /* hwlabel */
1059 drv_hwlabelOnOff, /* hwlabelOnOff */
1060 drv_doupdate, /* update */
1061 drv_defaultcolors, /* defaultcolors */
1062 drv_print, /* print */
1063 drv_size, /* getsize */
1064 drv_setsize, /* setsize */
1065 drv_initacs, /* initacs */
1066 drv_screen_init, /* scinit */
1067 drv_wrap, /* scexit */
1068 drv_twait, /* twait */
1069 drv_read, /* read */
1071 drv_kpad, /* kpad */
1072 drv_keyok, /* kyOk */
1073 drv_kyExist /* kyExist */