Browse Source

win32: improvements to the Win32 driver by Bastian Märkisch <bmaerkisch@web.de>:

- Save and correctly restore console input mode, ie. do not
   change settings of the original console.
 - Fix hiding of cursor.
 - Free console again if the driver actually created a new one.
 - Default canvas size is current window size.
 - Base calculation on current font.
 - Properly handle press and release events of up to 5 mouse buttons.
 - Map right mouse button to button #3. This is a change in behaviour,
   which is desirable for cross-platform codes.
 - Generate two click events for double mouse clicks.
 - Mouse wheel support, creates button press events. Button numbers
   are identical to X11 mappings.
 - Handle window buffer resize events.
tags/v0.99.beta19
Sam Hocevar sam 12 years ago
parent
commit
75fd8cd06f
2 changed files with 122 additions and 53 deletions
  1. +1
    -0
      THANKS
  2. +121
    -53
      caca/driver/win32.c

+ 1
- 0
THANKS View File

@@ -4,6 +4,7 @@


- Gildas Bazin <gbazin@netcourrier.com> - win32 driver improvements - Gildas Bazin <gbazin@netcourrier.com> - win32 driver improvements
- Jari Komppa <jari.komppa at gmail> - win32 speed improvements - Jari Komppa <jari.komppa at gmail> - win32 speed improvements
- Bastian Märkisch <bmaerkisch@web.de> - bugfixes and win32 driver improvements


\section thanks2 Reused code \section thanks2 Reused code




+ 121
- 53
caca/driver/win32.c View File

@@ -1,6 +1,7 @@
/* /*
* libcaca Colour ASCII-Art library * libcaca Colour ASCII-Art library
* Copyright (c) 2002-2010 Sam Hocevar <sam@hocevar.net>
* Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
* 2012 Bastian Märkisch <bmaerkisch@web.de>
* All Rights Reserved * All Rights Reserved
* *
* This library is free software. It comes without any warranty, to * This library is free software. It comes without any warranty, to
@@ -18,8 +19,21 @@


#if defined(USE_WIN32) #if defined(USE_WIN32)


#define _WIN32_WINNT 0x500 /* Require WinXP or later */
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>


#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 <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>


@@ -75,6 +89,9 @@ struct driver_private
HANDLE hin, hout, screen; HANDLE hin, hout, screen;
CHAR_INFO *buffer; CHAR_INFO *buffer;
CONSOLE_CURSOR_INFO cci; CONSOLE_CURSOR_INFO cci;
DWORD mouse_state;
DWORD mode;
BOOL new_console;
}; };


static int win32_init_graphics(caca_display_t *dp) 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 width = caca_get_canvas_width(dp->cv);
int height = caca_get_canvas_height(dp->cv); int height = caca_get_canvas_height(dp->cv);
CONSOLE_SCREEN_BUFFER_INFO csbi; CONSOLE_SCREEN_BUFFER_INFO csbi;
CONSOLE_CURSOR_INFO cci_screen;
SMALL_RECT rect; SMALL_RECT rect;
COORD size; COORD size;


dp->drv.p = malloc(sizeof(struct driver_private)); 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->hin = GetStdHandle(STD_INPUT_HANDLE);
dp->drv.p->hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, 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) if(dp->drv.p->hout == INVALID_HANDLE_VALUE)
return -1; return -1;


/* Preserve state information */
GetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci); 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 = dp->drv.p->screen =
CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
if(!dp->drv.p->screen || dp->drv.p->screen == INVALID_HANDLE_VALUE) if(!dp->drv.p->screen || dp->drv.p->screen == INVALID_HANDLE_VALUE)
return -1; 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.X = width ? width : 80;
size.Y = height ? height : 25; 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); SetConsoleScreenBufferSize(dp->drv.p->screen, size);


rect.Left = rect.Top = 0; rect.Left = rect.Top = 0;
@@ -133,10 +156,13 @@ static int win32_init_graphics(caca_display_t *dp)


SetConsoleMode(dp->drv.p->screen, 0); 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); SetConsoleActiveScreenBuffer(dp->drv.p->screen);


@@ -153,14 +179,15 @@ static int win32_end_graphics(caca_display_t *dp)
SetConsoleActiveScreenBuffer(dp->drv.p->hout); SetConsoleActiveScreenBuffer(dp->drv.p->hout);
CloseHandle(dp->drv.p->screen); 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); SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
CloseHandle(dp->drv.p->hout); 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); free(dp->drv.p);


return 0; 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) static int win32_get_display_width(caca_display_t const *dp)
{ {
/* FIXME */

/* Fallback to a 6x10 font */ /* 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) static int win32_get_display_height(caca_display_t const *dp)
{ {
/* FIXME */

/* Fallback to a 6x10 font */ /* 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) 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) 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) 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( ; ; ) 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) if(num == 0)
break; 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.EventType == KEY_EVENT)
{ {
if(rec.Event.KeyEvent.bKeyDown) 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; 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)) (ev->data.key.ch <= 0x7f))
{ {
@@ -351,23 +394,30 @@ static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev)
return 1; 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) 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; ev->data.mouse.y = dp->mouse.y;
return 1; 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 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 */ /* Unknown event */


Loading…
Cancel
Save