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.
 
 
 
 
 
 

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