blob: 2d25c664701d3654ca588a4e30362a4d84530bad [file] [log] [blame]
Eric Pouech0b83d4c2001-11-23 23:04:58 +00001/*
2 * a GUI application for displaying a console
3 * USER32 back end
4 * Copyright 2001 Eric Pouech
5 */
6
7#include <stdio.h>
8#include "winecon_private.h"
9
10/* mapping console colors to RGB values */
11static COLORREF color_map[16] =
12{
13 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
14 RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0x80, 0x80, 0x80),
15 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
16 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF),
17};
18
19/******************************************************************
20 * WCUSER_FillMemDC
21 *
22 * Fills the Mem DC with current cells values
23 */
24static void WCUSER_FillMemDC(const struct inner_data* data, int upd_tp, int upd_bm)
25{
26 unsigned i, j, k;
27 CHAR_INFO* cell;
28 HFONT hOldFont;
29 WORD attr;
30 WCHAR* line;
31
32 if (!(line = HeapAlloc(GetProcessHeap(), 0, data->sb_width * sizeof(WCHAR))))
33 {Trace(0, "OOM\n"); return;}
34
35 hOldFont = SelectObject(data->hMemDC, data->hFont);
36 for (j = upd_tp; j <= upd_bm; j++)
37 {
38 cell = &data->cells[j * data->sb_width];
39 for (i = 0; i < data->win_width; i++)
40 {
41 attr = cell[i].Attributes;
42 SetBkColor(data->hMemDC, color_map[attr & 0x0F]);
43 SetTextColor(data->hMemDC, color_map[(attr >> 4) & 0x0F]);
44 for (k = i; k < data->win_width && cell[k].Attributes == attr; k++)
45 {
46 line[k - i] = cell[k].Char.UnicodeChar;
47 }
48 TextOut(data->hMemDC, i * data->cell_width, j * data->cell_height,
49 line, k - i);
50 i = k - 1;
51 }
52 }
53 SelectObject(data->hMemDC, hOldFont);
54 HeapFree(GetProcessHeap(), 0, line);
55}
56
57/******************************************************************
58 * WCUSER_NewBitmap
59 *
60 * Either the font geometry or the sb geometry has changed. we need to recreate the
61 * bitmap geometry
62 */
63static void WCUSER_NewBitmap(struct inner_data* data, BOOL fill)
64{
65 HBITMAP hnew, hold;
66
67 if (!data->sb_width || !data->sb_height)
68 return;
69 hnew = CreateCompatibleBitmap(data->hMemDC,
70 data->sb_width * data->cell_width,
71 data->sb_height * data->cell_height);
72 hold = SelectObject(data->hMemDC, hnew);
73
74 if (data->hBitmap)
75 {
76 if (hold == data->hBitmap)
77 DeleteObject(data->hBitmap);
78 else
79 Trace(0, "leak\n");
80 }
81 data->hBitmap = hnew;
82 if (fill)
83 WCUSER_FillMemDC(data, 0, data->sb_height - 1);
84}
85
86/******************************************************************
87 * WCUSER_ResizeScreenBuffer
88 *
89 *
90 */
91static void WCUSER_ResizeScreenBuffer(struct inner_data* data)
92{
93 WCUSER_NewBitmap(data, FALSE);
94}
95
96/******************************************************************
97 * WCUSER_PosCursor
98 *
99 * Set a new position for the cursor
100 */
101static void WCUSER_PosCursor(const struct inner_data* data)
102{
103 if (data->hWnd != GetFocus() || !data->cursor_visible) return;
104
105 SetCaretPos((data->cursor.X - data->win_pos.X) * data->cell_width,
106 (data->cursor.Y - data->win_pos.Y) * data->cell_height);
107 ShowCaret(data->hWnd);
108}
109
110/******************************************************************
111 * WCUSER_ShapeCursor
112 *
113 * Sets a new shape for the cursor
114 */
115void WCUSER_ShapeCursor(struct inner_data* data, int size, int vis, BOOL force)
116{
117 if (force || size != data->cursor_size)
118 {
119 if (data->cursor_visible && data->hWnd == GetFocus()) DestroyCaret();
120 if (data->cursor_bitmap) DeleteObject(data->cursor_bitmap);
121 data->cursor_bitmap = (HBITMAP)0;
122 if (size != 100)
123 {
124 int w16b; /* number of byets per row, aligned on word size */
125 BYTE* ptr;
126 int i, j, nbl;
127
128 w16b = ((data->cell_width + 15) & ~15) / 8;
129 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, w16b * data->cell_height);
130 if (!ptr) {Trace(0, "OOM\n"); return;}
131 nbl = max((data->cell_height * size) / 100, 1);
132 for (j = data->cell_height - nbl; j < data->cell_height; j++)
133 {
134 for (i = 0; i < data->cell_width; i++)
135 {
136 ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
137 }
138 }
139 data->cursor_bitmap = CreateBitmap(data->cell_width, data->cell_height, 1, 1, ptr);
140 HeapFree(GetProcessHeap(), 0, ptr);
141 }
142 data->cursor_size = size;
143 data->cursor_visible = -1;
144 }
145
146 vis = (vis) ? TRUE : FALSE;
147 if (force || vis != data->cursor_visible)
148 {
149 data->cursor_visible = vis;
150 if (data->hWnd == GetFocus())
151 {
152 if (vis)
153 {
154 CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height);
155 WCUSER_PosCursor(data);
156 }
157 else
158 {
159 DestroyCaret();
160 }
161 }
162 }
163}
164
165/******************************************************************
166 * INECON_ComputePositions
167 *
168 * Recomputes all the components (mainly scroll bars) positions
169 */
170void WCUSER_ComputePositions(struct inner_data* data)
171{
172 RECT r;
173 int dx, dy;
174
175 /* compute window size from desired client size */
176 r.left = r.top = 0;
177 r.right = data->win_width * data->cell_width;
178 r.bottom = data->win_height * data->cell_height;
179
180 if (IsRectEmpty(&r))
181 {
182 ShowWindow(data->hWnd, SW_HIDE);
183 return;
184 }
185
186 AdjustWindowRect(&r, GetWindowLong(data->hWnd, GWL_STYLE), FALSE);
187
188 dx = dy = 0;
189 if (data->sb_width > data->win_width)
190 {
191 dy = GetSystemMetrics(SM_CYHSCROLL);
192 SetScrollRange(data->hWnd, SB_HORZ, 0, data->sb_width - data->win_width, FALSE);
193 SetScrollPos(data->hWnd, SB_HORZ, 0, FALSE); /* FIXME */
194 ShowScrollBar(data->hWnd, SB_HORZ, TRUE);
195 }
196 else
197 {
198 ShowScrollBar(data->hWnd, SB_HORZ, FALSE);
199 }
200
201 if (data->sb_height > data->win_height)
202 {
203 dx = GetSystemMetrics(SM_CXVSCROLL);
204 SetScrollRange(data->hWnd, SB_VERT, 0, data->sb_height - data->win_height, FALSE);
205 SetScrollPos(data->hWnd, SB_VERT, 0, FALSE); /* FIXME */
206 ShowScrollBar(data->hWnd, SB_VERT, TRUE);
207 }
208 else
209 {
210 ShowScrollBar(data->hWnd, SB_VERT, FALSE);
211 }
212
213 SetWindowPos(data->hWnd, 0, 0, 0, r.right - r.left + dx, r.bottom - r.top + dy,
214 SWP_NOMOVE|SWP_NOZORDER|SWP_SHOWWINDOW);
215 WCUSER_ShapeCursor(data, data->cursor_size, data->cursor_visible, TRUE);
216 WCUSER_PosCursor(data);
217}
218
219/******************************************************************
220 * WCUSER_SetTitle
221 *
222 * Sets the title to the wine console
223 */
224static void WCUSER_SetTitle(const struct inner_data* data)
225{
226 WCHAR buffer[256];
227
228 if (WINECON_GetConsoleTitle(data->hConIn, buffer, sizeof(buffer)))
229 SetWindowText(data->hWnd, buffer);
230}
231
232/******************************************************************
233 * WCUSER_SetFont
234 *
235 *
236 */
237BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* logfont, const TEXTMETRIC* tm)
238{
239 if (!memcmp(logfont, &data->logFont, sizeof(LOGFONT))) return TRUE;
240 if (data->hFont) DeleteObject(data->hFont);
241 data->hFont = CreateFontIndirect(logfont);
242 if (!data->hFont) {Trace(0, "wrong font\n");return FALSE;}
243 data->cell_width = tm->tmMaxCharWidth; /* font is fixed Avg == Max */
244 data->cell_height = tm->tmHeight;
245 data->logFont = *logfont;
246 WCUSER_ComputePositions(data);
247 WCUSER_NewBitmap(data, TRUE);
248 InvalidateRect(data->hWnd, NULL, FALSE);
249 UpdateWindow(data->hWnd);
250 return TRUE;
251}
252
253/******************************************************************
254 * WCUSER_GetCell
255 *
256 * Get a cell from the a relative coordinate in window (takes into
257 * account the scrolling)
258 */
259static COORD WCUSER_GetCell(const struct inner_data* data, LPARAM lParam)
260{
261 COORD c;
262
263 c.X = data->win_pos.X + (short)LOWORD(lParam) / data->cell_width;
264 c.Y = data->win_pos.Y + (short)HIWORD(lParam) / data->cell_height;
265
266 return c;
267}
268
269/******************************************************************
270 * WCUSER_GetSelectionRect
271 *
272 * Get the selection rectangle
273 */
274static void WCUSER_GetSelectionRect(const struct inner_data* data, LPRECT r)
275{
276 r->left = (min(data->selectPt1.X, data->selectPt2.X) ) * data->cell_width;
277 r->top = (min(data->selectPt1.Y, data->selectPt2.Y) ) * data->cell_height;
278 r->right = (max(data->selectPt1.X, data->selectPt2.X) + 1) * data->cell_width;
279 r->bottom = (max(data->selectPt1.Y, data->selectPt2.Y) + 1) * data->cell_height;
280}
281
282/******************************************************************
283 * WCUSER_SetSelection
284 *
285 *
286 */
287static void WCUSER_SetSelection(const struct inner_data* data, HDC hRefDC)
288{
289 HDC hDC;
290 RECT r;
291
292 WCUSER_GetSelectionRect(data, &r);
293 hDC = hRefDC ? hRefDC : GetDC(data->hWnd);
294 if (hDC)
295 {
296 if (data->hWnd == GetFocus() && data->cursor_visible)
297 HideCaret(data->hWnd);
298 InvertRect(hDC, &r);
299 if (hDC != hRefDC)
300 ReleaseDC(data->hWnd, hDC);
301 if (data->hWnd == GetFocus() && data->cursor_visible)
302 ShowCaret(data->hWnd);
303 }
304}
305
306/******************************************************************
307 * WCUSER_MoveSelection
308 *
309 *
310 */
311static void WCUSER_MoveSelection(struct inner_data* data, COORD dst, BOOL final)
312{
313 RECT r;
314 HDC hDC;
315
316 WCUSER_GetSelectionRect(data, &r);
317 hDC = GetDC(data->hWnd);
318 if (hDC)
319 {
320 if (data->hWnd == GetFocus() && data->cursor_visible)
321 HideCaret(data->hWnd);
322 InvertRect(hDC, &r);
323 }
324 data->selectPt2 = dst;
325 if (hDC)
326 {
327 WCUSER_GetSelectionRect(data, &r);
328 InvertRect(hDC, &r);
329 ReleaseDC(data->hWnd, hDC);
330 if (data->hWnd == GetFocus() && data->cursor_visible)
331 ShowCaret(data->hWnd);
332 }
333 if (final)
334 {
335 ReleaseCapture();
336 data->hasSelection = TRUE;
337 }
338}
339
340/******************************************************************
341 * WCUSER_CopySelectionToClipboard
342 *
343 * Copies the current selection into the clipboard
344 */
345static void WCUSER_CopySelectionToClipboard(const struct inner_data* data)
346{
347 HANDLE hMem;
348 LPWSTR p;
349 unsigned w, h;
350
351 w = abs(data->selectPt1.X - data->selectPt2.X) + 2;
352 h = abs(data->selectPt1.Y - data->selectPt2.Y) + 1;
353
354 if (!OpenClipboard(data->hWnd)) return;
355 EmptyClipboard();
356
357 hMem = GlobalAlloc(GMEM_MOVEABLE, (w * h - 1) * sizeof(WCHAR));
358 if (hMem && (p = GlobalLock(hMem)))
359 {
360 COORD c;
361 int y;
362
363 c.X = data->win_pos.X + min(data->selectPt1.X, data->selectPt2.X);
364 c.Y = data->win_pos.Y + min(data->selectPt1.Y, data->selectPt2.Y);
365
366 for (y = 0; y < h; y++, c.Y++)
367 {
368 ReadConsoleOutputCharacter(data->hConOut, &p[y * w], w - 1, c, NULL);
369 if (y < h - 1) p[y * w + w - 1] = '\n';
370 }
371 GlobalUnlock(hMem);
372 SetClipboardData(CF_UNICODETEXT, hMem);
373 }
374 CloseClipboard();
375}
376
377/******************************************************************
378 * WCUSER_PasteFromClipboard
379 *
380 *
381 */
382static void WCUSER_PasteFromClipboard(struct inner_data* data)
383{
384 HANDLE h;
385 WCHAR* ptr;
386
387 if (!OpenClipboard(data->hWnd)) return;
388 h = GetClipboardData(CF_UNICODETEXT);
389 if (h && (ptr = GlobalLock(h)))
390 {
391 int i, len = GlobalSize(h) / sizeof(WCHAR);
392 INPUT_RECORD ir[2];
393 DWORD n;
394 SHORT sh;
395
396 ir[0].EventType = KEY_EVENT;
397 ir[0].Event.KeyEvent.wRepeatCount = 0;
398 ir[0].Event.KeyEvent.dwControlKeyState = 0;
399 ir[0].Event.KeyEvent.bKeyDown = TRUE;
400
401 /* generate the corresponding input records */
402 for (i = 0; i < len; i++)
403 {
404 /* FIXME: the modifying keys are not generated (shift, ctrl...) */
405 sh = VkKeyScan(ptr[i]);
406 ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
407 ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(LOBYTE(sh), 0);
408 ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
409
410 ir[1] = ir[0];
411 ir[1].Event.KeyEvent.bKeyDown = FALSE;
412
413 WriteConsoleInput(data->hConIn, ir, 2, &n);
414 }
415 GlobalUnlock(h);
416 }
417 CloseClipboard();
418}
419
420static void WCUSER_Refresh(const struct inner_data* data, int tp, int bm)
421{
422 if (data->win_pos.Y <= bm && data->win_pos.Y + data->win_height >= tp)
423 {
424 RECT r;
425
426 r.left = 0;
427 r.right = data->win_width * data->cell_width;
428 r.top = (tp - data->win_pos.Y) * data->cell_height;
429 r.bottom = (bm - data->win_pos.Y + 1) * data->cell_height;
430 InvalidateRect(data->hWnd, &r, FALSE);
431 WCUSER_FillMemDC(data, tp, bm);
432 UpdateWindow(data->hWnd);
433 }
434}
435
436/******************************************************************
437 * WCUSER_Paint
438 *
439 *
440 */
441static void WCUSER_Paint(const struct inner_data* data)
442{
443 PAINTSTRUCT ps;
444
445 BeginPaint(data->hWnd, &ps);
446 BitBlt(ps.hdc, 0, 0, data->win_width * data->cell_width, data->win_height * data->cell_height,
447 data->hMemDC, data->win_pos.X * data->cell_width, data->win_pos.Y * data->cell_height,
448 SRCCOPY);
449 if (data->hasSelection)
450 WCUSER_SetSelection(data, ps.hdc);
451 EndPaint(data->hWnd, &ps);
452}
453
454/******************************************************************
455 * WCUSER_Scroll
456 *
457 *
458 */
459static void WCUSER_Scroll(struct inner_data* data, int pos, BOOL horz)
460{
461 if (horz)
462 {
463 SetScrollPos(data->hWnd, SB_HORZ, pos, TRUE);
464 data->win_pos.X = pos;
465 InvalidateRect(data->hWnd, NULL, FALSE);
466 }
467 else
468 {
469 SetScrollPos(data->hWnd, SB_VERT, pos, TRUE);
470 data->win_pos.Y = pos;
471 }
472 InvalidateRect(data->hWnd, NULL, FALSE);
473}
474
475struct font_chooser {
476 struct inner_data* data;
477 int done;
478};
479
480/******************************************************************
481 * WCUSER_ValidateFontMetric
482 *
483 * Returns true if the font described in tm is usable as a font for the renderer
484 */
485BOOL WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm)
486{
487 return tm->tmMaxCharWidth * data->win_width < GetSystemMetrics(SM_CXSCREEN) &&
488 tm->tmHeight * data->win_height < GetSystemMetrics(SM_CYSCREEN) &&
489 !tm->tmItalic && !tm->tmUnderlined && !tm->tmStruckOut;
490}
491
492/******************************************************************
493 * WCUSER_ValidateFont
494 *
495 * Returns true if the font family described in lf is usable as a font for the renderer
496 */
497BOOL WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf)
498{
499 return (lf->lfPitchAndFamily & 3) == FIXED_PITCH && (lf->lfPitchAndFamily & 0xF0) == FF_MODERN;
500}
501
502/******************************************************************
503 * get_first_font_enum_2
504 * get_first_font_enum
505 *
506 * Helper functions to get a decent font for the renderer
507 */
508static int CALLBACK get_first_font_enum_2(const LOGFONT* lf, const TEXTMETRIC* tm,
509 DWORD FontType, LPARAM lParam)
510{
511 struct font_chooser* fc = (struct font_chooser*)lParam;
512
513 if (WCUSER_ValidateFontMetric(fc->data, tm))
514 {
515 WCUSER_SetFont(fc->data, lf, tm);
516 fc->done = 1;
517 return 0;
518 }
519 return 1;
520}
521
522static int CALLBACK get_first_font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
523 DWORD FontType, LPARAM lParam)
524{
525 struct font_chooser* fc = (struct font_chooser*)lParam;
526
527 if (WCUSER_ValidateFont(fc->data, lf))
528 {
529 EnumFontFamilies(fc->data->hMemDC, lf->lfFaceName, get_first_font_enum_2, lParam);
530 return !fc->done; /* we just need the first matching one... */
531 }
532 return 1;
533}
534
535/******************************************************************
536 * WCUSER_Create
537 *
538 * Creates the window for the rendering
539 */
540static LRESULT WCUSER_Create(HWND hWnd, LPCREATESTRUCT lpcs)
541{
542 struct inner_data* data;
543 HMENU hMenu;
544 HMENU hSubMenu;
545 WCHAR buff[256];
546 HINSTANCE hInstance = GetModuleHandle(NULL);
547
548 data = lpcs->lpCreateParams;
549 SetWindowLong(hWnd, 0L, (DWORD)data);
550 data->hWnd = hWnd;
551
552 data->cursor_size = 101; /* invalid value, will trigger a complete cleanup */
553 /* FIXME: error handling & memory cleanup */
554 hSubMenu = CreateMenu();
555 if (!hSubMenu) return 0;
556
557 hMenu = GetSystemMenu(hWnd, FALSE);
558 if (!hMenu) return 0;
559
560 LoadString(hInstance, IDS_MARK, buff, sizeof(buff) / sizeof(WCHAR));
561 InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff);
562 LoadString(hInstance, IDS_COPY, buff, sizeof(buff) / sizeof(WCHAR));
563 InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff);
564 LoadString(hInstance, IDS_PASTE, buff, sizeof(buff) / sizeof(WCHAR));
565 InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff);
566 LoadString(hInstance, IDS_SELECTALL, buff, sizeof(buff) / sizeof(WCHAR));
567 InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff);
568 LoadString(hInstance, IDS_SCROLL, buff, sizeof(buff) / sizeof(WCHAR));
569 InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff);
570 LoadString(hInstance, IDS_SEARCH, buff, sizeof(buff) / sizeof(WCHAR));
571 InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff);
572
573 InsertMenu(hMenu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
574 LoadString(hInstance, IDS_EDIT, buff, sizeof(buff) / sizeof(WCHAR));
575 InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)hSubMenu, buff);
576 LoadString(hInstance, IDS_DEFAULT, buff, sizeof(buff) / sizeof(WCHAR));
577 InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff);
578 LoadString(hInstance, IDS_PROPERTY, buff, sizeof(buff) / sizeof(WCHAR));
579 InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTY, buff);
580
581 data->hMemDC = CreateCompatibleDC(0);
582 if (!data->hMemDC) {Trace(0, "no mem dc\n");return 0;}
583
584 return 0;
585}
586
587/******************************************************************
588 * WCUSER_SetMenuDetails
589 *
590 * Grays / ungrays the menu items according to their state
591 */
592static void WCUSER_SetMenuDetails(const struct inner_data* data)
593{
594 HMENU hMenu = GetSystemMenu(data->hWnd, FALSE);
595
596 if (!hMenu) {Trace(0, "Issue in getting menu bits\n");return;}
597
598 /* FIXME: set the various menu items to their state (if known) */
599 EnableMenuItem(hMenu, IDS_DEFAULT, MF_BYCOMMAND|MF_GRAYED);
600
601 EnableMenuItem(hMenu, IDS_MARK, MF_BYCOMMAND|MF_GRAYED);
602 EnableMenuItem(hMenu, IDS_COPY, MF_BYCOMMAND|(data->hasSelection ? MF_ENABLED : MF_GRAYED));
603 EnableMenuItem(hMenu, IDS_PASTE,
604 MF_BYCOMMAND|(IsClipboardFormatAvailable(CF_UNICODETEXT)
605 ? MF_ENABLED : MF_GRAYED));
606 /* Select all: always active */
607 EnableMenuItem(hMenu, IDS_SCROLL, MF_BYCOMMAND|MF_GRAYED);
608 EnableMenuItem(hMenu, IDS_SEARCH, MF_BYCOMMAND|MF_GRAYED);
609}
610
611/******************************************************************
612 * WCUSER_GenerateInputRecord
613 *
614 * generates input_record from windows WM_KEYUP/WM_KEYDOWN messages
615 */
616static void WCUSER_GenerateInputRecord(struct inner_data* data, BOOL down,
617 WPARAM wParam, LPARAM lParam, BOOL sys)
618{
619 INPUT_RECORD ir;
620 DWORD n;
621 WCHAR buf[2];
622 BYTE keyState[256];
623 static WCHAR last; /* keep last char seen as feed for key up message */
624
625 ir.EventType = KEY_EVENT;
626 ir.Event.KeyEvent.bKeyDown = down;
627 ir.Event.KeyEvent.wRepeatCount = LOWORD(lParam);
628 ir.Event.KeyEvent.wVirtualKeyCode = wParam;
629
630 ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lParam) & 0xFF;
631 GetKeyboardState(keyState);
632
633 ir.Event.KeyEvent.uChar.UnicodeChar = 0;
634 ir.Event.KeyEvent.dwControlKeyState = 0;
635 if (lParam & (1L << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
636 if (keyState[VK_SHIFT] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
637 if (keyState[VK_CONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; /* FIXME: gotta choose one */
638 if (keyState[VK_LCONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
639 if (keyState[VK_RCONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
640 if (sys) ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; /* FIXME: gotta choose one */
641 if (keyState[VK_LMENU] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED;
642 if (keyState[VK_RMENU] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
643 if (keyState[VK_CAPITAL] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= CAPSLOCK_ON;
644 if (keyState[VK_NUMLOCK] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= NUMLOCK_ON;
645 if (keyState[VK_SCROLL] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= SCROLLLOCK_ON;
646
647 if (data->hasSelection && ir.Event.KeyEvent.dwControlKeyState == 0 &&
648 ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN)
649 {
650 data->hasSelection = FALSE;
651 WCUSER_SetSelection(data, 0);
652 WCUSER_CopySelectionToClipboard(data);
653 return;
654 }
655
656 if (!(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
657 {
658 if (down)
659 {
660 switch (ToUnicode(wParam, HIWORD(lParam), keyState, buf, 2, 0))
661 {
662 case 2:
663 /* FIXME... should generate two events... */
664 /* fall thru */
665 case 1:
666 last = buf[0];
667 break;
668 default:
669 last = 0;
670 break;
671 }
672 }
673 ir.Event.KeyEvent.uChar.UnicodeChar = last; /* FIXME HACKY... and buggy 'coz it should be a stack, not a single value */
674 if (!down) last = 0;
675 }
676
677 WriteConsoleInput(data->hConIn, &ir, 1, &n);
678}
679
680/******************************************************************
681 * WCUSER_Proc
682 *
683 *
684 */
685static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
686{
687 struct inner_data* data = (struct inner_data*)GetWindowLong(hWnd, 0);
688
689 switch (uMsg)
690 {
691 case WM_CREATE:
692 return WCUSER_Create(hWnd, (LPCREATESTRUCT)lParam);
693 case WM_DESTROY:
694 data->hWnd = 0;
695 PostQuitMessage(0);
696 break;
697 case WM_PAINT:
698 WCUSER_Paint(data);
699 break;
700 case WM_KEYDOWN:
701 case WM_KEYUP:
702 WCUSER_GenerateInputRecord(data, uMsg == WM_KEYDOWN, wParam, lParam, FALSE);
703 break;
704 case WM_SYSKEYDOWN:
705 case WM_SYSKEYUP:
706 WCUSER_GenerateInputRecord(data, uMsg == WM_SYSKEYDOWN, wParam, lParam, TRUE);
707 break;
708 case WM_LBUTTONDOWN:
709 /* EPP if (wParam != MK_LBUTTON) */
710 if (data->hasSelection)
711 {
712 data->hasSelection = FALSE;
713 }
714 else
715 {
716 data->selectPt1 = data->selectPt2 = WCUSER_GetCell(data, lParam);
717 SetCapture(data->hWnd);
718 }
719 WCUSER_SetSelection(data, 0);
720 break;
721 case WM_MOUSEMOVE:
722 /* EPP if (wParam != MK_LBUTTON) */
723 if (GetCapture() == data->hWnd)
724 {
725 WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), FALSE);
726 }
727 break;
728 case WM_LBUTTONUP:
729 /* EPP if (wParam != MK_LBUTTON) */
730 if (GetCapture() == data->hWnd)
731 {
732 WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), TRUE);
733 }
734 break;
735 case WM_SETFOCUS:
736 if (data->cursor_visible)
737 {
738 CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height);
739 WCUSER_PosCursor(data);
740 }
741 break;
742 case WM_KILLFOCUS:
743 if (data->cursor_visible)
744 DestroyCaret();
745 break;
746 case WM_HSCROLL:
747 {
748 int pos = data->win_pos.X;
749
750 switch (LOWORD(wParam))
751 {
752 case SB_PAGEUP: pos -= 8; break;
753 case SB_PAGEDOWN: pos += 8; break;
754 case SB_LINEUP: pos--; break;
755 case SB_LINEDOWN: pos++; break;
756 case SB_THUMBTRACK: pos = HIWORD(wParam); break;
757 default: break;
758 }
759 if (pos < 0) pos = 0;
760 if (pos > data->sb_width - data->win_width) pos = data->sb_width - data->win_width;
761 if (pos != data->win_pos.X)
762 {
763 ScrollWindow(hWnd, (data->win_pos.X - pos) * data->cell_width, 0, NULL, NULL);
764 data->win_pos.X = pos;
765 SetScrollPos(hWnd, SB_HORZ, pos, TRUE);
766 UpdateWindow(hWnd);
767 WCUSER_PosCursor(data);
768 WINECON_NotifyWindowChange(data);
769 }
770 }
771 break;
772 case WM_VSCROLL:
773 {
774 int pos = data->win_pos.Y;
775
776 switch (LOWORD(wParam))
777 {
778 case SB_PAGEUP: pos -= 8; break;
779 case SB_PAGEDOWN: pos += 8; break;
780 case SB_LINEUP: pos--; break;
781 case SB_LINEDOWN: pos++; break;
782 case SB_THUMBTRACK: pos = HIWORD(wParam); break;
783 default: break;
784 }
785 if (pos < 0) pos = 0;
786 if (pos > data->sb_height - data->win_height) pos = data->sb_height - data->win_height;
787 if (pos != data->win_pos.Y)
788 {
789 ScrollWindow(hWnd, 0, (data->win_pos.Y - pos) * data->cell_height, NULL, NULL);
790 data->win_pos.Y = pos;
791 SetScrollPos(hWnd, SB_VERT, pos, TRUE);
792 UpdateWindow(hWnd);
793 WCUSER_PosCursor(data);
794 WINECON_NotifyWindowChange(data);
795 }
796 }
797 break;
798 case WM_SYSCOMMAND:
799 switch (wParam)
800 {
801 case IDS_DEFAULT:
802 Trace(0, "unhandled yet command: %x\n", wParam);
803 break;
804 case IDS_PROPERTY:
805 WCUSER_GetProperties(data);
806 break;
807 default:
808 return DefWindowProc(hWnd, uMsg, wParam, lParam);
809 }
810 break;
811 case WM_RBUTTONDOWN:
812 WCUSER_GetProperties(data);
813 break;
814 case WM_COMMAND:
815 switch (wParam)
816 {
817 case IDS_MARK:
818 goto niy;
819 case IDS_COPY:
820 data->hasSelection = FALSE;
821 WCUSER_SetSelection(data, 0);
822 WCUSER_CopySelectionToClipboard(data);
823 break;
824 case IDS_PASTE:
825 WCUSER_PasteFromClipboard(data);
826 break;
827 case IDS_SELECTALL:
828 data->selectPt1.X = data->selectPt1.Y = 0;
829 data->selectPt2.X = (data->sb_width - 1) * data->cell_width;
830 data->selectPt2.Y = (data->sb_height - 1) * data->cell_height;
831 WCUSER_SetSelection(data, 0);
832 data->hasSelection = TRUE;
833 break;
834 case IDS_SCROLL:
835 case IDS_SEARCH:
836 niy:
837 Trace(0, "unhandled yet command: %x\n", wParam);
838 break;
839 default:
840 return DefWindowProc(hWnd, uMsg, wParam, lParam);
841 }
842 break;
843 case WM_INITMENUPOPUP:
844 if (!HIWORD(lParam)) return DefWindowProc(hWnd, uMsg, wParam, lParam);
845 WCUSER_SetMenuDetails(data);
846 break;
847 default:
848 return DefWindowProc(hWnd, uMsg, wParam, lParam);
849 }
850 return 0;
851}
852
853/******************************************************************
854 * WCUSER_DeleteBackend
855 *
856 *
857 */
858void WCUSER_DeleteBackend(struct inner_data* data)
859{
860 if (data->hWnd) DestroyWindow(data->hWnd);
861 if (data->hFont) DeleteObject(data->hFont);
862 if (data->cursor_bitmap) DeleteObject(data->cursor_bitmap);
863 if (data->hMemDC) DeleteDC(data->hMemDC);
864 if (data->hBitmap) DeleteObject(data->hBitmap);
865}
866
867/******************************************************************
868 * WCUSER_MainLoop
869 *
870 *
871 */
872static int WCUSER_MainLoop(struct inner_data* data)
873{
874 MSG msg;
875
876 for (;;)
877 {
878 switch (MsgWaitForMultipleObjects(1, &data->hSynchro, FALSE, INFINITE, QS_ALLINPUT))
879 {
880 case WAIT_OBJECT_0:
881 if (!WINECON_GrabChanges(data))
882 PostQuitMessage(0);
883 break;
884 case WAIT_OBJECT_0+1:
885 switch (GetMessage(&msg, 0, 0, 0))
886 {
887 case -1: /* the event handle became invalid, so exit */
888 return -1;
889 case 0: /* WM_QUIT has been posted */
890 return 0;
891 default:
892 DispatchMessage(&msg);
893 break;
894 }
895 break;
896 default:
897 Trace(0, "got pb\n");
898 /* err */
899 break;
900 }
901 }
902}
903
904/******************************************************************
905 * WCUSER_InitBackend
906 *
907 * Initialisation part II: creation of window.
908 *
909 */
910BOOL WCUSER_InitBackend(struct inner_data* data)
911{
912 static WCHAR wClassName[] = {'W','i','n','e','C','o','n','s','o','l','e','C','l','a','s','s',0};
913
914 WNDCLASS wndclass;
915 struct font_chooser fc;
916
917 data->fnMainLoop = WCUSER_MainLoop;
918 data->fnPosCursor = WCUSER_PosCursor;
919 data->fnShapeCursor = WCUSER_ShapeCursor;
920 data->fnComputePositions = WCUSER_ComputePositions;
921 data->fnRefresh = WCUSER_Refresh;
922 data->fnResizeScreenBuffer = WCUSER_ResizeScreenBuffer;
923 data->fnSetTitle = WCUSER_SetTitle;
924 data->fnScroll = WCUSER_Scroll;
925 data->fnDeleteBackend = WCUSER_DeleteBackend;
926
927 wndclass.style = 0;
928 wndclass.lpfnWndProc = WCUSER_Proc;
929 wndclass.cbClsExtra = 0;
930 wndclass.cbWndExtra = sizeof(DWORD);
931 wndclass.hInstance = GetModuleHandle(NULL);
932 wndclass.hIcon = LoadIcon(0, IDI_WINLOGO);
933 wndclass.hCursor = LoadCursor(0, IDC_ARROW);
934 wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
935 wndclass.lpszMenuName = NULL;
936 wndclass.lpszClassName = wClassName;
937
938 RegisterClass(&wndclass);
939
940 CreateWindow(wndclass.lpszClassName, NULL,
941 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_HSCROLL|WS_VSCROLL,
942 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, 0, wndclass.hInstance, data);
943 if (!data->hWnd) return FALSE;
944
945 /* force update of current data */
946 WINECON_GrabChanges(data);
947
948 /* try to find an acceptable font */
949 fc.data = data;
950 fc.done = 0;
951 EnumFontFamilies(data->hMemDC, NULL, get_first_font_enum, (LPARAM)&fc);
952
953 return fc.done;
954}
955
956
957