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

Last change on this file since 824 was 819, checked in by Sam Hocevar, 15 years ago
  • More function mass-renaming: caca_attach -> caca_create_display, etc.
  • Property svn:keywords set to Id
File size: 10.0 KB
RevLine 
[35]1/*
[672]2 *  libcaca       Colour ASCII-Art library
[527]3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
[268]4 *                All Rights Reserved
[35]5 *
[769]6 *  $Id: driver_win32.c 819 2006-04-19 10:10:58Z sam $
7 *
[268]8 *  This library is free software; you can redistribute it and/or
[522]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.
[35]12 */
[17]13
[769]14/*
[540]15 *  This file contains the libcaca Win32 input and output driver
[205]16 */
17
[63]18#include "config.h"
19
[539]20#if defined(USE_WIN32)
21
22#include <windows.h>
23
[550]24#include <stdlib.h>
[632]25#include <stdio.h>
[550]26
[185]27#include "caca.h"
28#include "caca_internals.h"
[524]29#include "cucul.h"
30#include "cucul_internals.h"
[17]31
[247]32/*
33 * Global variables
34 */
35
[336]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};
[527]75
[550]76struct driver_private
77{
[632]78    HANDLE hin, hout, screen;
[550]79    CHAR_INFO *buffer;
80    CONSOLE_CURSOR_INFO cci;
81};
82
[811]83static int win32_init_graphics(caca_display_t *dp)
[227]84{
[539]85    CONSOLE_SCREEN_BUFFER_INFO csbi;
[632]86    SMALL_RECT rect;
[539]87    COORD size;
[348]88
[811]89    dp->drv.p = malloc(sizeof(struct driver_private));
[550]90
[539]91    /* This call is allowed to fail in case we already have a console */
92    AllocConsole();
[227]93
[811]94    dp->drv.p->hin = GetStdHandle(STD_INPUT_HANDLE);
95    dp->drv.p->hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
[550]96                                 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
97                                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
[811]98    if(dp->drv.p->hout == INVALID_HANDLE_VALUE)
[539]99        return -1;
[231]100
[811]101    GetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
102    dp->drv.p->cci.bVisible = FALSE;
103    SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
[227]104
[811]105    SetConsoleMode(dp->drv.p->hout, ENABLE_MOUSE_INPUT);
[227]106
[811]107    dp->drv.p->screen =
[539]108        CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
109                                  0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
[811]110    if(!dp->drv.p->screen || dp->drv.p->screen == INVALID_HANDLE_VALUE)
[539]111        return -1;
[227]112
[632]113    /* Set the new console size */
[811]114    size.X = dp->cv->width;
115    size.Y = dp->cv->height;
116    SetConsoleScreenBufferSize(dp->drv.p->screen, size);
[227]117
[632]118    rect.Left = rect.Top = 0;
[811]119    rect.Right = dp->cv->width - 1;
120    rect.Bottom = dp->cv->height - 1;
121    SetConsoleWindowInfo(dp->drv.p->screen, TRUE, &rect);
[632]122
123    /* Report our new size to libcucul */
[811]124    if(!GetConsoleScreenBufferInfo(dp->drv.p->screen, &csbi))
[539]125        return -1;
[227]126
[813]127    _cucul_set_canvas_size(dp->cv, csbi.srWindow.Right - csbi.srWindow.Left + 1,
128                           csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
[227]129
[811]130    SetConsoleMode(dp->drv.p->screen, 0);
[251]131
[811]132    GetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
133    dp->drv.p->cci.dwSize = 0;
134    dp->drv.p->cci.bVisible = FALSE;
135    SetConsoleCursorInfo(dp->drv.p->screen, &dp->drv.p->cci);
[261]136
[811]137    SetConsoleActiveScreenBuffer(dp->drv.p->screen);
[274]138
[811]139    dp->drv.p->buffer = malloc(dp->cv->width * dp->cv->height
[539]140                               * sizeof(CHAR_INFO));
[811]141    if(dp->drv.p->buffer == NULL)
[539]142        return -1;
[263]143
[227]144    return 0;
145}
146
[811]147static int win32_end_graphics(caca_display_t *dp)
[251]148{
[811]149    SetConsoleActiveScreenBuffer(dp->drv.p->hout);
150    CloseHandle(dp->drv.p->screen);
[300]151
[811]152    SetConsoleTextAttribute(dp->drv.p->hout, FOREGROUND_INTENSITY
[539]153                                             | FOREGROUND_RED
154                                             | FOREGROUND_GREEN
155                                             | FOREGROUND_BLUE);
[811]156    dp->drv.p->cci.bVisible = TRUE;
157    SetConsoleCursorInfo(dp->drv.p->hout, &dp->drv.p->cci);
158    CloseHandle(dp->drv.p->hout);
[539]159
[811]160    free(dp->drv.p);
[550]161
[251]162    return 0;
163}
164
[819]165static int win32_set_display_title(caca_display_t *dp, char const *title)
[343]166{
[539]167    SetConsoleTitle(title);
[343]168    return 0;
169}
170
[819]171static unsigned int win32_get_display_width(caca_display_t *dp)
[352]172{
[539]173    /* FIXME */
[352]174
175    /* Fallback to a 6x10 font */
[811]176    return dp->cv->width * 6;
[352]177}
178
[819]179static unsigned int win32_get_display_height(caca_display_t *dp)
[352]180{
[539]181    /* FIXME */
[352]182
183    /* Fallback to a 6x10 font */
[811]184    return dp->cv->height * 10;
[352]185}
186
[811]187static void win32_display(caca_display_t *dp)
[227]188{
[539]189    COORD size, pos;
190    SMALL_RECT rect;
191    unsigned int i;
[227]192
[632]193    /* Render everything to our screen buffer */
[811]194    for(i = 0; i < dp->cv->width * dp->cv->height; i++)
[265]195    {
[811]196        uint32_t ch = dp->cv->chars[i];
[557]197
[612]198#if 0
[811]199        if(ch > 0x00000020 && ch < 0x00000080)
200            dp->drv.p->buffer[i].Char.AsciiChar = (uint8_t)ch;
[557]201        else
[811]202            dp->drv.p->buffer[i].Char.AsciiChar = ' ';
[612]203#else
[811]204        if(ch > 0x00000020 && ch < 0x00010000)
205            dp->drv.p->buffer[i].Char.UnicodeChar = (uint16_t)ch;
[612]206        else
[811]207            dp->drv.p->buffer[i].Char.UnicodeChar = (uint16_t)' ';
[612]208#endif
[557]209
[811]210        dp->drv.p->buffer[i].Attributes =
211                win32_fg_palette[_cucul_argb32_to_ansi4fg(dp->cv->attr[i])]
212                 | win32_bg_palette[_cucul_argb32_to_ansi4bg(dp->cv->attr[i])];
[265]213    }
[261]214
[632]215    /* Blit the screen buffer */
[811]216    size.X = dp->cv->width;
217    size.Y = dp->cv->height;
[539]218    pos.X = pos.Y = 0;
219    rect.Left = rect.Top = 0;
[811]220    rect.Right = dp->cv->width - 1;
221    rect.Bottom = dp->cv->height - 1;
[612]222#if 0
[811]223    WriteConsoleOutput(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
[612]224#else
[811]225    WriteConsoleOutputW(dp->drv.p->screen, dp->drv.p->buffer, size, pos, &rect);
[612]226#endif
[227]227}
228
[811]229static void win32_handle_resize(caca_display_t *dp)
[347]230{
[553]231    /* FIXME: I don't know what to do here. */
[811]232    dp->resize.w = dp->cv->width;
233    dp->resize.h = dp->cv->height;
[347]234}
235
[811]236static int win32_get_event(caca_display_t *dp, caca_event_t *ev)
[548]237{
238    INPUT_RECORD rec;
239    DWORD num;
240
241    for( ; ; )
242    {
[811]243        GetNumberOfConsoleInputEvents(dp->drv.p->hin, &num);
[548]244        if(num == 0)
245            break;
246
[811]247        ReadConsoleInput(dp->drv.p->hin, &rec, 1, &num);
[548]248        if(rec.EventType == KEY_EVENT)
249        {
250            unsigned int event;
251
252            if(rec.Event.KeyEvent.bKeyDown)
[681]253                ev->type = CACA_EVENT_KEY_PRESS;
[548]254            else
[681]255                ev->type = CACA_EVENT_KEY_RELEASE;
[548]256
257            if(rec.Event.KeyEvent.uChar.AsciiChar)
[681]258            {
[810]259                ev->data.key.ch = rec.Event.KeyEvent.uChar.AsciiChar;
260                ev->data.key.ucs4 = (uint32_t)ev->data.key.ch;
261                ev->data.key.utf8[0] = ev->data.key.ch;
[681]262                ev->data.key.utf8[1] = '\0';
263
264                return 1;
265            }
[548]266        }
267
268        if(rec.EventType == MOUSE_EVENT)
269        {
270            if(rec.Event.MouseEvent.dwEventFlags == 0)
271            {
272                if(rec.Event.MouseEvent.dwButtonState & 0x01)
[681]273                {
274                    ev->type = CACA_EVENT_MOUSE_PRESS;
275                    ev->data.mouse.button = 1;
276                    return 1;
277                }
[548]278
279                if(rec.Event.MouseEvent.dwButtonState & 0x02)
[681]280                {
281                    ev->type = CACA_EVENT_MOUSE_PRESS;
282                    ev->data.mouse.button = 2;
283                    return 1;
284                }
[548]285            }
286            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
287            {
288                COORD pos = rec.Event.MouseEvent.dwMousePosition;
289
[811]290                if(dp->mouse.x == (unsigned int)pos.X &&
291                   dp->mouse.y == (unsigned int)pos.Y)
[548]292                    continue;
293
[811]294                dp->mouse.x = pos.X;
295                dp->mouse.y = pos.Y;
[548]296
[681]297                ev->type = CACA_EVENT_MOUSE_MOTION;
[811]298                ev->data.mouse.x = dp->mouse.x;
299                ev->data.mouse.y = dp->mouse.y;
[681]300                return 1;
[548]301            }
302#if 0
303            else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
304            {
305                cout << rec.Event.MouseEvent.dwMousePosition.X << "," <<
306                        rec.Event.MouseEvent.dwMousePosition.Y << "  " << flush;
307            }
308            else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
309            {
310                SetConsoleCursorPosition(hOut,
311                                         WheelWhere);
312                if(rec.Event.MouseEvent.dwButtonState & 0xFF000000)
313                    cout << "Down" << flush;
314                else
315                    cout << "Up  " << flush;
316            }
317#endif
318        }
319
320        /* Unknown event */
[681]321        ev->type = CACA_EVENT_NONE;
322        return 0;
[548]323    }
324
325    /* No event */
[681]326    ev->type = CACA_EVENT_NONE;
327    return 0;
[548]328}
329
[539]330/*
331 * Driver initialisation
332 */
[281]333
[811]334int win32_install(caca_display_t *dp)
[300]335{
[811]336    dp->drv.driver = CACA_DRIVER_WIN32;
[300]337
[811]338    dp->drv.init_graphics = win32_init_graphics;
339    dp->drv.end_graphics = win32_end_graphics;
[819]340    dp->drv.set_display_title = win32_set_display_title;
341    dp->drv.get_display_width = win32_get_display_width;
342    dp->drv.get_display_height = win32_get_display_height;
[811]343    dp->drv.display = win32_display;
344    dp->drv.handle_resize = win32_handle_resize;
345    dp->drv.get_event = win32_get_event;
346    dp->drv.set_mouse = NULL;
[684]347
348    return 0;
[348]349}
350
[539]351#endif /* USE_WIN32 */
[527]352
Note: See TracBrowser for help on using the repository browser.