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

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