~ubuntu-branches/ubuntu/gutsy/libcaca/gutsy

« back to all changes in this revision

Viewing changes to caca/driver_win32.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hocevar (Debian packages)
  • Date: 2006-12-03 02:05:11 UTC
  • mfrom: (3.1.6 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203020511-h5nzqgf8nov7ns3z
Tags: 0.99.beta11.debian-2
Remove toilet from caca-utils now that it has entered testing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 1011 2006-11-11 08:44:14Z 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
 
 
37
static 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
 
 
57
static 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
 
 
77
struct driver_private
 
78
{
 
79
    HANDLE hin, hout, screen;
 
80
    CHAR_INFO *buffer;
 
81
    CONSOLE_CURSOR_INFO cci;
 
82
};
 
83
 
 
84
static 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
 
 
148
static 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
 
 
166
static int win32_set_display_title(caca_display_t *dp, char const *title)
 
167
{
 
168
    SetConsoleTitle(title);
 
169
    return 0;
 
170
}
 
171
 
 
172
static 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
 
 
180
static 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
 
 
188
static 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 *attrs = dp->cv->attrs;
 
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
        uint8_t fg = cucul_attr_to_ansi_fg(*attrs);
 
202
        uint8_t bg = cucul_attr_to_ansi_bg(*attrs);
 
203
 
 
204
#if 0
 
205
        if(ch > 0x00000020 && ch < 0x00000080)
 
206
            dp->drv.p->buffer[i].Char.AsciiChar = (uint8_t)ch;
 
207
        else
 
208
            dp->drv.p->buffer[i].Char.AsciiChar = ' ';
 
209
#else
 
210
        if(n && *chars == CUCUL_MAGIC_FULLWIDTH)
 
211
            ;
 
212
        else if(ch > 0x00000020 && ch < 0x00010000)
 
213
            buffer->Char.UnicodeChar = (uint16_t)ch;
 
214
        else
 
215
            buffer->Char.UnicodeChar = (uint16_t)' ';
 
216
#endif
 
217
 
 
218
        buffer->Attributes = win32_fg_palette[fg < 0x10 ? fg : CUCUL_LIGHTGRAY]
 
219
                              | win32_bg_palette[bg < 0x10 ? bg : CUCUL_BLACK];
 
220
        attrs++;
 
221
        buffer++;
 
222
    }
 
223
 
 
224
    /* Blit the screen buffer */
 
225
    size.X = dp->cv->width;
 
226
    size.Y = dp->cv->height;
 
227
    pos.X = pos.Y = 0;
 
228
    rect.Left = rect.Top = 0;
 
229
    rect.Right = dp->cv->width - 1;
 
230
    rect.Bottom = dp->cv->height - 1;
 
231
#if 0
 
