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

Last change on this file since 2299 was 2299, checked in by Sam Hocevar, 12 years ago
  • Remove #include <stdint.h> etc. from "common.h". Instead, make sure that <cucul.h> will provide the C99 types, even if libcaca has been installed.
  • Rename what's left of "common.h" to "stubs.h".
  • Remove all references to erroneous <inttypes.h> from source files.
  • Property svn:keywords set to Id
File size: 10.8 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 2299 2008-04-19 12:42:50Z 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 "cucul.h"
29#include "caca.h"
30#include "caca_internals.h"
31
32/*
33 * Global variables
34 */
35
36static int const win32_fg_palette[] =
37{
38    0,
39    FOREGROUND_BLUE,
40    FOREGROUND_GREEN,
41    FOREGROUND_GREEN | FOREGROUND_BLUE,
42    FOREGROUND_RED,
43    FOREGROUND_RED | FOREGROUND_BLUE,
44    FOREGROUND_RED | FOREGROUND_GREEN,
45    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
46    FOREGROUND_INTENSITY,
47    FOREGROUND_INTENSITY | FOREGROUND_BLUE,
48    FOREGROUND_INTENSITY | FOREGROUND_GREEN,
49    FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
50    FOREGROUND_INTENSITY | FOREGROUND_RED,
51    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
52    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
53    FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
54};
55
56static int const win32_bg_palette[] =
57{
58    0,
59    BACKGROUND_BLUE,
60    BACKGROUND_GREEN,
61    BACKGROUND_GREEN | BACKGROUND_BLUE,
62    BACKGROUND_RED,
63    BACKGROUND_RED | BACKGROUND_BLUE,
64    BACKGROUND_RED | BACKGROUND_GREEN,
65    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
66    BACKGROUND_INTENSITY,
67    BACKGROUND_INTENSITY | BACKGROUND_BLUE,
68    BACKGROUND_INTENSITY | BACKGROUND_GREEN,
69    BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
70    BACKGROUND_INTENSITY | BACKGROUND_RED,
71    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
72    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
73    BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
74};
75
76struct driver_private
77{
78    HANDLE hin, hout, screen;
79    CHAR_INFO *buffer;
80    CONSOLE_CURSOR_INFO cci;
81};
82
83static int win32_init_graphics(caca_display_t *dp)
84{
85    unsigned int width = cucul_get_canvas_width(dp->cv);
86    unsigned int height = cucul_get_canvas_height(dp->cv);
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 = width ? width : 80;
117    size.Y = height ? height : 25;
118    SetConsoleScreenBufferSize(dp->drv.p->screen, size);
119
120    rect.Left = rect.Top = 0;
121    rect.Right = size.X - 1;
122    rect.Bottom = size.Y - 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    dp->resize.allow = 1;
130    cucul_set_canvas_size(dp->cv,
131                          csbi.srWindow.Right - csbi.srWindow.Left + 1,
132                          csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
133    width = cucul_get_canvas_width(dp->cv);
134    height = cucul_get_canvas_height(dp->cv);
135    dp->resize.allow = 0;
136
137    SetConsoleMode(dp->drv.p->screen, 0);
138
139    GetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
140    dp->drv.p->cci.dwSize = 0;
141    dp->drv.p->cci.bVisible = FALSE;
142    SetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
143
144    SetConsoleActiveScreenBuffer(dp->drv.p->screen);
145
146    dp->drv.p->buffer = malloc(width * height
147                               * sizeof(CHAR_INFO));
148    if(dp->drv.p->buffer == NULL)
149        return -1;
150
151    return 0;
152}
153
154static int win32_end_graphics(caca_display_t *dp)
155{
156    SetConsoleActiveScreenBuffer(dp->drv.p->hout);
157    CloseHandle(dp->drv.p->screen);
158
159    SetConsoleTextAttribute(dp->drv.p->hout, FOREGROUND_INTENSITY
160                                             | FOREGROUND_RED
161                                             | FOREGROUND_GREEN
162                                             | FOREGROUND_BLUE);
163    dp->drv.p->cci.bVisible = TRUE;
164    SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
165    CloseHandle(dp->drv.p->hout);
166
167    free(dp->drv.p);
168
169    return 0;
170}
171
172static int win32_set_display_title(caca_display_t *dp, char const *title)
173{
174    SetConsoleTitle(title);
175    return 0;
176}
177
178static unsigned int win32_get_display_width(caca_display_t const *dp)
179{
180    /* FIXME */
181
182    /* Fallback to a 6x10 font */
183    return cucul_get_canvas_width(dp->cv) * 6;
184}
185
186static unsigned int win32_get_display_height(caca_display_t const *dp)
187{
188    /* FIXME */
189
190    /* Fallback to a 6x10 font */
191    return cucul_get_canvas_height(dp->cv) * 10;
192}
193
194static void win32_display(caca_display_t *dp)
195{
196    COORD size, pos;
197    SMALL_RECT rect;
198    CHAR_INFO *buffer = dp->drv.p->buffer;
199    uint32_t const *cvchars = (uint32_t const *)cucul_get_canvas_chars(dp->cv);
200    uint32_t const *cvattrs = (uint32_t const *)cucul_get_canvas_attrs(dp->cv);
201    unsigned int width = cucul_get_canvas_width(dp->cv);
202    unsigned int height = cucul_get_canvas_height(dp->cv);
203    unsigned int n;
204
205    /* Render everything to our screen buffer */
206    for(n = height * width; n--; )
207    {
208        uint32_t ch = *cvchars++;
209        uint8_t fg = cucul_attr_to_ansi_fg(*cvattrs);
210        uint8_t bg = cucul_attr_to_ansi_bg(*cvattrs);
211
212#if 0
213        if(ch > 0x00000020 && ch < 0x00000080)
214            dp->drv.p->buffer[i].Char.AsciiChar = (uint8_t)ch;
215        else
216            dp->drv.p->buffer[i].Char.AsciiChar = ' ';
217#else
218        if(n && *cvchars == CUCUL_MAGIC_FULLWIDTH)
219            ;
220        else if(ch > 0x00000020 && ch < 0x00010000)
221            buffer->Char.UnicodeChar = (uint16_t)ch;
222        else
223            buffer->Char.UnicodeChar = (uint16_t)' ';
224#endif
225
226        buffer->Attributes = win32_fg_palette[fg < 0x10 ? fg : CUCUL_LIGHTGRAY]
227                              | win32_bg_palette[bg < 0x10 ? bg : CUCUL_BLACK];
228        cvattrs++;
229        buffer++;
230    }
231
232    /* Blit the screen buffer */
233    size.X = width;
234    size.Y = height;
235    pos.X = pos.Y = 0;
236    rect.Left = rect.Top = 0;
237    rect.Right = width - 1;
238    rect.Bottom = height - 1;
239#if 0
240    WriteConsoleOutput(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
241#else
242    WriteConsoleOutputW(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
243#endif
244}
245
246static void win32_handle_resize(caca_display_t *dp)
247{
248    /* FIXME: I don't know what to do here. */
249    dp->resize.w = cucul_get_canvas_width(dp->cv);
250    dp->resize.h = cucul_get_canvas_height(dp->cv);
251}
252
253static int win32_get_event(caca_display_t *dp, caca_privevent_t *ev)
254{
255    INPUT_RECORD rec;
256    DWORD num;
257
258    for( ; ; )
259    {
260        GetNumberOfConsoleInputEvents(dp->drv.p->hin, &num);
261        if(num == 0)
262            break;
263
264        ReadConsoleInput(dp->drv.p->hin, &rec, 1, &num);
265        if(rec.EventType == KEY_EVENT)
266        {
267            if(rec.Event.KeyEvent.bKeyDown)
268                ev->type = CACA_EVENT_KEY_PRESS;
269            else
270                ev->type = CACA_EVENT_KEY_RELEASE;
271
272            if(rec.Event.KeyEvent.uChar.AsciiChar)
273            {
274                ev->data.key.ch = rec.Event.KeyEvent.uChar.AsciiChar;
275                ev->data.key.utf32 = (uint32_t)ev->data.key.ch;
276                ev->data.key.utf8[0] = ev->data.key.ch;
277                ev->data.key.utf8[1] = '\0';
278
279                return 1;
280            }
281        }
282
283        if(rec.EventType == MOUSE_EVENT)
284        {
285            if(rec.Event.MouseEvent.dwEventFlags == 0)
286            {
287                if(rec.Event.MouseEvent.dwButtonState & 0x01)
288                {
289                    ev->type = CACA_EVENT_MOUSE_PRESS;
290                    ev->data.mouse.button = 1;
291                    return 1;
292                }
293
294                if(rec.Event.MouseEvent.dwButtonState & 0x02)
295                {
296                    ev->type = CACA_EVENT_MOUSE_PRESS;
297                    ev->data.mouse.button = 2;
298                    return 1;
299                }
300            }
301            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
302            {
303                COORD pos = rec.Event.MouseEvent.dwMousePosition;
304
305                if(dp->mouse.x == (unsigned int)pos.X &&
306                   dp->mouse.y == (unsigned int)pos.Y)
307                    continue;
308
309                dp->mouse.x = pos.X;
310                dp->mouse.y = pos.Y;
311
312                ev->type = CACA_EVENT_MOUSE_MOTION;
313                ev->data.mouse.x = dp->mouse.x;
314                ev->data.mouse.y = dp->mouse.y;
315                return 1;
316            }
317#if 0
318            else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
319            {
320                cout << rec.Event.MouseEvent.dwMousePosition.X << "," <<
321                        rec.Event.MouseEvent.dwMousePosition.Y << "  " << flush;
322            }
323            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
324            {
325                SetConsoleCursorPosition(hOut,
326                                         WheelWhere);
327                if(rec.Event.MouseEvent.dwButtonState & 0xFF000000)
328                    cout << "Down" << flush;
329                else
330                    cout << "Up  " << flush;
331            }
332#endif
333        }
334
335        /* Unknown event */
336        ev->type = CACA_EVENT_NONE;
337        return 0;
338    }
339
340    /* No event */
341    ev->type = CACA_EVENT_NONE;
342    return 0;
343}
344
345/*
346 * Driver initialisation
347 */
348
349int win32_install(caca_display_t *dp)
350{
351    dp->drv.id = CACA_DRIVER_WIN32;
352    dp->drv.driver = "win32";
353
354    dp->drv.init_graphics = win32_init_graphics;
355    dp->drv.end_graphics = win32_end_graphics;
356    dp->drv.set_display_title = win32_set_display_title;
357    dp->drv.get_display_width = win32_get_display_width;
358    dp->drv.get_display_height = win32_get_display_height;
359    dp->drv.display = win32_display;
360    dp->drv.handle_resize = win32_handle_resize;
361    dp->drv.get_event = win32_get_event;
362    dp->drv.set_mouse = NULL;
363    dp->drv.set_cursor = NULL;
364
365    return 0;
366}
367
368#endif /* USE_WIN32 */
369
Note: See TracBrowser for help on using the repository browser.