720a8fb7 |
1 | /* |
2 | * windows.c: Windows front end for my puzzle collection. |
3 | */ |
4e7ef6e6 |
4 | |
5 | #include <windows.h> |
fd1a1a2b |
6 | #include <commctrl.h> |
4e7ef6e6 |
7 | |
8 | #include <stdio.h> |
4efb3868 |
9 | #include <assert.h> |
4e7ef6e6 |
10 | #include <stdarg.h> |
11 | #include <stdlib.h> |
12 | #include <time.h> |
13 | |
14 | #include "puzzles.h" |
15 | |
eb2ad6f1 |
16 | #define IDM_NEW 0x0010 |
17 | #define IDM_RESTART 0x0020 |
18 | #define IDM_UNDO 0x0030 |
19 | #define IDM_REDO 0x0040 |
20 | #define IDM_QUIT 0x0050 |
21 | #define IDM_PRESETS 0x0100 |
22 | |
c71454c0 |
23 | #ifdef DEBUG |
24 | static FILE *debug_fp = NULL; |
25 | static HANDLE debug_hdl = INVALID_HANDLE_VALUE; |
26 | static int debug_got_console = 0; |
27 | |
28 | void dputs(char *buf) |
29 | { |
30 | DWORD dw; |
31 | |
32 | if (!debug_got_console) { |
33 | if (AllocConsole()) { |
34 | debug_got_console = 1; |
35 | debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE); |
36 | } |
37 | } |
38 | if (!debug_fp) { |
39 | debug_fp = fopen("debug.log", "w"); |
40 | } |
41 | |
42 | if (debug_hdl != INVALID_HANDLE_VALUE) { |
43 | WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL); |
44 | } |
45 | fputs(buf, debug_fp); |
46 | fflush(debug_fp); |
47 | } |
48 | |
49 | void debug_printf(char *fmt, ...) |
50 | { |
51 | char buf[4096]; |
52 | va_list ap; |
53 | |
54 | va_start(ap, fmt); |
55 | vsprintf(buf, fmt, ap); |
56 | dputs(buf); |
57 | va_end(ap); |
58 | } |
59 | |
60 | #define debug(x) (debug_printf x) |
61 | |
62 | #else |
63 | |
64 | #define debug(x) |
65 | |
66 | #endif |
67 | |
4efb3868 |
68 | struct font { |
69 | HFONT font; |
70 | int type; |
71 | int size; |
72 | }; |
73 | |
4e7ef6e6 |
74 | struct frontend { |
75 | midend_data *me; |
fd1a1a2b |
76 | HWND hwnd, statusbar; |
4e7ef6e6 |
77 | HBITMAP bitmap, prevbm; |
78 | HDC hdc_bm; |
79 | COLORREF *colours; |
80 | HBRUSH *brushes; |
81 | HPEN *pens; |
4efb3868 |
82 | HRGN clip; |
4e7ef6e6 |
83 | UINT timer; |
eb2ad6f1 |
84 | int npresets; |
85 | game_params **presets; |
4efb3868 |
86 | struct font *fonts; |
87 | int nfonts, fontsize; |
4e7ef6e6 |
88 | }; |
89 | |
90 | void fatal(char *fmt, ...) |
91 | { |
92 | char buf[2048]; |
93 | va_list ap; |
94 | |
95 | va_start(ap, fmt); |
96 | vsprintf(buf, fmt, ap); |
97 | va_end(ap); |
98 | |
99 | MessageBox(NULL, buf, "Fatal error", MB_ICONEXCLAMATION | MB_OK); |
100 | |
101 | exit(1); |
102 | } |
103 | |
fd1a1a2b |
104 | void status_bar(frontend *fe, char *text) |
105 | { |
106 | SetWindowText(fe->statusbar, text); |
107 | } |
108 | |
4e7ef6e6 |
109 | void frontend_default_colour(frontend *fe, float *output) |
110 | { |
111 | DWORD c = GetSysColor(COLOR_MENU); /* ick */ |
112 | |
113 | output[0] = (float)(GetRValue(c) / 255.0); |
114 | output[1] = (float)(GetGValue(c) / 255.0); |
115 | output[2] = (float)(GetBValue(c) / 255.0); |
116 | } |
117 | |
4efb3868 |
118 | void clip(frontend *fe, int x, int y, int w, int h) |
119 | { |
120 | if (!fe->clip) { |
121 | fe->clip = CreateRectRgn(0, 0, 1, 1); |
122 | GetClipRgn(fe->hdc_bm, fe->clip); |
123 | } |
124 | |
125 | IntersectClipRect(fe->hdc_bm, x, y, x+w, y+h); |
126 | } |
127 | |
128 | void unclip(frontend *fe) |
129 | { |
130 | assert(fe->clip); |
131 | SelectClipRgn(fe->hdc_bm, fe->clip); |
132 | } |
133 | |
134 | void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize, |
135 | int align, int colour, char *text) |
136 | { |
137 | int i; |
138 | |
139 | /* |
140 | * Find or create the font. |
141 | */ |
142 | for (i = 0; i < fe->nfonts; i++) |
143 | if (fe->fonts[i].type == fonttype && fe->fonts[i].size == fontsize) |
144 | break; |
145 | |
146 | if (i == fe->nfonts) { |
147 | if (fe->fontsize <= fe->nfonts) { |
148 | fe->fontsize = fe->nfonts + 10; |
149 | fe->fonts = sresize(fe->fonts, fe->fontsize, struct font); |
150 | } |
151 | |
152 | fe->nfonts++; |
153 | |
154 | fe->fonts[i].type = fonttype; |
155 | fe->fonts[i].size = fontsize; |
156 | |
157 | /* |
158 | * FIXME: Really I should make at least _some_ effort to |
159 | * pick the correct font. |
160 | */ |
161 | fe->fonts[i].font = CreateFont(-fontsize, 0, 0, 0, 0, |
162 | FALSE, FALSE, FALSE, DEFAULT_CHARSET, |
163 | OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, |
164 | DEFAULT_QUALITY, |
165 | (fonttype == FONT_FIXED ? |
166 | FIXED_PITCH | FF_DONTCARE : |
167 | VARIABLE_PITCH | FF_SWISS), |
168 | NULL); |
169 | } |
170 | |
171 | /* |
172 | * Position and draw the text. |
173 | */ |
174 | { |
175 | HFONT oldfont; |
176 | TEXTMETRIC tm; |
177 | SIZE size; |
178 | |
179 | oldfont = SelectObject(fe->hdc_bm, fe->fonts[i].font); |
180 | if (GetTextMetrics(fe->hdc_bm, &tm)) { |
181 | if (align & ALIGN_VCENTRE) |
182 | y -= (tm.tmAscent+tm.tmDescent)/2; |
183 | else |
184 | y -= tm.tmAscent; |
185 | } |
186 | if (GetTextExtentPoint32(fe->hdc_bm, text, strlen(text), &size)) { |
187 | if (align & ALIGN_HCENTRE) |
188 | x -= size.cx / 2; |
189 | else if (align & ALIGN_HRIGHT) |
190 | x -= size.cx; |
191 | } |
192 | SetBkMode(fe->hdc_bm, TRANSPARENT); |
193 | TextOut(fe->hdc_bm, x, y, text, strlen(text)); |
194 | SelectObject(fe->hdc_bm, oldfont); |
195 | } |
196 | } |
197 | |
4e7ef6e6 |
198 | void draw_rect(frontend *fe, int x, int y, int w, int h, int colour) |
199 | { |
fbdd7610 |
200 | if (w == 1 && h == 1) { |
201 | /* |
202 | * Rectangle() appears to get uppity if asked to draw a 1x1 |
203 | * rectangle, presumably on the grounds that that's beneath |
204 | * its dignity and you ought to be using SetPixel instead. |
205 | * So I will. |
206 | */ |
207 | SetPixel(fe->hdc_bm, x, y, fe->colours[colour]); |
208 | } else { |
209 | HBRUSH oldbrush = SelectObject(fe->hdc_bm, fe->brushes[colour]); |
210 | HPEN oldpen = SelectObject(fe->hdc_bm, fe->pens[colour]); |
211 | Rectangle(fe->hdc_bm, x, y, x+w, y+h); |
212 | SelectObject(fe->hdc_bm, oldbrush); |
213 | SelectObject(fe->hdc_bm, oldpen); |
214 | } |
4e7ef6e6 |
215 | } |
216 | |
217 | void draw_line(frontend *fe, int x1, int y1, int x2, int y2, int colour) |
218 | { |
219 | HPEN oldpen = SelectObject(fe->hdc_bm, fe->pens[colour]); |
220 | MoveToEx(fe->hdc_bm, x1, y1, NULL); |
221 | LineTo(fe->hdc_bm, x2, y2); |
222 | SetPixel(fe->hdc_bm, x2, y2, fe->colours[colour]); |
223 | SelectObject(fe->hdc_bm, oldpen); |
224 | } |
225 | |
226 | void draw_polygon(frontend *fe, int *coords, int npoints, |
227 | int fill, int colour) |
228 | { |
229 | POINT *pts = snewn(npoints+1, POINT); |
230 | int i; |
231 | |
232 | for (i = 0; i <= npoints; i++) { |
233 | int j = (i < npoints ? i : 0); |
234 | pts[i].x = coords[j*2]; |
235 | pts[i].y = coords[j*2+1]; |
236 | } |
237 | |
238 | if (fill) { |
239 | HBRUSH oldbrush = SelectObject(fe->hdc_bm, fe->brushes[colour]); |
240 | HPEN oldpen = SelectObject(fe->hdc_bm, fe->pens[colour]); |
241 | Polygon(fe->hdc_bm, pts, npoints); |
242 | SelectObject(fe->hdc_bm, oldbrush); |
243 | SelectObject(fe->hdc_bm, oldpen); |
244 | } else { |
245 | HPEN oldpen = SelectObject(fe->hdc_bm, fe->pens[colour]); |
246 | Polyline(fe->hdc_bm, pts, npoints+1); |
247 | SelectObject(fe->hdc_bm, oldpen); |
248 | } |
249 | |
250 | sfree(pts); |
251 | } |
252 | |
253 | void start_draw(frontend *fe) |
254 | { |
255 | HDC hdc_win; |
256 | hdc_win = GetDC(fe->hwnd); |
257 | fe->hdc_bm = CreateCompatibleDC(hdc_win); |
258 | fe->prevbm = SelectObject(fe->hdc_bm, fe->bitmap); |
259 | ReleaseDC(fe->hwnd, hdc_win); |
4efb3868 |
260 | fe->clip = NULL; |
4e7ef6e6 |
261 | } |
262 | |
263 | void draw_update(frontend *fe, int x, int y, int w, int h) |
264 | { |
265 | RECT r; |
266 | |
267 | r.left = x; |
268 | r.top = y; |
269 | r.right = x + w; |
270 | r.bottom = y + h; |
271 | |
272 | InvalidateRect(fe->hwnd, &r, FALSE); |
273 | } |
274 | |
275 | void end_draw(frontend *fe) |
276 | { |
277 | SelectObject(fe->hdc_bm, fe->prevbm); |
278 | DeleteDC(fe->hdc_bm); |
4efb3868 |
279 | if (fe->clip) { |
280 | DeleteObject(fe->clip); |
281 | fe->clip = NULL; |
282 | } |
4e7ef6e6 |
283 | } |
284 | |
285 | void deactivate_timer(frontend *fe) |
286 | { |
287 | KillTimer(fe->hwnd, fe->timer); |
288 | fe->timer = 0; |
289 | } |
290 | |
291 | void activate_timer(frontend *fe) |
292 | { |
293 | fe->timer = SetTimer(fe->hwnd, fe->timer, 20, NULL); |
294 | } |
295 | |
296 | static frontend *new_window(HINSTANCE inst) |
297 | { |
298 | frontend *fe; |
299 | int x, y; |
fd1a1a2b |
300 | RECT r, sr; |
4e7ef6e6 |
301 | HDC hdc; |
302 | |
303 | fe = snew(frontend); |
304 | fe->me = midend_new(fe); |
305 | midend_new_game(fe->me, NULL); |
306 | midend_size(fe->me, &x, &y); |
307 | |
308 | fe->timer = 0; |
309 | |
310 | { |
311 | int i, ncolours; |
312 | float *colours; |
313 | |
314 | colours = midend_colours(fe->me, &ncolours); |
315 | |
316 | fe->colours = snewn(ncolours, COLORREF); |
317 | fe->brushes = snewn(ncolours, HBRUSH); |
318 | fe->pens = snewn(ncolours, HPEN); |
319 | |
320 | for (i = 0; i < ncolours; i++) { |
321 | fe->colours[i] = RGB(255 * colours[i*3+0], |
322 | 255 * colours[i*3+1], |
323 | 255 * colours[i*3+2]); |
324 | fe->brushes[i] = CreateSolidBrush(fe->colours[i]); |
325 | if (!fe->brushes[i]) |
326 | MessageBox(fe->hwnd, "ooh", "eck", MB_OK); |
327 | fe->pens[i] = CreatePen(PS_SOLID, 1, fe->colours[i]); |
328 | } |
329 | } |
330 | |
331 | r.left = r.top = 0; |
332 | r.right = x; |
333 | r.bottom = y; |
334 | AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~ |
335 | (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED), |
eb2ad6f1 |
336 | TRUE, 0); |
4e7ef6e6 |
337 | |
0c490335 |
338 | fe->hwnd = CreateWindowEx(0, game_name, game_name, |
4e7ef6e6 |
339 | WS_OVERLAPPEDWINDOW &~ |
340 | (WS_THICKFRAME | WS_MAXIMIZEBOX), |
341 | CW_USEDEFAULT, CW_USEDEFAULT, |
342 | r.right - r.left, r.bottom - r.top, |
343 | NULL, NULL, inst, NULL); |
344 | |
eb2ad6f1 |
345 | { |
346 | HMENU bar = CreateMenu(); |
347 | HMENU menu = CreateMenu(); |
348 | |
349 | AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Game"); |
350 | AppendMenu(menu, MF_ENABLED, IDM_NEW, "New"); |
351 | AppendMenu(menu, MF_ENABLED, IDM_RESTART, "Restart"); |
352 | |
353 | if ((fe->npresets = midend_num_presets(fe->me)) > 0) { |
354 | HMENU sub = CreateMenu(); |
355 | int i; |
356 | |
357 | AppendMenu(menu, MF_ENABLED|MF_POPUP, (UINT)sub, "Type"); |
358 | |
359 | fe->presets = snewn(fe->npresets, game_params *); |
360 | |
361 | for (i = 0; i < fe->npresets; i++) { |
362 | char *name; |
363 | |
364 | midend_fetch_preset(fe->me, i, &name, &fe->presets[i]); |
365 | |
366 | /* |
367 | * FIXME: we ought to go through and do something |
368 | * with ampersands here. |
369 | */ |
370 | |
371 | AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, name); |
372 | } |
373 | } |
374 | |
375 | AppendMenu(menu, MF_SEPARATOR, 0, 0); |
376 | AppendMenu(menu, MF_ENABLED, IDM_UNDO, "Undo"); |
377 | AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo"); |
378 | AppendMenu(menu, MF_SEPARATOR, 0, 0); |
379 | AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit"); |
380 | SetMenu(fe->hwnd, bar); |
381 | } |
382 | |
fd1a1a2b |
383 | if (midend_wants_statusbar(fe->me)) { |
384 | fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh", |
385 | WS_CHILD | WS_VISIBLE, |
386 | 0, 0, 0, 0, /* status bar does these */ |
387 | fe->hwnd, NULL, inst, NULL); |
388 | GetWindowRect(fe->statusbar, &sr); |
389 | SetWindowPos(fe->hwnd, NULL, 0, 0, |
390 | r.right - r.left, r.bottom - r.top + sr.bottom - sr.top, |
391 | SWP_NOMOVE | SWP_NOZORDER); |
392 | SetWindowPos(fe->statusbar, NULL, 0, y, x, sr.bottom - sr.top, |
393 | SWP_NOZORDER); |
394 | } else { |
395 | fe->statusbar = NULL; |
396 | } |
397 | |
4e7ef6e6 |
398 | hdc = GetDC(fe->hwnd); |
399 | fe->bitmap = CreateCompatibleBitmap(hdc, x, y); |
400 | ReleaseDC(fe->hwnd, hdc); |
401 | |
402 | SetWindowLong(fe->hwnd, GWL_USERDATA, (LONG)fe); |
403 | |
404 | ShowWindow(fe->hwnd, SW_NORMAL); |
405 | SetForegroundWindow(fe->hwnd); |
406 | |
407 | midend_redraw(fe->me); |
408 | |
409 | return fe; |
410 | } |
411 | |
412 | static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, |
413 | WPARAM wParam, LPARAM lParam) |
414 | { |
415 | frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA); |
416 | |
417 | switch (message) { |
418 | case WM_CLOSE: |
419 | DestroyWindow(hwnd); |
420 | return 0; |
eb2ad6f1 |
421 | case WM_COMMAND: |
422 | switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */ |
423 | case IDM_NEW: |
424 | if (!midend_process_key(fe->me, 0, 0, 'n')) |
425 | PostQuitMessage(0); |
426 | break; |
427 | case IDM_RESTART: |
428 | if (!midend_process_key(fe->me, 0, 0, 'r')) |
429 | PostQuitMessage(0); |
430 | break; |
431 | case IDM_UNDO: |
432 | if (!midend_process_key(fe->me, 0, 0, 'u')) |
433 | PostQuitMessage(0); |
434 | break; |
435 | case IDM_REDO: |
436 | if (!midend_process_key(fe->me, 0, 0, '\x12')) |
437 | PostQuitMessage(0); |
438 | break; |
439 | case IDM_QUIT: |
440 | if (!midend_process_key(fe->me, 0, 0, 'q')) |
441 | PostQuitMessage(0); |
442 | break; |
443 | default: |
444 | { |
445 | int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10; |
446 | |
447 | if (p >= 0 && p < fe->npresets) { |
fd1a1a2b |
448 | RECT r, sr; |
eb2ad6f1 |
449 | HDC hdc; |
450 | int x, y; |
451 | |
452 | midend_set_params(fe->me, fe->presets[p]); |
453 | midend_new_game(fe->me, NULL); |
454 | midend_size(fe->me, &x, &y); |
455 | |
456 | r.left = r.top = 0; |
457 | r.right = x; |
458 | r.bottom = y; |
459 | AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~ |
460 | (WS_THICKFRAME | WS_MAXIMIZEBOX | |
461 | WS_OVERLAPPED), |
462 | TRUE, 0); |
463 | |
fd1a1a2b |
464 | if (fe->statusbar != NULL) { |
465 | GetWindowRect(fe->statusbar, &sr); |
466 | } else { |
467 | sr.left = sr.right = sr.top = sr.bottom = 0; |
468 | } |
eb2ad6f1 |
469 | SetWindowPos(fe->hwnd, NULL, 0, 0, |
fd1a1a2b |
470 | r.right - r.left, |
471 | r.bottom - r.top + sr.bottom - sr.top, |
eb2ad6f1 |
472 | SWP_NOMOVE | SWP_NOZORDER); |
fd1a1a2b |
473 | if (fe->statusbar != NULL) |
474 | SetWindowPos(fe->statusbar, NULL, 0, y, x, |
475 | sr.bottom - sr.top, SWP_NOZORDER); |
eb2ad6f1 |
476 | |
477 | DeleteObject(fe->bitmap); |
478 | |
479 | hdc = GetDC(fe->hwnd); |
480 | fe->bitmap = CreateCompatibleBitmap(hdc, x, y); |
481 | ReleaseDC(fe->hwnd, hdc); |
482 | |
483 | midend_redraw(fe->me); |
484 | } |
485 | } |
486 | break; |
487 | } |
488 | break; |
4e7ef6e6 |
489 | case WM_DESTROY: |
490 | PostQuitMessage(0); |
491 | return 0; |
492 | case WM_PAINT: |
493 | { |
494 | PAINTSTRUCT p; |
495 | HDC hdc, hdc2; |
496 | HBITMAP prevbm; |
497 | |
498 | hdc = BeginPaint(hwnd, &p); |
499 | hdc2 = CreateCompatibleDC(hdc); |
500 | prevbm = SelectObject(hdc2, fe->bitmap); |
501 | BitBlt(hdc, |
502 | p.rcPaint.left, p.rcPaint.top, |
503 | p.rcPaint.right - p.rcPaint.left, |
504 | p.rcPaint.bottom - p.rcPaint.top, |
505 | hdc2, |
506 | p.rcPaint.left, p.rcPaint.top, |
507 | SRCCOPY); |
508 | SelectObject(hdc2, prevbm); |
509 | DeleteDC(hdc2); |
510 | EndPaint(hwnd, &p); |
511 | } |
512 | return 0; |
513 | case WM_KEYDOWN: |
514 | { |
515 | int key = -1; |
516 | |
517 | switch (wParam) { |
518 | case VK_LEFT: key = CURSOR_LEFT; break; |
519 | case VK_RIGHT: key = CURSOR_RIGHT; break; |
520 | case VK_UP: key = CURSOR_UP; break; |
521 | case VK_DOWN: key = CURSOR_DOWN; break; |
c71454c0 |
522 | /* |
523 | * Diagonal keys on the numeric keypad. |
524 | */ |
525 | case VK_PRIOR: |
526 | if (!(lParam & 0x01000000)) key = CURSOR_UP_RIGHT; |
527 | break; |
528 | case VK_NEXT: |
529 | if (!(lParam & 0x01000000)) key = CURSOR_DOWN_RIGHT; |
530 | break; |
531 | case VK_HOME: |
532 | if (!(lParam & 0x01000000)) key = CURSOR_UP_LEFT; |
533 | break; |
534 | case VK_END: |
535 | if (!(lParam & 0x01000000)) key = CURSOR_DOWN_LEFT; |
536 | break; |
537 | /* |
538 | * Numeric keypad keys with Num Lock on. |
539 | */ |
540 | case VK_NUMPAD4: key = CURSOR_LEFT; break; |
541 | case VK_NUMPAD6: key = CURSOR_RIGHT; break; |
542 | case VK_NUMPAD8: key = CURSOR_UP; break; |
543 | case VK_NUMPAD2: key = CURSOR_DOWN; break; |
544 | case VK_NUMPAD9: key = CURSOR_UP_RIGHT; break; |
545 | case VK_NUMPAD3: key = CURSOR_DOWN_RIGHT; break; |
546 | case VK_NUMPAD7: key = CURSOR_UP_LEFT; break; |
547 | case VK_NUMPAD1: key = CURSOR_DOWN_LEFT; break; |
4e7ef6e6 |
548 | } |
549 | |
550 | if (key != -1) { |
eb2ad6f1 |
551 | if (!midend_process_key(fe->me, 0, 0, key)) |
4e7ef6e6 |
552 | PostQuitMessage(0); |
c71454c0 |
553 | } else { |
554 | MSG m; |
555 | m.hwnd = hwnd; |
556 | m.message = WM_KEYDOWN; |
557 | m.wParam = wParam; |
558 | m.lParam = lParam & 0xdfff; |
559 | TranslateMessage(&m); |
4e7ef6e6 |
560 | } |
561 | } |
562 | break; |
563 | case WM_LBUTTONDOWN: |
564 | case WM_RBUTTONDOWN: |
565 | case WM_MBUTTONDOWN: |
b0f06719 |
566 | { |
567 | int button; |
568 | |
569 | /* |
570 | * Shift-clicks count as middle-clicks, since otherwise |
571 | * two-button Windows users won't have any kind of |
572 | * middle click to use. |
573 | */ |
574 | if (message == WM_MBUTTONDOWN || (wParam & MK_SHIFT)) |
575 | button = MIDDLE_BUTTON; |
576 | else if (message == WM_LBUTTONDOWN) |
577 | button = LEFT_BUTTON; |
578 | else |
579 | button = RIGHT_BUTTON; |
580 | |
581 | if (!midend_process_key(fe->me, LOWORD(lParam), |
582 | HIWORD(lParam), button)) |
583 | PostQuitMessage(0); |
584 | } |
4e7ef6e6 |
585 | break; |
586 | case WM_CHAR: |
eb2ad6f1 |
587 | if (!midend_process_key(fe->me, 0, 0, (unsigned char)wParam)) |
4e7ef6e6 |
588 | PostQuitMessage(0); |
589 | return 0; |
590 | case WM_TIMER: |
591 | if (fe->timer) |
592 | midend_timer(fe->me, (float)0.02); |
593 | return 0; |
594 | } |
595 | |
596 | return DefWindowProc(hwnd, message, wParam, lParam); |
597 | } |
598 | |
599 | int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) |
600 | { |
601 | MSG msg; |
602 | |
603 | srand(time(NULL)); |
604 | |
fd1a1a2b |
605 | InitCommonControls(); |
606 | |
4e7ef6e6 |
607 | if (!prev) { |
608 | WNDCLASS wndclass; |
609 | |
610 | wndclass.style = 0; |
611 | wndclass.lpfnWndProc = WndProc; |
612 | wndclass.cbClsExtra = 0; |
613 | wndclass.cbWndExtra = 0; |
614 | wndclass.hInstance = inst; |
615 | wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION); |
616 | wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); |
617 | wndclass.hbrBackground = NULL; |
618 | wndclass.lpszMenuName = NULL; |
0c490335 |
619 | wndclass.lpszClassName = game_name; |
4e7ef6e6 |
620 | |
621 | RegisterClass(&wndclass); |
622 | } |
623 | |
624 | new_window(inst); |
625 | |
626 | while (GetMessage(&msg, NULL, 0, 0)) { |
4e7ef6e6 |
627 | DispatchMessage(&msg); |
628 | } |
629 | |
630 | return msg.wParam; |
631 | } |