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

Last change on this file since 599 was 582, checked in by Sam Hocevar, 14 years ago
  • Use the internal version of cucul_set_size in output drivers so that they can force a resize. We need to find a way to make those specific cucul - caca interactions unavailable to the clueless user.
  • Property svn:keywords set to Id
File size: 9.4 KB
RevLine 
[35]1/*
[268]2 *  libcaca       ASCII-Art library
[527]3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
[268]4 *                All Rights Reserved
[35]5 *
[268]6 *  This library is free software; you can redistribute it and/or
[522]7 *  modify it under the terms of the Do What The Fuck You Want To
8 *  Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
[35]10 */
[17]11
[540]12/** \file driver_win32.c
[268]13 *  \version \$Id: driver_win32.c 582 2006-03-10 10:01:22Z sam $
14 *  \author Sam Hocevar <sam@zoy.org>
[540]15 *  \brief Win32 driver
[205]16 *
[540]17 *  This file contains the libcaca Win32 input and output driver
[205]18 */
19
[63]20#include "config.h"
21
[539]22#if defined(USE_WIN32)
23
24#include <windows.h>
25
[550]26#include <stdlib.h>
27
[185]28#include "caca.h"
29#include "caca_internals.h"
[524]30#include "cucul.h"
31#include "cucul_internals.h"
[17]32
[247]33/*
34 * Global variables
35 */
36
[336]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};
[527]76
[550]77struct driver_private
78{
79    HANDLE hin, hout;
80    HANDLE front, back;
81    CHAR_INFO *buffer;
82    CONSOLE_CURSOR_INFO cci;
83};
84
[540]85static int win32_init_graphics(caca_t *kk)
[227]86{
[539]87    CONSOLE_SCREEN_BUFFER_INFO csbi;
88    COORD size;
[348]89
[550]90    kk->drv.p = malloc(sizeof(struct driver_private));
91
[539]92    /* This call is allowed to fail in case we already have a console */
93    AllocConsole();
[227]94
[550]95    kk->drv.p->hin = GetStdHandle(STD_INPUT_HANDLE);
96    kk->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(kk->drv.p->hout == INVALID_HANDLE_VALUE)
[539]100        return -1;
[231]101
[550]102    GetConsoleCursorInfo(kk->drv.p->hout, &kk->drv.p->cci);
103    kk->drv.p->cci.bVisible = FALSE;
104    SetConsoleCursorInfo(kk->drv.p->hout, &kk->drv.p->cci);
[227]105
[550]106    SetConsoleMode(kk->drv.p->hout, ENABLE_MOUSE_INPUT);
[227]107
[550]108    kk->drv.p->front =
[539]109        CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
110                                  0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
[550]111    if(!kk->drv.p->front || kk->drv.p->front == INVALID_HANDLE_VALUE)
[539]112        return -1;
[227]113
[550]114    kk->drv.p->back =
[539]115        CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
116                                  0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
[550]117    if(!kk->drv.p->back || kk->drv.p->back == INVALID_HANDLE_VALUE)
[539]118        return -1;
[227]119
[550]120    if(!GetConsoleScreenBufferInfo(kk->drv.p->hout, &csbi))
[539]121        return -1;
[227]122
[539]123    /* Sample code to get the biggest possible window */
[550]124    //size = GetLargestConsoleWindowSize(kk->drv.p->hout);
[582]125    _cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1,
126                            csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
[539]127    size.X = kk->qq->width;
128    size.Y = kk->qq->height;
[550]129    SetConsoleScreenBufferSize(kk->drv.p->front, size);
130    SetConsoleScreenBufferSize(kk->drv.p->back, size);
[227]131
[550]132    SetConsoleMode(kk->drv.p->front, 0);
133    SetConsoleMode(kk->drv.p->back, 0);
[251]134
[550]135    GetConsoleCursorInfo(kk->drv.p->front, &kk->drv.p->cci);
136    kk->drv.p->cci.dwSize = 0;
137    kk->drv.p->cci.bVisible = FALSE;
138    SetConsoleCursorInfo(kk->drv.p->front, &kk->drv.p->cci);
139    SetConsoleCursorInfo(kk->drv.p->back, &kk->drv.p->cci);
[261]140
[550]141    SetConsoleActiveScreenBuffer(kk->drv.p->front);
[274]142
[550]143    kk->drv.p->buffer = malloc(kk->qq->width * kk->qq->height
[539]144                               * sizeof(CHAR_INFO));
[550]145    if(kk->drv.p->buffer == NULL)
[539]146        return -1;
[263]147
[227]148    return 0;
149}
150
[540]151static int win32_end_graphics(caca_t *kk)
[251]152{
[550]153    SetConsoleActiveScreenBuffer(kk->drv.p->hout);
154    CloseHandle(kk->drv.p->back);
155    CloseHandle(kk->drv.p->front);
[300]156
[550]157    SetConsoleTextAttribute(kk->drv.p->hout, FOREGROUND_INTENSITY
[539]158                                             | FOREGROUND_RED
159                                             | FOREGROUND_GREEN
160                                             | FOREGROUND_BLUE);
[550]161    kk->drv.p->cci.bVisible = TRUE;
162    SetConsoleCursorInfo(kk->drv.p->hout, &kk->drv.p->cci);
163    CloseHandle(kk->drv.p->hout);
[539]164
[550]165    free(kk->drv.p);
166
[251]167    return 0;
168}
169
[540]170static int win32_set_window_title(caca_t *kk, char const *title)
[343]171{
[539]172    SetConsoleTitle(title);
[343]173    return 0;
174}
175
[540]176static unsigned int win32_get_window_width(caca_t *kk)
[352]177{
[539]178    /* FIXME */
[352]179
180    /* Fallback to a 6x10 font */
[524]181    return kk->qq->width * 6;
[352]182}
183
[540]184static unsigned int win32_get_window_height(caca_t *kk)
[352]185{
[539]186    /* FIXME */
[352]187
188    /* Fallback to a 6x10 font */
[524]189    return kk->qq->height * 10;
[352]190}
191
[540]192static void win32_display(caca_t *kk)
[227]193{
[539]194    COORD size, pos;
195    SMALL_RECT rect;
196    unsigned int i;
[227]197
[539]198    /* Render everything to our back buffer */
199    for(i = 0; i < kk->qq->width * kk->qq->height; i++)
[265]200    {
[557]201        uint32_t c = kk->qq->chars[i];
202
203        if(c > 0x00000020 && c < 0x00000080)
204            kk->drv.p->buffer[i].Char.AsciiChar = (char)c;
205        else
206            kk->drv.p->buffer[i].Char.AsciiChar = ' ';
207
[550]208        kk->drv.p->buffer[i].Attributes =
[539]209                win32_fg_palette[kk->qq->attr[i] & 0xf]
210                 | win32_bg_palette[kk->qq->attr[i] >> 4];
[265]211    }
[261]212
[539]213    /* Blit the back buffer to the front buffer */
214    size.X = kk->qq->width;
215    size.Y = kk->qq->height;
216    pos.X = pos.Y = 0;
217    rect.Left = rect.Top = 0;
218    rect.Right = kk->qq->width - 1;
219    rect.Bottom = kk->qq->height - 1;
[550]220    WriteConsoleOutput(kk->drv.p->front, kk->drv.p->buffer, size, pos, &rect);
[227]221}
222
[553]223static void win32_handle_resize(caca_t *kk)
[347]224{
[553]225    /* FIXME: I don't know what to do here. */
226    kk->resize.w = kk->qq->width;
227    kk->resize.h = kk->qq->height;
[347]228}
229
[548]230static unsigned int win32_get_event(caca_t *kk)
231{
232    INPUT_RECORD rec;
233    DWORD num;
234
235    for( ; ; )
236    {
[550]237        GetNumberOfConsoleInputEvents(kk->drv.p->hin, &num);
[548]238        if(num == 0)
239            break;
240
[550]241        ReadConsoleInput(kk->drv.p->hin, &rec, 1, &num);
[548]242        if(rec.EventType == KEY_EVENT)
243        {
244            unsigned int event;
245
246            if(rec.Event.KeyEvent.bKeyDown)
247                event = CACA_EVENT_KEY_PRESS;
248            else
249                event = CACA_EVENT_KEY_RELEASE;
250
251            if(rec.Event.KeyEvent.uChar.AsciiChar)
252                return event | rec.Event.KeyEvent.uChar.AsciiChar;
253        }
254
255        if(rec.EventType == MOUSE_EVENT)
256        {
257            if(rec.Event.MouseEvent.dwEventFlags == 0)
258            {
259                if(rec.Event.MouseEvent.dwButtonState & 0x01)
260                    return CACA_EVENT_MOUSE_PRESS | 0x000001;
261
262                if(rec.Event.MouseEvent.dwButtonState & 0x02)
263                    return CACA_EVENT_MOUSE_PRESS | 0x000002;
264            }
265            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
266            {
267                COORD pos = rec.Event.MouseEvent.dwMousePosition;
268
[551]269                if(kk->mouse.x == (unsigned int)pos.X &&
270                   kk->mouse.y == (unsigned int)pos.Y)
[548]271                    continue;
272
[551]273                kk->mouse.x = pos.X;
274                kk->mouse.y = pos.Y;
[548]275
[551]276                return CACA_EVENT_MOUSE_MOTION
277                        | (kk->mouse.x << 12) | kk->mouse.y;
[548]278            }
279#if 0
280            else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
281            {
282                cout << rec.Event.MouseEvent.dwMousePosition.X << "," <<
283                        rec.Event.MouseEvent.dwMousePosition.Y << "  " << flush;
284            }
285            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
286            {
287                SetConsoleCursorPosition(hOut,
288                                         WheelWhere);
289                if(rec.Event.MouseEvent.dwButtonState & 0xFF000000)
290                    cout << "Down" << flush;
291                else
292                    cout << "Up  " << flush;
293            }
294#endif
295        }
296
297        /* Unknown event */
298        return CACA_EVENT_NONE;
299    }
300
301    /* No event */
302    return CACA_EVENT_NONE;
303}
304
[539]305/*
306 * Driver initialisation
307 */
[281]308
[539]309void win32_init_driver(caca_t *kk)
[300]310{
[550]311    kk->drv.driver = CACA_DRIVER_WIN32;
[300]312
[550]313    kk->drv.init_graphics = win32_init_graphics;
314    kk->drv.end_graphics = win32_end_graphics;
315    kk->drv.set_window_title = win32_set_window_title;
316    kk->drv.get_window_width = win32_get_window_width;
317    kk->drv.get_window_height = win32_get_window_height;
318    kk->drv.display = win32_display;
319    kk->drv.handle_resize = win32_handle_resize;
320    kk->drv.get_event = win32_get_event;
[348]321}
322
[539]323#endif /* USE_WIN32 */
[527]324
Note: See TracBrowser for help on using the repository browser.