From 75fd8cd06f1416bc85be329a320820f82f6383ed Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Sun, 18 Nov 2012 18:34:14 +0000 Subject: [PATCH] =?UTF-8?q?win32:=20improvements=20to=20the=20Win32=20driv?= =?UTF-8?q?er=20by=20Bastian=20M=C3=A4rkisch=20:=20=20-?= =?UTF-8?q?=20Save=20and=20correctly=20restore=20console=20input=20mode,?= =?UTF-8?q?=20ie.=20do=20not=20=20=20=20change=20settings=20of=20the=20ori?= =?UTF-8?q?ginal=20console.=20=20-=20Fix=20hiding=20of=20cursor.=20=20-=20?= =?UTF-8?q?Free=20console=20again=20if=20the=20driver=20actually=20created?= =?UTF-8?q?=20a=20new=20one.=20=20-=20Default=20canvas=20size=20is=20curre?= =?UTF-8?q?nt=20window=20size.=20=20-=20Base=20calculation=20on=20current?= =?UTF-8?q?=20font.=20=20-=20Properly=20handle=20press=20and=20release=20e?= =?UTF-8?q?vents=20of=20up=20to=205=20mouse=20buttons.=20=20-=20Map=20righ?= =?UTF-8?q?t=20mouse=20button=20to=20button=20#3.=20This=20is=20a=20change?= =?UTF-8?q?=20in=20behaviour,=20=20=20=20which=20is=20desirable=20for=20cr?= =?UTF-8?q?oss-platform=20codes.=20=20-=20Generate=20two=20click=20events?= =?UTF-8?q?=20for=20double=20mouse=20clicks.=20=20-=20Mouse=20wheel=20supp?= =?UTF-8?q?ort,=20creates=20button=20press=20events.=20Button=20numbers=20?= =?UTF-8?q?=20=20=20are=20identical=20to=20X11=20mappings.=20=20-=20Handle?= =?UTF-8?q?=20window=20buffer=20resize=20events.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- THANKS | 1 + caca/driver/win32.c | 174 ++++++++++++++++++++++++++++++-------------- 2 files changed, 122 insertions(+), 53 deletions(-) diff --git a/THANKS b/THANKS index 27f1e44..f12b5b4 100644 --- a/THANKS +++ b/THANKS @@ -4,6 +4,7 @@ - Gildas Bazin - win32 driver improvements - Jari Komppa - win32 speed improvements +- Bastian Märkisch - bugfixes and win32 driver improvements \section thanks2 Reused code diff --git a/caca/driver/win32.c b/caca/driver/win32.c index faeaaef..6a91aa5 100644 --- a/caca/driver/win32.c +++ b/caca/driver/win32.c @@ -1,6 +1,7 @@ /* * libcaca Colour ASCII-Art library - * Copyright (c) 2002-2010 Sam Hocevar + * Copyright (c) 2002-2012 Sam Hocevar + * 2012 Bastian Märkisch * All Rights Reserved * * This library is free software. It comes without any warranty, to @@ -18,8 +19,21 @@ #if defined(USE_WIN32) +#define _WIN32_WINNT 0x500 /* Require WinXP or later */ +#define WIN32_LEAN_AND_MEAN #include +#ifdef __MINGW32__ +/* This is missing from the MinGW headers. */ +# if (_WIN32_WINNT >= 0x0500) +BOOL WINAPI GetCurrentConsoleFont(HANDLE hConsoleOutput, BOOL bMaximumWindow, + PCONSOLE_FONT_INFO lpConsoleCurrentFont); +# endif +#endif +#ifndef MOUSE_HWHEELED +# define MOUSE_HWHEELED 0x0008 +#endif + #include #include @@ -75,6 +89,9 @@ struct driver_private HANDLE hin, hout, screen; CHAR_INFO *buffer; CONSOLE_CURSOR_INFO cci; + DWORD mouse_state; + DWORD mode; + BOOL new_console; }; static int win32_init_graphics(caca_display_t *dp) @@ -82,13 +99,14 @@ static int win32_init_graphics(caca_display_t *dp) int width = caca_get_canvas_width(dp->cv); int height = caca_get_canvas_height(dp->cv); CONSOLE_SCREEN_BUFFER_INFO csbi; + CONSOLE_CURSOR_INFO cci_screen; SMALL_RECT rect; COORD size; dp->drv.p = malloc(sizeof(struct driver_private)); - /* This call is allowed to fail in case we already have a console */ - AllocConsole(); + /* This call is allowed to fail in case we already have a console. */ + dp->drv.p->new_console = AllocConsole(); dp->drv.p->hin = GetStdHandle(STD_INPUT_HANDLE); dp->drv.p->hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, @@ -97,21 +115,26 @@ static int win32_init_graphics(caca_display_t *dp) if(dp->drv.p->hout == INVALID_HANDLE_VALUE) return -1; + /* Preserve state information */ GetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci); - dp->drv.p->cci.bVisible = FALSE; - SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci); - - SetConsoleMode(dp->drv.p->hout, ENABLE_MOUSE_INPUT); dp->drv.p->screen = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); if(!dp->drv.p->screen || dp->drv.p->screen == INVALID_HANDLE_VALUE) return -1; + dp->drv.p->mouse_state = 0; - /* Set the new console size */ + /* Set the new console size, default to current screen size. */ size.X = width ? width : 80; size.Y = height ? height : 25; + if ((width <= 0) && (height <= 0)) + { + CONSOLE_SCREEN_BUFFER_INFO info; + + if (GetConsoleScreenBufferInfo(dp->drv.p->hout, &info) != 0) + size = info.dwSize; + } SetConsoleScreenBufferSize(dp->drv.p->screen, size); rect.Left = rect.Top = 0; @@ -133,10 +156,13 @@ static int win32_init_graphics(caca_display_t *dp) SetConsoleMode(dp->drv.p->screen, 0); - GetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci); - dp->drv.p->cci.dwSize = 0; - dp->drv.p->cci.bVisible = FALSE; - SetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci); + /* We want mouse and window resize events. */ + GetConsoleMode(dp->drv.p->hin, &dp->drv.p->mode); + SetConsoleMode(dp->drv.p->hin, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT); + + cci_screen.dwSize = 1; /* must be > 0, see MSDN */ + cci_screen.bVisible = FALSE; + SetConsoleCursorInfo(dp->drv.p->screen, &cci_screen); SetConsoleActiveScreenBuffer(dp->drv.p->screen); @@ -153,14 +179,15 @@ static int win32_end_graphics(caca_display_t *dp) SetConsoleActiveScreenBuffer(dp->drv.p->hout); CloseHandle(dp->drv.p->screen); - SetConsoleTextAttribute(dp->drv.p->hout, FOREGROUND_INTENSITY - | FOREGROUND_RED - | FOREGROUND_GREEN - | FOREGROUND_BLUE); - dp->drv.p->cci.bVisible = TRUE; + /* Reset console parameters */ + SetConsoleMode(dp->drv.p->hin, dp->drv.p->mode); SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci); CloseHandle(dp->drv.p->hout); + /* We only free the console if we successfully created a new one before */ + if (dp->drv.p->new_console) + FreeConsole(); + free(dp->drv.p); return 0; @@ -174,18 +201,28 @@ static int win32_set_display_title(caca_display_t *dp, char const *title) static int win32_get_display_width(caca_display_t const *dp) { - /* FIXME */ - /* Fallback to a 6x10 font */ - return caca_get_canvas_width(dp->cv) * 6; + int font_width = 6; + +#if (_WIN32_WINNT >= 0x500) + CONSOLE_FONT_INFO info; + if (GetCurrentConsoleFont(dp->drv.p->screen, FALSE, &info) != 0) + font_width = info.dwFontSize.X; +#endif + return font_width * caca_get_canvas_width(dp->cv); } static int win32_get_display_height(caca_display_t const *dp) { - /* FIXME */ - /* Fallback to a 6x10 font */ - return caca_get_canvas_height(dp->cv) * 10; + int font_height = 10; + +#if (_WIN32_WINNT >= 0x500) + CONSOLE_FONT_INFO info; + if (GetCurrentConsoleFont(dp->drv.p->screen, FALSE, &info) != 0) + font_height = info.dwFontSize.Y; +#endif + return font_height * caca_get_canvas_height(dp->cv); } static void win32_display(caca_display_t *dp) @@ -244,9 +281,9 @@ static void win32_display(caca_display_t *dp) static void win32_handle_resize(caca_display_t *dp) { - /* FIXME: I don't know what to do here. */ - dp->resize.w = caca_get_canvas_width(dp->cv); - dp->resize.h = caca_get_canvas_height(dp->cv); + /* We only need to resize the internal buffer. */ + dp->drv.p->buffer = realloc(dp->drv.p->buffer, + dp->resize.w * dp->resize.h * sizeof(CHAR_INFO)); } static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev) @@ -256,11 +293,17 @@ static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev) for( ; ; ) { - GetNumberOfConsoleInputEvents(dp->drv.p->hin, &num); + HANDLE hin = GetStdHandle(STD_INPUT_HANDLE); + if(hin == INVALID_HANDLE_VALUE) + break; + + GetNumberOfConsoleInputEvents(hin, &num); if(num == 0) break; - ReadConsoleInput(dp->drv.p->hin, &rec, 1, &num); + if(!ReadConsoleInput(hin, &rec, 1, &num) || (num == 0)) + break; + if(rec.EventType == KEY_EVENT) { if(rec.Event.KeyEvent.bKeyDown) @@ -334,7 +377,7 @@ static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev) default: ev->type = CACA_EVENT_NONE; return 0; } - if ((ev->data.key.ch > 0) + if((ev->data.key.ch > 0) && (ev->data.key.ch <= 0x7f)) { @@ -351,23 +394,30 @@ static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev) return 1; } } - - if(rec.EventType == MOUSE_EVENT) + else if(rec.EventType == MOUSE_EVENT) { - if(rec.Event.MouseEvent.dwEventFlags == 0) + if((rec.Event.MouseEvent.dwEventFlags == 0) || + (rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)) { - if(rec.Event.MouseEvent.dwButtonState & 0x01) - { - ev->type = CACA_EVENT_MOUSE_PRESS; - ev->data.mouse.button = 1; - return 1; - } + DWORD mouse_state_changed = + dp->drv.p->mouse_state ^ rec.Event.MouseEvent.dwButtonState; + int button; + DWORD mask = 0x01; + int const mapping[] = {1, 3, 2, 8, 9}; - if(rec.Event.MouseEvent.dwButtonState & 0x02) + for (button = 1; button <= 5; button++) { - ev->type = CACA_EVENT_MOUSE_PRESS; - ev->data.mouse.button = 2; - return 1; + if(mouse_state_changed == mask) + { + if(rec.Event.MouseEvent.dwButtonState & mask) + ev->type = CACA_EVENT_MOUSE_PRESS; + else + ev->type = CACA_EVENT_MOUSE_RELEASE; + ev->data.mouse.button = mapping[button - 1]; + dp->drv.p->mouse_state = rec.Event.MouseEvent.dwButtonState; + return 1; + } + mask <<= 1; } } else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) @@ -385,22 +435,40 @@ static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev) ev->data.mouse.y = dp->mouse.y; return 1; } -#if 0 - else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) + else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED) { - cout << rec.Event.MouseEvent.dwMousePosition.X << "," << - rec.Event.MouseEvent.dwMousePosition.Y << " " << flush; + ev->type = CACA_EVENT_MOUSE_PRESS; + if((int16_t)HIWORD(rec.Event.MouseEvent.dwButtonState) > 0) + ev->data.mouse.button = 4; /* up */ + else + ev->data.mouse.button = 5; /* down */ + return 1; } - else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED) + else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_HWHEELED) { - SetConsoleCursorPosition(hOut, - WheelWhere); - if(rec.Event.MouseEvent.dwButtonState & 0xFF000000) - cout << "Down" << flush; + ev->type = CACA_EVENT_MOUSE_PRESS; + if((int16_t)HIWORD(rec.Event.MouseEvent.dwButtonState) > 0) + ev->data.mouse.button = 7; /* right */ else - cout << "Up " << flush; + ev->data.mouse.button = 6; /* left */ + return 1; } -#endif + } + else if(rec.EventType == WINDOW_BUFFER_SIZE_EVENT) + { + int width = caca_get_canvas_width(dp->cv); + int height = caca_get_canvas_height(dp->cv); + int w = rec.Event.WindowBufferSizeEvent.dwSize.X; + int h = rec.Event.WindowBufferSizeEvent.dwSize.Y; + if((w == 0) || (h == 0) || ((w == width) && (h == height))) + continue; + + /* resize the canvas accordingly */ + ev->type = CACA_EVENT_RESIZE; + dp->resize.w = w; + dp->resize.h = h; + dp->resize.resized = 1; + return 1; } /* Unknown event */