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

Last change on this file since 1233 was 1233, checked in by Sam Hocevar, 13 years ago
  • Allow to create the initial canvas with a zero size. Either the application resizes it later, or the driver changes it to fit the display.
  • Property svn:keywords set to Id
File size: 10.2 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 1233 2006-10-26 08:16:43Z sam $
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14/*
15 *  This file contains the libcaca Win32 input and output driver
16 */
17
18#include "config.h"
19#include "common.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#include "cucul.h"
31#include "cucul_internals.h"
32
33/*
34 * Global variables
35 */
36
37static int const win32_fg_palette[] =
38{
39    0,
40    FOREGROUND_BLUE,
41    FOREGROUND_GREEN,
42    FOREGROUND_GREEN | FOREGROUND_BLUE,
43    FOREGROUND_RED,
44    FOREGROUND_RED | FOREGROUND_BLUE,
45    FOREGROUND_RED | FOREGROUND_GREEN,
46    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
47    FOREGROUND_INTENSITY,
48    FOREGROUND_INTENSITY | FOREGROUND_BLUE,
49    FOREGROUND_INTENSITY | FOREGROUND_GREEN,
50    FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
51    FOREGROUND_INTENSITY | FOREGROUND_RED,
52    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
53    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
54    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
55};
56
57static int const win32_bg_palette[] =
58{
59    0,
60    BACKGROUND_BLUE,
61    BACKGROUND_GREEN,
62    BACKGROUND_GREEN | BACKGROUND_BLUE,
63    BACKGROUND_RED,
64    BACKGROUND_RED | BACKGROUND_BLUE,
65    BACKGROUND_RED | BACKGROUND_GREEN,
66    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
67    BACKGROUND_INTENSITY,
68    BACKGROUND_INTENSITY | BACKGROUND_BLUE,
69    BACKGROUND_INTENSITY | BACKGROUND_GREEN,
70    BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
71    BACKGROUND_INTENSITY | BACKGROUND_RED,
72    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
73    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
74    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
75};
76
77struct driver_private
78{
79    HANDLE hin, hout, screen;
80    CHAR_INFO *buffer;
81    CONSOLE_CURSOR_INFO cci;
82};
83
84static int win32_init_graphics(caca_display_t *dp)
85{
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 = dp->cv->width ? dp->cv->width : 80;
116    size.Y = dp->cv->height ? dp->cv->height : 25;
117    SetConsoleScreenBufferSize(dp->drv.p->screen, size);
118
119    rect.Left = rect.Top = 0;
120    rect.Right = dp->cv->width - 1;
121    rect.Bottom = dp->cv->height - 1;
122    SetConsoleWindowInfo(dp->drv.p->screen, TRUE, &rect);
123
124    /* Report our new size to libcucul */
125    if(!GetConsoleScreenBufferInfo(dp->drv.p->screen, &csbi))
126        return -1;
127
128    _cucul_set_canvas_size(dp->cv, csbi.srWindow.Right - csbi.srWindow.Left + 1,
129                           csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
130
131    SetConsoleMode(dp->drv.p->screen, 0);
132
133    GetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
134    dp->drv.p->cci.dwSize = 0;
135    dp->drv.p->cci.bVisible = FALSE;
136    SetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
137
138    SetConsoleActiveScreenBuffer(dp->drv.p->screen);
139
140    dp->drv.p->buffer = malloc(dp->cv->width * dp->cv->height
141                               * sizeof(CHAR_INFO));
142    if(dp->drv.p->buffer == NULL)
143        return -1;
144
145    return 0;
146}
147
148static int win32_end_graphics(caca_display_t *dp)
149{
150    SetConsoleActiveScreenBuffer(dp->drv.p->hout);
151    CloseHandle(dp->drv.p->screen);
152
153    SetConsoleTextAttribute(dp->drv.p->hout, FOREGROUND_INTENSITY
154                                             | FOREGROUND_RED
155                                             | FOREGROUND_GREEN
156                                             | FOREGROUND_BLUE);
157    dp->drv.p->cci.bVisible = TRUE;
158    SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
159    CloseHandle(dp->drv.p->hout);
160
161    free(dp->drv.p);
162
163    return 0;
164}
165
166static int win32_set_display_title(caca_display_t *dp, char const *title)
167{
168    SetConsoleTitle(title);
169    return 0;
170}
171
172static unsigned int win32_get_display_width(caca_display_t *dp)
173{
174    /* FIXME */
175
176    /* Fallback to a 6x10 font */
177    return dp->cv->width * 6;
178}
179
180static unsigned int win32_get_display_height(caca_display_t *dp)
181{
182    /* FIXME */
183
184    /* Fallback to a 6x10 font */
185    return dp->cv->height * 10;
186}
187
188static void win32_display(caca_display_t *dp)
189{
190    COORD size, pos;
191    SMALL_RECT rect;
192    CHAR_INFO *buffer = dp->drv.p->buffer;
193    uint32_t *attr = dp->cv->attr;
194    uint32_t *chars = dp->cv->chars;
195    unsigned int n;
196
197    /* Render everything to our screen buffer */
198    for(n = dp->cv->height * dp->cv->width; n--; )
199    {
200        uint32_t ch = *chars++;
201
202#if 0
203        if(ch > 0x00000020 && ch < 0x00000080)
204            dp->drv.p->buffer[i].Char.AsciiChar = (uint8_t)ch;
205        else
206            dp->drv.p->buffer[i].Char.AsciiChar = ' ';
207#else
208        if(n && *chars == CUCUL_MAGIC_FULLWIDTH)
209            ;
210        else if(ch > 0x00000020 && ch < 0x00010000)
211            buffer->Char.UnicodeChar = (uint16_t)ch;
212        else
213            buffer->Char.UnicodeChar = (uint16_t)' ';
214#endif
215
216        buffer->Attributes =
217                win32_fg_palette[_cucul_argb32_to_ansi4fg(*attr)]
218                 | win32_bg_palette[_cucul_argb32_to_ansi4bg(*attr)];
219        attr++;
220        buffer++;
221    }
222
223    /* Blit the screen buffer */
224    size.X = dp->cv->width;
225    size.Y = dp->cv->height;
226    pos.X = pos.Y = 0;
227    rect.Left = rect.Top = 0;
228    rect.Right = dp->cv->width - 1;
229    rect.Bottom = dp->cv->height - 1;
230#if 0
231    WriteConsoleOutput(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
232#else
233    WriteConsoleOutputW(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
234#endif
235}
236
237static void win32_handle_resize(caca_display_t *dp)
238{
239    /* FIXME: I don't know what to do here. */
240    dp->resize.w = dp->cv->width;
241    dp->resize.h = dp->cv->height;
242}
243
244static int win32_get_event(caca_display_t *dp, caca_event_t *ev)
245{
246    INPUT_RECORD rec;
247    DWORD num;
248
249    for( ; ; )
250    {
251        GetNumberOfConsoleInputEvents(dp->drv.p->hin, &num);
252        if(num == 0)
253            break;
254
255        ReadConsoleInput(dp->drv.p->hin, &rec, 1, &num);
256        if(rec.EventType == KEY_EVENT)
257        {
258            if(rec.Event.KeyEvent.bKeyDown)
259                ev->type = CACA_EVENT_KEY_PRESS;
260            else
261                ev->type = CACA_EVENT_KEY_RELEASE;
262
263            if(rec.Event.KeyEvent.uChar.AsciiChar)
264            {
265                ev->data.key.ch = rec.Event.KeyEvent.uChar.AsciiChar;
266                ev->data.key.utf32 = (uint32_t)ev->data.key.ch;
267                ev->data.key.utf8[0] = ev->data.key.ch;
268                ev->data.key.utf8[1] = '\0';
269
270                return 1;
271            }
272        }
273
274        if(rec.EventType == MOUSE_EVENT)
275        {
276            if(rec.Event.MouseEvent.dwEventFlags == 0)
277            {
278                if(rec.Event.MouseEvent.dwButtonState & 0x01)
279                {
280                    ev->type = CACA_EVENT_MOUSE_PRESS;
281                    ev->data.mouse.button = 1;
282                    return 1;
283                }
284
285                if(rec.Event.MouseEvent.dwButtonState & 0x02)
286                {
287                    ev->type = CACA_EVENT_MOUSE_PRESS;
288                    ev->data.mouse.button = 2;
289                    return 1;
290                }
291            }
292            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
293            {
294                COORD pos = rec.Event.MouseEvent.dwMousePosition;
295
296                if(dp->mouse.x == (unsigned int)pos.X &&
297                   dp->mouse.y == (unsigned int)pos.Y)
298                    continue;
299
300                dp->mouse.x = pos.X;
301                dp->mouse.y = pos.Y;
302
303                ev->type = CACA_EVENT_MOUSE_MOTION;
304                ev->data.mouse.x = dp->mouse.x;
305                ev->data.mouse.y = dp->mouse.y;
306                return 1;
307            }
308#if 0
309            else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
310            {
311                cout << rec.Event.MouseEvent.dwMousePosition.X << "," <<
312                        rec.Event.MouseEvent.dwMousePosition.Y << "  " << flush;
313            }
314            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
315            {
316                SetConsoleCursorPosition(hOut,
317                                         WheelWhere);
318                if(rec.Event.MouseEvent.dwButtonState & 0xFF000000)
319                    cout << "Down" << flush;
320                else
321                    cout << "Up  " << flush;
322            }
323#endif
324        }
325
326        /* Unknown event */
327        ev->type = CACA_EVENT_NONE;
328        return 0;
329    }
330
331    /* No event */
332    ev->type = CACA_EVENT_NONE;
333    return 0;
334}
335
336/*
337 * Driver initialisation
338 */
339
340int win32_install(caca_display_t *dp)
341{
342    dp->drv.driver = CACA_DRIVER_WIN32;
343
344    dp->drv.init_graphics = win32_init_graphics;
345    dp->drv.end_graphics = win32_end_graphics;
346    dp->drv.set_display_title = win32_set_display_title;
347    dp->drv.get_display_width = win32_get_display_width;
348    dp->drv.get_display_height = win32_get_display_height;
349    dp->drv.display = win32_display;
350    dp->drv.handle_resize = win32_handle_resize;
351    dp->drv.get_event = win32_get_event;
352    dp->drv.set_mouse = NULL;
353
354    return 0;
355}
356
357#endif /* USE_WIN32 */
358
Note: See TracBrowser for help on using the repository browser.