source: libcaca/trunk/caca/driver_win32.c @ 2821

Last change on this file since 2821 was 2821, checked in by Sam Hocevar, 11 years ago

Starting refactoring to get rid of libcucul. The initial reason for the
split is rendered moot by the plugin system: when enabled, binaries do
not link directly with libX11 or libGL. I hope this is a step towards
more consisteny and clarity.

  • Property svn:keywords set to Id
File size: 10.7 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: driver_win32.c 2821 2008-09-27 13:12:46Z sam $
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  This file contains the libcaca Win32 input and output driver
17 */
18
19#include "config.h"
20
21#if defined(USE_WIN32)
22
23#include <windows.h>
24
25#include <stdlib.h>
26#include <stdio.h>
27
28#include "caca.h"
29#include "caca_internals.h"
30
31/*
32 * Global variables
33 */
34
35static int const win32_fg_palette[] =
36{
37    0,
38    FOREGROUND_BLUE,
39    FOREGROUND_GREEN,
40    FOREGROUND_GREEN | FOREGROUND_BLUE,
41    FOREGROUND_RED,
42    FOREGROUND_RED | FOREGROUND_BLUE,
43    FOREGROUND_RED | FOREGROUND_GREEN,
44    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
45    FOREGROUND_INTENSITY,
46    FOREGROUND_INTENSITY | FOREGROUND_BLUE,
47    FOREGROUND_INTENSITY | FOREGROUND_GREEN,
48    FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
49    FOREGROUND_INTENSITY | FOREGROUND_RED,
50    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
51    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
52    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
53};
54
55static int const win32_bg_palette[] =
56{
57    0,
58    BACKGROUND_BLUE,
59    BACKGROUND_GREEN,
60    BACKGROUND_GREEN | BACKGROUND_BLUE,
61    BACKGROUND_RED,
62    BACKGROUND_RED | BACKGROUND_BLUE,
63    BACKGROUND_RED | BACKGROUND_GREEN,
64    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
65    BACKGROUND_INTENSITY,
66    BACKGROUND_INTENSITY | BACKGROUND_BLUE,
67    BACKGROUND_INTENSITY | BACKGROUND_GREEN,
68    BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
69    BACKGROUND_INTENSITY | BACKGROUND_RED,
70    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
71    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
72    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
73};
74
75struct driver_private
76{
77    HANDLE hin, hout, screen;
78    CHAR_INFO *buffer;
79    CONSOLE_CURSOR_INFO cci;
80};
81
82static int win32_init_graphics(caca_display_t *dp)
83{
84    int width = caca_get_canvas_width(dp->cv);
85    int height = caca_get_canvas_height(dp->cv);
86    CONSOLE_SCREEN_BUFFER_INFO csbi;
87    SMALL_RECT rect;
88    COORD size;
89
90    dp->drv.p = malloc(sizeof(struct driver_private));
91
92    /* This call is allowed to fail in case we already have a console */
93    AllocConsole();
94
95    dp->drv.p->hin = GetStdHandle(STD_INPUT_HANDLE);
96    dp->drv.p->hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
97                                 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
98                                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
99    if(dp->drv.p->hout == INVALID_HANDLE_VALUE)
100        return -1;
101
102    GetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
103    dp->drv.p->cci.bVisible = FALSE;
104    SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
105
106    SetConsoleMode(dp->drv.p->hout, ENABLE_MOUSE_INPUT);
107
108    dp->drv.p->screen =
109        CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
110                                  0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
111    if(!dp->drv.p->screen || dp->drv.p->screen == INVALID_HANDLE_VALUE)
112        return -1;
113
114    /* Set the new console size */
115    size.X = width ? width : 80;
116    size.Y = height ? height : 25;
117    SetConsoleScreenBufferSize(dp->drv.p->screen, size);
118
119    rect.Left = rect.Top = 0;
120    rect.Right = size.X - 1;
121    rect.Bottom = size.Y - 1;
122    SetConsoleWindowInfo(dp->drv.p->screen, TRUE, &rect);
123
124    /* Report our new size to libcaca */
125    if(!GetConsoleScreenBufferInfo(dp->drv.p->screen, &csbi))
126        return -1;
127
128    dp->resize.allow = 1;
129    caca_set_canvas_size(dp->cv,
130                          csbi.srWindow.Right - csbi.srWindow.Left + 1,
131                          csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
132    width = caca_get_canvas_width(dp->cv);
133    height = caca_get_canvas_height(dp->cv);
134    dp->resize.allow = 0;
135
136    SetConsoleMode(dp->drv.p->screen, 0);
137
138    GetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
139    dp->drv.p->cci.dwSize = 0;
140    dp->drv.p->cci.bVisible = FALSE;
141    SetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
142
143    SetConsoleActiveScreenBuffer(dp->drv.p->screen);
144
145    dp->drv.p->buffer = malloc(width * height
146                               * sizeof(CHAR_INFO));
147    if(dp->drv.p->buffer == NULL)
148        return -1;
149
150    return 0;
151}
152
153static int win32_end_graphics(caca_display_t *dp)
154{
155    SetConsoleActiveScreenBuffer(dp->drv.p->hout);
156    CloseHandle(dp->drv.p->screen);
157
158    SetConsoleTextAttribute(dp->drv.p->hout, FOREGROUND_INTENSITY
159                                             | FOREGROUND_RED
160                                             | FOREGROUND_GREEN
161                                             | FOREGROUND_BLUE);
162    dp->drv.p->cci.bVisible = TRUE;
163    SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
164    CloseHandle(dp->drv.p->hout);
165
166    free(dp->drv.p);
167
168    return 0;
169}
170
171static int win32_set_display_title(caca_display_t *dp, char const *title)
172{
173    SetConsoleTitle(title);
174    return 0;
175}
176
177static int win32_get_display_width(caca_display_t const *dp)
178{
179    /* FIXME */
180
181    /* Fallback to a 6x10 font */
182    return caca_get_canvas_width(dp->cv) * 6;
183}
184
185static int win32_get_display_height(caca_display_t const *dp)
186{
187    /* FIXME */
188
189    /* Fallback to a 6x10 font */
190    return caca_get_canvas_height(dp->cv) * 10;
191}
192
193static void win32_display(caca_display_t *dp)
194{
195    COORD size, pos;
196    SMALL_RECT rect;
197    CHAR_INFO *buffer = dp->drv.p->buffer;
198    uint32_t const *cvchars = (uint32_t const *)caca_get_canvas_chars(dp->cv);
199    uint32_t const *cvattrs = (uint32_t const *)caca_get_canvas_attrs(dp->cv);
200    int width = caca_get_canvas_width(dp->cv);
201    int height = caca_get_canvas_height(dp->cv);
202    int n;
203
204    /* Render everything to our screen buffer */
205    for(n = height * width; n--; )
206    {
207        uint32_t ch = *cvchars++;
208        uint8_t fg = caca_attr_to_ansi_fg(*cvattrs);
209        uint8_t bg = caca_attr_to_ansi_bg(*cvattrs);
210
211#if 0
212        if(ch > 0x00000020 && ch < 0x00000080)
213            dp->drv.p->buffer[i].Char.AsciiChar = (uint8_t)ch;
214        else
215            dp->drv.p->buffer[i].Char.AsciiChar = ' ';
216#else
217        if(n && *cvchars == CACA_MAGIC_FULLWIDTH)
218            ;
219        else if(ch > 0x00000020 && ch < 0x00010000)
220            buffer->Char.UnicodeChar = (uint16_t)ch;
221        else
222            buffer->Char.UnicodeChar = (uint16_t)' ';
223#endif
224
225        buffer->Attributes = win32_fg_palette[fg < 0x10 ? fg : CACA_LIGHTGRAY]
226                              | win32_bg_palette[bg < 0x10 ? bg : CACA_BLACK];
227        cvattrs++;
228        buffer++;
229    }
230
231    /* Blit the screen buffer */
232    size.X = width;
233    size.Y = height;
234    pos.X = pos.Y = 0;
235    rect.Left = rect.Top = 0;
236    rect.Right = width - 1;
237    rect.Bottom = height - 1;
238#if 0
239    WriteConsoleOutput(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
240#else
241    WriteConsoleOutputW(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
242#endif
243}
244
245static void win32_handle_resize(caca_display_t *dp)
246{
247    /* FIXME: I don't know what to do here. */
248    dp->resize.w = caca_get_canvas_width(dp->cv);
249    dp->resize.h = caca_get_canvas_height(dp->cv);
250}
251
252static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev)
253{
254    INPUT_RECORD rec;
255    DWORD num;
256
257    for( ; ; )
258    {
259        GetNumberOfConsoleInputEvents(dp->drv.p->hin, &num);
260        if(num == 0)
261            break;
262
263        ReadConsoleInput(dp->drv.p->hin, &rec, 1, &num);
264        if(rec.EventType == KEY_EVENT)
265        {
266            if(rec.Event.KeyEvent.bKeyDown)
267                ev->type = CACA_EVENT_KEY_PRESS;
268            else
269                ev->type = CACA_EVENT_KEY_RELEASE;
270
271            if(rec.Event.KeyEvent.uChar.AsciiChar)
272            {
273                ev->data.key.ch = rec.Event.KeyEvent.uChar.AsciiChar;
274                ev->data.key.utf32 = (uint32_t)ev->data.key.ch;
275                ev->data.key.utf8[0] = ev->data.key.ch;
276                ev->data.key.utf8[1] = '\0';
277
278                return 1;
279            }
280        }
281
282        if(rec.EventType == MOUSE_EVENT)
283        {
284            if(rec.Event.MouseEvent.dwEventFlags == 0)
285            {
286                if(rec.Event.MouseEvent.dwButtonState & 0x01)
287                {
288                    ev->type = CACA_EVENT_MOUSE_PRESS;
289                    ev->data.mouse.button = 1;
290                    return 1;
291                }
292
293                if(rec.Event.MouseEvent.dwButtonState & 0x02)
294                {
295                    ev->type = CACA_EVENT_MOUSE_PRESS;
296                    ev->data.mouse.button = 2;
297                    return 1;
298                }
299            }
300            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
301            {
302                COORD pos = rec.Event.MouseEvent.dwMousePosition;
303
304                if(dp->mouse.x == pos.X && dp->mouse.y == pos.Y)
305                    continue;
306
307                dp->mouse.x = pos.X;
308                dp->mouse.y = pos.Y;
309
310                ev->type = CACA_EVENT_MOUSE_MOTION;
311                ev->data.mouse.x = dp->mouse.x;
312                ev->data.mouse.y = dp->mouse.y;
313                return 1;
314            }
315#if 0
316            else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
317            {
318                cout << rec.Event.MouseEvent.dwMousePosition.X << "," <<
319                        rec.Event.MouseEvent.dwMousePosition.Y << "  " << flush;
320            }
321            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
322            {
323                SetConsoleCursorPosition(hOut,
324                                         WheelWhere);
325                if(rec.Event.MouseEvent.dwButtonState & 0xFF000000)
326                    cout << "Down" << flush;
327                else
328                    cout << "Up  " << flush;
329            }
330#endif
331        }
332
333        /* Unknown event */
334        ev->type = CACA_EVENT_NONE;
335        return 0;
336    }
337
338    /* No event */
339    ev->type = CACA_EVENT_NONE;
340    return 0;
341}
342
343/*
344 * Driver initialisation
345 */
346
347int win32_install(caca_display_t *dp)
348{
349    dp->drv.id = CACA_DRIVER_WIN32;
350    dp->drv.driver = "win32";
351
352    dp->drv.init_graphics = win32_init_graphics;
353    dp->drv.end_graphics = win32_end_graphics;
354    dp->drv.set_display_title = win32_set_display_title;
355    dp->drv.get_display_width = win32_get_display_width;
356    dp->drv.get_display_height = win32_get_display_height;
357    dp->drv.display = win32_display;
358    dp->drv.handle_resize = win32_handle_resize;
359    dp->drv.get_event = win32_get_event;
360    dp->drv.set_mouse = NULL;
361    dp->drv.set_cursor = NULL;
362
363    return 0;
364}
365
366#endif /* USE_WIN32 */
367
Note: See TracBrowser for help on using the repository browser.