Bladeren bron

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 jaren geleden
bovenliggende
commit
75fd8cd06f
2 gewijzigde bestanden met toevoegingen van 122 en 53 verwijderingen
  1. +1
    -0
      THANKS
  2. +121
    -53
      caca/driver/win32.c

+ 1
- 0
THANKS Bestand weergeven

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

- Gildas Bazin <gbazin@netcourrier.com> - win32 driver 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



+ 121
- 53
caca/driver/win32.c Bestand weergeven

@@ -1,6 +1,7 @@
/*
* 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
*
* 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 <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 <stdio.h>

@@ -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 */


Laden…
Annuleren
Opslaan