PageRenderTime 57ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/Samples/Chap06/Typer/Typer.d

http://github.com/AndrejMitrovic/DWinProgramming
D | 357 lines | 275 code | 74 blank | 8 comment | 20 complexity | c568f03e5b4fdbca4320418aeea05e11 MD5 | raw file
  1. /+
  2. + Copyright (c) Charles Petzold, 1998.
  3. + Ported to the D Programming Language by Andrej Mitrovic, 2011.
  4. +/
  5. module Typer;
  6. import core.runtime;
  7. import core.thread;
  8. import std.algorithm : min, max;
  9. import std.conv;
  10. import std.math;
  11. import std.range;
  12. import std.string;
  13. import std.stdio;
  14. import std.utf;
  15. auto toUTF16z(S)(S s)
  16. {
  17. return toUTFz!(const(wchar)*)(s);
  18. }
  19. pragma(lib, "gdi32.lib");
  20. import core.sys.windows.windef;
  21. import core.sys.windows.winuser;
  22. import core.sys.windows.wingdi;
  23. extern(Windows)
  24. int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  25. {
  26. int result;
  27. try
  28. {
  29. Runtime.initialize();
  30. result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow);
  31. Runtime.terminate();
  32. }
  33. catch(Throwable o)
  34. {
  35. MessageBox(null, o.toString().toUTF16z, "Error", MB_OK | MB_ICONEXCLAMATION);
  36. result = 0;
  37. }
  38. return result;
  39. }
  40. int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  41. {
  42. string appName = "Typer";
  43. HWND hwnd;
  44. MSG msg;
  45. WNDCLASS wndclass;
  46. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  47. wndclass.lpfnWndProc = &WndProc;
  48. wndclass.cbClsExtra = 0;
  49. wndclass.cbWndExtra = 0;
  50. wndclass.hInstance = hInstance;
  51. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  52. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  53. wndclass.hbrBackground = cast(HBRUSH)GetStockObject(WHITE_BRUSH);
  54. wndclass.lpszMenuName = NULL;
  55. wndclass.lpszClassName = appName.toUTF16z;
  56. if (!RegisterClass(&wndclass))
  57. {
  58. MessageBox(NULL, "This program requires Windows NT!", appName.toUTF16z, MB_ICONERROR);
  59. return 0;
  60. }
  61. hwnd = CreateWindow(appName.toUTF16z, // window class name
  62. "Typing Program", // window caption
  63. WS_OVERLAPPEDWINDOW, // window style
  64. CW_USEDEFAULT, // initial x position
  65. CW_USEDEFAULT, // initial y position
  66. CW_USEDEFAULT, // initial x size
  67. CW_USEDEFAULT, // initial y size
  68. NULL, // parent window handle
  69. NULL, // window menu handle
  70. hInstance, // program instance handle
  71. NULL); // creation parameters
  72. ShowWindow(hwnd, iCmdShow);
  73. UpdateWindow(hwnd);
  74. while (GetMessage(&msg, NULL, 0, 0))
  75. {
  76. TranslateMessage(&msg);
  77. DispatchMessage(&msg);
  78. }
  79. return msg.wParam;
  80. }
  81. extern(Windows)
  82. LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) nothrow
  83. {
  84. scope (failure) assert(0);
  85. static DWORD dwCharSet = DEFAULT_CHARSET;
  86. static int cxChar, cyChar, cxClient, cyClient, cxBuffer, cyBuffer, xCaret, yCaret;
  87. static wchar[][] textBuffer;
  88. HDC hdc;
  89. int x;
  90. PAINTSTRUCT ps;
  91. TEXTMETRIC tm;
  92. switch (message)
  93. {
  94. case WM_INPUTLANGCHANGE:
  95. {
  96. dwCharSet = wParam;
  97. goto case WM_CREATE;
  98. }
  99. case WM_CREATE:
  100. {
  101. hdc = GetDC(hwnd);
  102. scope(exit) ReleaseDC(hwnd, hdc);
  103. SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));
  104. scope(exit) DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
  105. GetTextMetrics(hdc, &tm);
  106. cxChar = tm.tmAveCharWidth;
  107. cyChar = tm.tmHeight;
  108. goto case WM_SIZE;
  109. }
  110. case WM_SIZE:
  111. {
  112. // obtain window size in pixels
  113. if (message == WM_SIZE)
  114. {
  115. cxClient = LOWORD(lParam);
  116. cyClient = HIWORD(lParam);
  117. }
  118. // calculate window size in characters
  119. cxBuffer = max(1, cxClient / cxChar);
  120. cyBuffer = max(1, cyClient / cyChar);
  121. textBuffer = new wchar[][](cyBuffer, cxBuffer);
  122. foreach (ref wchar[] line; textBuffer)
  123. {
  124. line[] = ' ';
  125. }
  126. // set caret to upper left corner
  127. xCaret = 0;
  128. yCaret = 0;
  129. if (hwnd == GetFocus())
  130. SetCaretPos(xCaret * cxChar, yCaret * cyChar);
  131. InvalidateRect(hwnd, NULL, TRUE);
  132. return 0;
  133. }
  134. case WM_SETFOCUS:
  135. {
  136. CreateCaret(hwnd, NULL, cxChar, cyChar);
  137. SetCaretPos(xCaret * cxChar, yCaret * cyChar);
  138. ShowCaret(hwnd);
  139. return 0;
  140. }
  141. case WM_KILLFOCUS:
  142. {
  143. HideCaret(hwnd);
  144. DestroyCaret();
  145. return 0;
  146. }
  147. case WM_KEYDOWN:
  148. {
  149. switch (wParam)
  150. {
  151. case VK_HOME:
  152. xCaret = 0;
  153. break;
  154. case VK_END:
  155. xCaret = cxBuffer - 1;
  156. break;
  157. case VK_PRIOR:
  158. yCaret = 0;
  159. break;
  160. case VK_NEXT:
  161. yCaret = cyBuffer - 1;
  162. break;
  163. case VK_LEFT:
  164. xCaret = max(xCaret - 1, 0);
  165. break;
  166. case VK_RIGHT:
  167. xCaret = min(xCaret + 1, cxBuffer - 1);
  168. break;
  169. case VK_UP:
  170. yCaret = max(yCaret - 1, 0);
  171. break;
  172. case VK_DOWN:
  173. yCaret = min(yCaret + 1, cyBuffer - 1);
  174. break;
  175. case VK_DELETE:
  176. {
  177. textBuffer[yCaret] = textBuffer[yCaret][1..$] ~ ' ';
  178. HideCaret(hwnd);
  179. hdc = GetDC(hwnd);
  180. scope(exit) ReleaseDC(hwnd, hdc);
  181. SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));
  182. scope(exit) DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
  183. TextOut(hdc, xCaret * cxChar, yCaret * cyChar, &textBuffer[yCaret][xCaret], cxBuffer - xCaret);
  184. ShowCaret(hwnd);
  185. break;
  186. }
  187. default:
  188. }
  189. SetCaretPos(xCaret * cxChar, yCaret * cyChar);
  190. return 0;
  191. }
  192. case WM_CHAR:
  193. {
  194. // lParam stores the repeat count of a character
  195. foreach (i; 0 .. cast(int)LOWORD(lParam))
  196. {
  197. switch (wParam)
  198. {
  199. case '\b':
  200. {
  201. if (xCaret > 0)
  202. {
  203. xCaret--;
  204. SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1);
  205. }
  206. break;
  207. }
  208. case '\t':
  209. {
  210. do
  211. {
  212. SendMessage(hwnd, WM_CHAR, ' ', 1);
  213. }
  214. while (xCaret % 4 != 0);
  215. break;
  216. }
  217. case '\n':
  218. {
  219. if (++yCaret == cyBuffer)
  220. yCaret = 0;
  221. break;
  222. }
  223. case '\r':
  224. {
  225. xCaret = 0;
  226. if (++yCaret == cyBuffer)
  227. yCaret = 0;
  228. break;
  229. }
  230. case '\x1B': // escape
  231. {
  232. foreach (ref wchar[] line; textBuffer)
  233. {
  234. line[] = ' ';
  235. }
  236. xCaret = 0;
  237. yCaret = 0;
  238. InvalidateRect(hwnd, NULL, FALSE);
  239. break;
  240. }
  241. default: // other chars
  242. {
  243. textBuffer[yCaret][xCaret] = cast(char)wParam;
  244. HideCaret(hwnd);
  245. hdc = GetDC(hwnd);
  246. scope(exit) ReleaseDC(hwnd, hdc);
  247. SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));
  248. scope(exit) DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
  249. TextOut(hdc, xCaret * cxChar, yCaret * cyChar,
  250. &textBuffer[yCaret][xCaret], 1);
  251. ShowCaret(hwnd);
  252. if (++xCaret == cxBuffer)
  253. {
  254. xCaret = 0;
  255. if (++yCaret == cyBuffer)
  256. yCaret = 0;
  257. }
  258. break;
  259. }
  260. }
  261. }
  262. SetCaretPos(xCaret * cxChar, yCaret * cyChar);
  263. return 0;
  264. }
  265. case WM_PAINT:
  266. {
  267. hdc = BeginPaint(hwnd, &ps);
  268. scope(exit) EndPaint(hwnd, &ps);
  269. SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));
  270. scope(exit) DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
  271. foreach (y; 0 .. cyBuffer)
  272. {
  273. TextOut(hdc, 0, y * cyChar, textBuffer[y].ptr, cxBuffer);
  274. }
  275. return 0;
  276. }
  277. case WM_DESTROY:
  278. PostQuitMessage(0);
  279. return 0;
  280. default:
  281. }
  282. return DefWindowProc(hwnd, message, wParam, lParam);
  283. }