You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

353 line
9.9 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  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. * This file contains the libcaca Win32 input and output driver
  15. */
  16. #include "config.h"
  17. #if defined(USE_WIN32)
  18. #include <windows.h>
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include "caca.h"
  22. #include "caca_internals.h"
  23. #include "cucul.h"
  24. #include "cucul_internals.h"
  25. /*
  26. * Global variables
  27. */
  28. static int const win32_fg_palette[] =
  29. {
  30. 0,
  31. FOREGROUND_BLUE,
  32. FOREGROUND_GREEN,
  33. FOREGROUND_GREEN | FOREGROUND_BLUE,
  34. FOREGROUND_RED,
  35. FOREGROUND_RED | FOREGROUND_BLUE,
  36. FOREGROUND_RED | FOREGROUND_GREEN,
  37. FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
  38. FOREGROUND_INTENSITY,
  39. FOREGROUND_INTENSITY | FOREGROUND_BLUE,
  40. FOREGROUND_INTENSITY | FOREGROUND_GREEN,
  41. FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE,
  42. FOREGROUND_INTENSITY | FOREGROUND_RED,
  43. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE,
  44. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN,
  45. FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
  46. };
  47. static int const win32_bg_palette[] =
  48. {
  49. 0,
  50. BACKGROUND_BLUE,
  51. BACKGROUND_GREEN,
  52. BACKGROUND_GREEN | BACKGROUND_BLUE,
  53. BACKGROUND_RED,
  54. BACKGROUND_RED | BACKGROUND_BLUE,
  55. BACKGROUND_RED | BACKGROUND_GREEN,
  56. BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
  57. BACKGROUND_INTENSITY,
  58. BACKGROUND_INTENSITY | BACKGROUND_BLUE,
  59. BACKGROUND_INTENSITY | BACKGROUND_GREEN,
  60. BACKGROUND_INTENSITY | BACKGROUND_GREEN | BACKGROUND_BLUE,
  61. BACKGROUND_INTENSITY | BACKGROUND_RED,
  62. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE,
  63. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN,
  64. BACKGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
  65. };
  66. struct driver_private
  67. {
  68. HANDLE hin, hout, screen;
  69. CHAR_INFO *buffer;
  70. CONSOLE_CURSOR_INFO cci;
  71. };
  72. static int win32_init_graphics(caca_t *kk)
  73. {
  74. CONSOLE_SCREEN_BUFFER_INFO csbi;
  75. SMALL_RECT rect;
  76. COORD size;
  77. kk->drv.p = malloc(sizeof(struct driver_private));
  78. /* This call is allowed to fail in case we already have a console */
  79. AllocConsole();
  80. kk->drv.p->hin = GetStdHandle(STD_INPUT_HANDLE);
  81. kk->drv.p->hout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
  82. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  83. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  84. if(kk->drv.p->hout == INVALID_HANDLE_VALUE)
  85. return -1;
  86. GetConsoleCursorInfo(kk->drv.p->hout, &kk->drv.p->cci);
  87. kk->drv.p->cci.bVisible = FALSE;
  88. SetConsoleCursorInfo(kk->drv.p->hout, &kk->drv.p->cci);
  89. SetConsoleMode(kk->drv.p->hout, ENABLE_MOUSE_INPUT);
  90. kk->drv.p->screen =
  91. CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  92. 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
  93. if(!kk->drv.p->screen || kk->drv.p->screen == INVALID_HANDLE_VALUE)
  94. return -1;
  95. /* Set the new console size */
  96. size.X = kk->qq->width;
  97. size.Y = kk->qq->height;
  98. SetConsoleScreenBufferSize(kk->drv.p->screen, size);
  99. rect.Left = rect.Top = 0;
  100. rect.Right = kk->qq->width - 1;
  101. rect.Bottom = kk->qq->height - 1;
  102. SetConsoleWindowInfo(kk->drv.p->screen, TRUE, &rect);
  103. /* Report our new size to libcucul */
  104. if(!GetConsoleScreenBufferInfo(kk->drv.p->screen, &csbi))
  105. return -1;
  106. _cucul_set_size(kk->qq, csbi.srWindow.Right - csbi.srWindow.Left + 1,
  107. csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
  108. SetConsoleMode(kk->drv.p->screen, 0);
  109. GetConsoleCursorInfo(kk->drv.p->screen, &kk->drv.p->cci);
  110. kk->drv.p->cci.dwSize = 0;
  111. kk->drv.p->cci.bVisible = FALSE;
  112. SetConsoleCursorInfo(kk->drv.p->screen, &kk->drv.p->cci);
  113. SetConsoleActiveScreenBuffer(kk->drv.p->screen);
  114. kk->drv.p->buffer = malloc(kk->qq->width * kk->qq->height
  115. * sizeof(CHAR_INFO));
  116. if(kk->drv.p->buffer == NULL)
  117. return -1;
  118. return 0;
  119. }
  120. static int win32_end_graphics(caca_t *kk)
  121. {
  122. SetConsoleActiveScreenBuffer(kk->drv.p->hout);
  123. CloseHandle(kk->drv.p->screen);
  124. SetConsoleTextAttribute(kk->drv.p->hout, FOREGROUND_INTENSITY
  125. | FOREGROUND_RED
  126. | FOREGROUND_GREEN
  127. | FOREGROUND_BLUE);
  128. kk->drv.p->cci.bVisible = TRUE;
  129. SetConsoleCursorInfo(kk->drv.p->hout, &kk->drv.p->cci);
  130. CloseHandle(kk->drv.p->hout);
  131. free(kk->drv.p);
  132. return 0;
  133. }
  134. static int win32_set_window_title(caca_t *kk, char const *title)
  135. {
  136. SetConsoleTitle(title);
  137. return 0;
  138. }
  139. static unsigned int win32_get_window_width(caca_t *kk)
  140. {
  141. /* FIXME */
  142. /* Fallback to a 6x10 font */
  143. return kk->qq->width * 6;
  144. }
  145. static unsigned int win32_get_window_height(caca_t *kk)
  146. {
  147. /* FIXME */
  148. /* Fallback to a 6x10 font */
  149. return kk->qq->height * 10;
  150. }
  151. static void win32_display(caca_t *kk)
  152. {
  153. COORD size, pos;
  154. SMALL_RECT rect;
  155. unsigned int i;
  156. /* Render everything to our screen buffer */
  157. for(i = 0; i < kk->qq->width * kk->qq->height; i++)
  158. {
  159. uint32_t c = kk->qq->chars[i];
  160. #if 0
  161. if(c > 0x00000020 && c < 0x00000080)
  162. kk->drv.p->buffer[i].Char.AsciiChar = (uint8_t)c;
  163. else
  164. kk->drv.p->buffer[i].Char.AsciiChar = ' ';
  165. #else
  166. if(c > 0x00000020 && c < 0x00010000)
  167. kk->drv.p->buffer[i].Char.UnicodeChar = (uint16_t)c;
  168. else
  169. kk->drv.p->buffer[i].Char.UnicodeChar = (uint16_t)' ';
  170. #endif
  171. kk->drv.p->buffer[i].Attributes =
  172. win32_fg_palette[_cucul_argb32_to_ansi4fg(kk->qq->attr[i])]
  173. | win32_bg_palette[_cucul_argb32_to_ansi4bg(kk->qq->attr[i])];
  174. }
  175. /* Blit the screen buffer */
  176. size.X = kk->qq->width;
  177. size.Y = kk->qq->height;
  178. pos.X = pos.Y = 0;
  179. rect.Left = rect.Top = 0;
  180. rect.Right = kk->qq->width - 1;
  181. rect.Bottom = kk->qq->height - 1;
  182. #if 0
  183. WriteConsoleOutput(kk->drv.p->screen, kk->drv.p->buffer, size, pos, &rect);
  184. #else
  185. WriteConsoleOutputW(kk->drv.p->screen, kk->drv.p->buffer, size, pos, &rect);
  186. #endif
  187. }
  188. static void win32_handle_resize(caca_t *kk)
  189. {
  190. /* FIXME: I don't know what to do here. */
  191. kk->resize.w = kk->qq->width;
  192. kk->resize.h = kk->qq->height;
  193. }
  194. static int win32_get_event(caca_t *kk, caca_event_t *ev)
  195. {
  196. INPUT_RECORD rec;
  197. DWORD num;
  198. for( ; ; )
  199. {
  200. GetNumberOfConsoleInputEvents(kk->drv.p->hin, &num);
  201. if(num == 0)
  202. break;
  203. ReadConsoleInput(kk->drv.p->hin, &rec, 1, &num);
  204. if(rec.EventType == KEY_EVENT)
  205. {
  206. unsigned int event;
  207. if(rec.Event.KeyEvent.bKeyDown)
  208. ev->type = CACA_EVENT_KEY_PRESS;
  209. else
  210. ev->type = CACA_EVENT_KEY_RELEASE;
  211. if(rec.Event.KeyEvent.uChar.AsciiChar)
  212. {
  213. ev->data.key.c = rec.Event.KeyEvent.uChar.AsciiChar;
  214. ev->data.key.ucs4 = (uint32_t)ev->data.key.c;
  215. ev->data.key.utf8[0] = ev->data.key.c;
  216. ev->data.key.utf8[1] = '\0';
  217. return 1;
  218. }
  219. }
  220. if(rec.EventType == MOUSE_EVENT)
  221. {
  222. if(rec.Event.MouseEvent.dwEventFlags == 0)
  223. {
  224. if(rec.Event.MouseEvent.dwButtonState & 0x01)
  225. {
  226. ev->type = CACA_EVENT_MOUSE_PRESS;
  227. ev->data.mouse.button = 1;
  228. return 1;
  229. }
  230. if(rec.Event.MouseEvent.dwButtonState & 0x02)
  231. {
  232. ev->type = CACA_EVENT_MOUSE_PRESS;
  233. ev->data.mouse.button = 2;
  234. return 1;
  235. }
  236. }
  237. else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
  238. {
  239. COORD pos = rec.Event.MouseEvent.dwMousePosition;
  240. if(kk->mouse.x == (unsigned int)pos.X &&
  241. kk->mouse.y == (unsigned int)pos.Y)
  242. continue;
  243. kk->mouse.x = pos.X;
  244. kk->mouse.y = pos.Y;
  245. ev->type = CACA_EVENT_MOUSE_MOTION;
  246. ev->data.mouse.x = kk->mouse.x;
  247. ev->data.mouse.y = kk->mouse.y;
  248. return 1;
  249. }
  250. #if 0
  251. else if(rec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
  252. {
  253. cout << rec.Event.MouseEvent.dwMousePosition.X << "," <<
  254. rec.Event.MouseEvent.dwMousePosition.Y << " " << flush;
  255. }
  256. else if(rec.Event.MouseEvent.dwEventFlags == MOUSE_WHEELED)
  257. {
  258. SetConsoleCursorPosition(hOut,
  259. WheelWhere);
  260. if(rec.Event.MouseEvent.dwButtonState & 0xFF000000)
  261. cout << "Down" << flush;
  262. else
  263. cout << "Up " << flush;
  264. }
  265. #endif
  266. }
  267. /* Unknown event */
  268. ev->type = CACA_EVENT_NONE;
  269. return 0;
  270. }
  271. /* No event */
  272. ev->type = CACA_EVENT_NONE;
  273. return 0;
  274. }
  275. /*
  276. * Driver initialisation
  277. */
  278. int win32_install(caca_t *kk)
  279. {
  280. kk->drv.driver = CACA_DRIVER_WIN32;
  281. kk->drv.init_graphics = win32_init_graphics;
  282. kk->drv.end_graphics = win32_end_graphics;
  283. kk->drv.set_window_title = win32_set_window_title;
  284. kk->drv.get_window_width = win32_get_window_width;
  285. kk->drv.get_window_height = win32_get_window_height;
  286. kk->drv.display = win32_display;
  287. kk->drv.handle_resize = win32_handle_resize;
  288. kk->drv.get_event = win32_get_event;
  289. kk->drv.set_mouse = NULL;
  290. return 0;
  291. }
  292. #endif /* USE_WIN32 */