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.

преди 18 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 */