diff --git a/NOTES b/NOTES index 9b0abda..160df04 100644 --- a/NOTES +++ b/NOTES @@ -193,5 +193,6 @@ $Id$ o MS-DOS: all bright colours, bright backgrounds, and bright combinations work using . No need to kludge anything. - o Win32: we use GetConsoleScreenBufferInfo etc. + o Win32: we use GetConsoleScreenBufferInfo etc. There is an interesting + tutorial here: http://www.adrianxw.dk/SoftwareSite/index.html diff --git a/examples/cacaview.c b/examples/cacaview.c index 0e61d97..44ac0f7 100644 --- a/examples/cacaview.c +++ b/examples/cacaview.c @@ -34,6 +34,10 @@ # include #endif +#if defined(HAVE_SLEEP) +# include +#endif + #include "caca.h" /* Local macros */ @@ -256,7 +260,11 @@ int main(int argc, char **argv) if(!update) { +#if defined(HAVE_USLEEP) usleep(10000); +#elif defined(HAVE_SLEEP) + Sleep(10); +#endif continue; } diff --git a/src/caca.c b/src/caca.c index 414fc7c..51a07bd 100644 --- a/src/caca.c +++ b/src/caca.c @@ -70,6 +70,10 @@ enum caca_driver _caca_driver; static mmask_t oldmask; #endif +#if defined(USE_WIN32) +static CONSOLE_CURSOR_INFO cci; +#endif + /** \brief Initialise \e libcaca. * * This function initialises internal \e libcaca structures and the backend @@ -168,8 +172,19 @@ int caca_init(void) #if defined(USE_WIN32) if(_caca_driver == CACA_DRIVER_WIN32) { - /* Nothing to do */ - printf("initialising win32 driver\n"); + win32_hin = GetStdHandle(STD_INPUT_HANDLE); + win32_hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if(win32_hout == INVALID_HANDLE_VALUE) + return -1; + + GetConsoleCursorInfo(win32_hout, &cci); + cci.bVisible = FALSE; + SetConsoleCursorInfo(win32_hout, &cci); + + SetConsoleMode(win32_hout, ENABLE_MOUSE_INPUT); } else #endif @@ -391,7 +406,13 @@ void caca_end(void) #if defined(USE_WIN32) if(_caca_driver == CACA_DRIVER_WIN32) { - /* Nothing to do */ + SetConsoleTextAttribute(win32_hout, FOREGROUND_INTENSITY + | FOREGROUND_RED + | FOREGROUND_GREEN + | FOREGROUND_BLUE); + cci.bVisible = TRUE; + SetConsoleCursorInfo(win32_hout, &cci); + CloseHandle(win32_hout); } else #endif diff --git a/src/caca_internals.h b/src/caca_internals.h index 5bd9e06..66e1866 100644 --- a/src/caca_internals.h +++ b/src/caca_internals.h @@ -86,4 +86,9 @@ extern Window x11_window; extern int x11_font_width, x11_font_height; #endif +#if defined(USE_WIN32) +#include +extern HANDLE win32_hin, win32_hout; +#endif + #endif /* __CACA_INTERNALS_H__ */ diff --git a/src/graphics.c b/src/graphics.c index c4ab587..1bd29af 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -51,6 +51,9 @@ # include # endif #endif +#if defined(USE_WIN32) +# include +#endif #if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME) # include @@ -61,6 +64,7 @@ typedef unsigned char uint8_t; #include /* BUFSIZ */ #include #include +#include #include #include "caca.h" @@ -161,6 +165,53 @@ static Bool x11_detect_autorepeat; #endif #endif +#if defined(USE_WIN32) +static uint8_t *win32_char, *win32_attr; +HANDLE win32_hin, win32_hout; +static HANDLE win32_front, win32_back; +static CHAR_INFO *win32_buffer; + +static int const win32_fg_palette[] = +{ + 0, + FOREGROUND_BLUE, + FOREGROUND_GREEN, + FOREGROUND_GREEN | FOREGROUND_BLUE, + FOREGROUND_RED, + FOREGROUND_RED | FOREGROUND_BLUE, + FOREGROUND_RED | FOREGROUND_GREEN, + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, + FOREGROUND_INTENSITY, + FOREGROUND_INTENSITY | FOREGROUND_BLUE, + FOREGROUND_INTENSITY | FOREGROUND_GREEN, + FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE, + FOREGROUND_INTENSITY | FOREGROUND_RED, + FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE, + FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN, + FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE +}; + +static int const win32_bg_palette[] = +{ + 0, + BACKGROUND_BLUE, + BACKGROUND_GREEN, + BACKGROUND_GREEN | BACKGROUND_BLUE, + BACKGROUND_RED, + BACKGROUND_RED | BACKGROUND_BLUE, + BACKGROUND_RED | BACKGROUND_GREEN, + BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE, + BACKGROUND_INTENSITY, + BACKGROUND_INTENSITY | BACKGROUND_BLUE, + BACKGROUND_INTENSITY | BACKGROUND_GREEN, + BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE, + BACKGROUND_INTENSITY | BACKGROUND_RED, + BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE, + BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN, + BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE +}; +#endif + static char *_caca_empty_line; static char *_caca_scratch_line; @@ -244,7 +295,12 @@ void caca_set_color(enum caca_color fgcolor, enum caca_color bgcolor) #endif #if defined(USE_X11) case CACA_DRIVER_X11: - /* FIXME */ + /* Nothing to do */ + break; +#endif +#if defined(USE_WIN32) + case CACA_DRIVER_WIN32: + /* Nothing to do */ break; #endif default: @@ -326,6 +382,12 @@ void caca_putchar(int x, int y, char c) x11_char[x + y * _caca_width] = c; x11_attr[x + y * _caca_width] = (_caca_bgcolor << 4) | _caca_fgcolor; break; +#endif +#if defined(USE_WIN32) + case CACA_DRIVER_WIN32: + win32_char[x + y * _caca_width] = c; + win32_attr[x + y * _caca_width] = (_caca_bgcolor << 4) | _caca_fgcolor; + break; #endif default: break; @@ -345,10 +407,10 @@ void caca_putchar(int x, int y, char c) */ void caca_putstr(int x, int y, char const *s) { -#if defined(USE_CONIO) | defined(USE_X11) +#if defined(USE_CONIO) | defined(USE_X11) | defined(USE_WIN32) char *charbuf; #endif -#if defined(USE_X11) +#if defined(USE_X11) | defined(USE_WIN32) char *attrbuf; #endif unsigned int len; @@ -414,6 +476,17 @@ void caca_putstr(int x, int y, char const *s) *attrbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor; } break; +#endif +#if defined(USE_WIN32) + case CACA_DRIVER_WIN32: + charbuf = win32_char + x + y * _caca_width; + attrbuf = win32_attr + x + y * _caca_width; + while(*s) + { + *charbuf++ = *s++; + *attrbuf++ = (_caca_bgcolor << 4) | _caca_fgcolor; + } + break; #endif default: break; @@ -734,6 +807,64 @@ int _caca_init_graphics(void) DefaultScreen(x11_dpy))); } else +#endif +#if defined(USE_WIN32) + if(_caca_driver == CACA_DRIVER_WIN32) + { + CONSOLE_CURSOR_INFO cci; + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD size; + + win32_front = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + if(!win32_front) + return -1; + + win32_back = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + if(!win32_back) + return -1; + + if(!GetConsoleScreenBufferInfo(win32_hout, &csbi)) + return -1; + + _caca_width = csbi.srWindow.Right - csbi.srWindow.Left + 1; + _caca_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + + size.X = _caca_width; + size.Y = _caca_height; + SetConsoleScreenBufferSize(win32_front, size); + SetConsoleScreenBufferSize(win32_back, size); + + SetConsoleMode(win32_front, 0); + SetConsoleMode(win32_back, 0); + + GetConsoleCursorInfo(win32_front, &cci); + cci.bVisible = FALSE; + SetConsoleCursorInfo(win32_front, &cci); + SetConsoleCursorInfo(win32_back, &cci); + + SetConsoleActiveScreenBuffer(win32_front); + + win32_char = malloc(_caca_width * _caca_height * sizeof(int)); + if(win32_char == NULL) + return -1; + + win32_attr = malloc(_caca_width * _caca_height * sizeof(int)); + if(win32_attr == NULL) + { + free(win32_char); + return -1; + } + +win32_buffer = malloc(sizeof(CHAR_INFO) * _caca_width * _caca_height); + + memset(win32_char, 0, _caca_width * _caca_height * sizeof(int)); + memset(win32_attr, 0, _caca_width * _caca_height * sizeof(int)); + } + else #endif { /* Dummy */ @@ -784,6 +915,17 @@ int _caca_end_graphics(void) free(x11_attr); } else +#endif +#if defined(USE_WIN32) + if(_caca_driver == CACA_DRIVER_WIN32) + { + SetConsoleActiveScreenBuffer(win32_hout); + CloseHandle(win32_back); + CloseHandle(win32_front); + free(win32_char); + free(win32_attr); + } + else #endif { /* Dummy */ @@ -926,7 +1068,55 @@ void caca_refresh(void) 0, 0); XFlush(x11_dpy); } + else #endif +#if defined(USE_WIN32) + if(_caca_driver == CACA_DRIVER_WIN32) + { + COORD size, pos; + SMALL_RECT rect; + DWORD dummy; + unsigned int x, y, len; + + /* Render everything to our back buffer */ + for(y = 0; y < _caca_height; y++) + { + pos.X = 0; + pos.Y = y; + SetConsoleCursorPosition(win32_back, pos); + + for(x = 0; x < _caca_width; x += len) + { + unsigned char *attr = win32_attr + x + y * _caca_width; + + len = 1; + while(x + len < _caca_width && attr[len] == attr[0]) + len++; + + SetConsoleTextAttribute(win32_back, + win32_fg_palette[attr[0] & 0xf] + | win32_bg_palette[attr[0] >> 4]); + + WriteConsole(win32_back, win32_char + x + y * _caca_width, + len, &dummy, NULL); + } + } + + /* Blit the back buffer to the front buffer */ + size.X = _caca_width; + size.Y = _caca_height; + pos.X = pos.Y = 0; + rect.Left = rect.Top = 0; + rect.Right = _caca_width - 1; + rect.Bottom = _caca_height - 1; + ReadConsoleOutput(win32_back, win32_buffer, size, pos, &rect); + WriteConsoleOutput(win32_front, win32_buffer, size, pos, &rect); + } + else +#endif + { + /* Dummy */ + } /* Wait until _caca_delay + time of last call */ ticks += _caca_getticks(&timer); diff --git a/src/io.c b/src/io.c index a26c07d..c5672f6 100644 --- a/src/io.c +++ b/src/io.c @@ -56,14 +56,18 @@ static unsigned int _get_next_event(void); static unsigned int _lowlevel_event(void); +#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) static void _push_event(unsigned int); static unsigned int _pop_event(void); +#endif #if !defined(_DOXYGEN_SKIP_ME) #define EVENTBUF_LEN 10 #endif +#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) static unsigned int eventbuf[EVENTBUF_LEN]; static int events = 0; +#endif #if !defined(_DOXYGEN_SKIP_ME) /* If no new key was pressed after AUTOREPEAT_THRESHOLD usec, assume the @@ -198,10 +202,14 @@ static unsigned int _get_next_event(void) static unsigned int _lowlevel_event(void) { - unsigned int event = _pop_event(); + unsigned int event; + +#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) + event = _pop_event(); if(event) return event; +#endif #if defined(USE_X11) /* The X11 event check routine */ @@ -540,6 +548,58 @@ static unsigned int _lowlevel_event(void) #if defined(USE_WIN32) if(_caca_driver == CACA_DRIVER_WIN32) { + INPUT_RECORD rec; + DWORD num; + + GetNumberOfConsoleInputEvents(win32_hin, &num); + if(num == 0) + return CACA_EVENT_NONE; + + ReadConsoleInput(win32_hin, &rec, 1, &num); + if(rec.EventType == KEY_EVENT) + { + if(rec.Event.KeyEvent.bKeyDown) + event = CACA_EVENT_KEY_PRESS; + else + event = CACA_EVENT_KEY_RELEASE; + + if(rec.Event.KeyEvent.uChar.AsciiChar) + return event | rec.Event.KeyEvent.uChar.AsciiChar; + } + else if(rec.EventType == MOUSE_EVENT) + { + if(rec.Event.MouseEvent.dwEventFlags == 0) + { + if(rec.Event.MouseEvent.dwButtonState & 0x01) + return CACA_EVENT_MOUSE_PRESS | 0x000001; + + if(rec.Event.MouseEvent.dwButtonState & 0x02) + return CACA_EVENT_MOUSE_PRESS | 0x000002; + } + else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) + { + return CACA_EVENT_MOUSE_MOTION + | (rec.Event.MouseEvent.dwMousePosition.X << 12) + | (rec.Event.MouseEvent.dwMousePosition.Y); + } +#if 0 + else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) + { + cout << rec.Event.MouseEvent.dwMousePosition.X << "," << + rec.Event.MouseEvent.dwMousePosition.Y << " " << flush; + } + else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED) + { + SetConsoleCursorPosition(hOut, + WheelWhere); + if(rec.Event.MouseEvent.dwButtonState & 0xFF000000) + cout << "Down" << flush; + else + cout << "Up " << flush; + } +#endif + } + return CACA_EVENT_NONE; } else @@ -551,6 +611,7 @@ static unsigned int _lowlevel_event(void) return CACA_EVENT_NONE; } +#if defined(USE_SLANG) || defined(USE_NCURSES) || defined(USE_CONIO) static void _push_event(unsigned int event) { if(events == EVENTBUF_LEN) @@ -574,4 +635,5 @@ static unsigned int _pop_event(void) return event; } +#endif diff --git a/src/time.c b/src/time.c index ec147a3..071234d 100644 --- a/src/time.c +++ b/src/time.c @@ -58,8 +58,8 @@ unsigned int _caca_getticks(struct caca_timer *timer) #if defined(HAVE_GETTIMEOFDAY) struct timeval tv; #elif defined(USE_WIN32) - static long long int freq = -1LL; - long long int usec; + static long long int freq = -1; + unsigned long long int usec; #endif unsigned int ticks = 0; int new_sec, new_usec; @@ -69,15 +69,15 @@ unsigned int _caca_getticks(struct caca_timer *timer) new_sec = tv.tv_sec; new_usec = tv.tv_usec; #elif defined(USE_WIN32) - if(freq == -1LL) + if(freq == -1) { if(!QueryPerformanceFrequency((LARGE_INTEGER *)&freq)) freq = 0; } QueryPerformanceCounter((LARGE_INTEGER *)&usec); - new_sec = usec / freq; - new_usec = usec % freq; + new_sec = usec * 1000000 / freq / 1000000; + new_usec = (usec * 1000000 / freq) % 1000000; #endif if(timer->last_sec != 0)