232
    WriteConsoleOutput(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
 
233
#else
 
234
    WriteConsoleOutputW(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
 
235
#endif
 
236
}
 
237
 
 
238
static void win32_handle_resize(caca_display_t *dp)
 
239
{
 
240
    /* FIXME: I don't know what to do here. */
 
241
    dp->resize.w = dp->cv->width;
 
242
    dp->resize.h = dp->cv->height;
 
243
}
 
244
 
 
245
static int win32_get_event(caca_display_t *dp, caca_event_t *ev)
 
246
{
 
247
    INPUT_RECORD rec;
 
248
    DWORD num;
 
249
 
 
250
    for( ; ; )
 
251
    {
 
252
        GetNumberOfConsoleInputEvents(dp->drv.p->hin, &num);
 
253
        if(num == 0)
 
254
            break;
 
255
 
 
256
        ReadConsoleInput(dp->drv.p->hin, &rec, 1, &num);
 
257
        if(rec.EventType == KEY_EVENT)
 
258
        {
 
259
            if(rec.Event.KeyEvent.bKeyDown)
 
260
                ev->type = CACA_EVENT_KEY_PRESS;
 
261
            else
 
262
                ev->type = CACA_EVENT_KEY_RELEASE;
 
263
 
 
264
            if(rec.Event.KeyEvent.uChar.AsciiChar)
 
265
            {
 
266
                ev->data.key.ch = rec.Event.KeyEvent.uChar.AsciiChar;
 
267
                ev->data.key.utf32 = (uint32_t)ev->data.key.ch;
 
268
                ev->data.key.utf8[0] = ev->data.key.ch;
 
269
                ev->data.key.utf8[1] = '\0';
 
270
 
 
271
                return 1;
 
272
            }
 
273
        }
 
274
 
 
275
        if(rec.EventType == MOUSE_EVENT)
 
276
        {
 
277
            if(rec.Event.MouseEvent.dwEventFlags == 0)
 
278
            {
 
279
                if(rec.Event.MouseEvent.dwButtonState & 0x01)
 
280
                {
 
281
                    ev->type = CACA_EVENT_MOUSE_PRESS;
 
282
                    ev->data.mouse.button = 1;
 
283
                    return 1;
 
284
                }
 
285
 
 
286
                if(rec.Event.MouseEvent.dwButtonState & 0x02)
 
287
                {
 
288
                    ev->type = CACA_EVENT_MOUSE_PRESS;
 
289
                    ev->data.mouse.button = 2;
 
290
                    return 1;
 
291
                }
 
292
            }
 
293
            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
 
294
            {
 
295
                COORD pos = rec.Event.MouseEvent.dwMousePosition;
 
296
 
 
297
                if(dp->mouse.x == (unsigned int)pos.X &&
 
298
                   dp->mouse.y == (unsigned int)pos.Y)
 
299
                    continue;
 
300
 
 
301
                dp->mouse.x = pos.X;
 
302
                dp->mouse.y = pos.Y;
 
303
 
 
304
                ev->type = CACA_EVENT_MOUSE_MOTION;
 
305
                ev->data.mouse.x = dp->mouse.x;
 
306
                ev->data.mouse.y = dp->mouse.y;
 
307
                return 1;
 
308
            }
 
309
#if 0
 
310
            else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
 
311
            {
 
312
                cout << rec.Event.MouseEvent.dwMousePosition.X << "," <<
 
313
                        rec.Event.MouseEvent.dwMousePosition.Y << "  " << flush;
 
314
            }
 
315
            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
 
316
            {
 
317
                SetConsoleCursorPosition(hOut,
 
318
                                         WheelWhere);
 
319
                if(rec.Event.MouseEvent.dwButtonState & 0xFF000000)
 
320
                    cout << "Down" << flush;
 
321
                else
 
322
                    cout << "Up  " << flush;
 
323
            }
 
324
#endif
 
325
        }
 
326
 
 
327
        /* Unknown event */
 
328
        ev->type = CACA_EVENT_NONE;
 
329
        return 0;
 
330
    }
 
331
 
 
332
    /* No event */
 
333
    ev->type = CACA_EVENT_NONE;
 
334
    return 0;
 
335
}
 
336
 
 
337
/*
 
338
 * Driver initialisation
 
339
 */
 
340
 
 
341
int win32_install(caca_display_t *dp)
 
342
{
 
343
    dp->drv.driver = CACA_DRIVER_WIN32;
 
344
 
 
345
    dp->drv.init_graphics = win32_init_graphics;
 
346
    dp->drv.end_graphics = win32_end_graphics;
 
347
    dp->drv.set_display_title = win32_set_display_title;
 
348
    dp->drv.get_display_width = win32_get_display_width;
 
349
    dp->drv.get_display_height = win32_get_display_height;
 
350
    dp->drv.display = win32_display;
 
351
    dp->drv.handle_resize = win32_handle_resize;
 
352
    dp->drv.get_event = win32_get_event;
 
353
    dp->drv.set_mouse = NULL;
 
354
 
 
355
    return 0;
 
356
}
 
357
 
 
358
#endif /* USE_WIN32 */
 
359