Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/conhost/window.c
8553 views
1
/*
2
* Copyright 2001 Eric Pouech
3
* Copyright 2020 Jacek Caban for CodeWeavers
4
*
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
9
*
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
14
*
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18
*/
19
20
#include <stdlib.h>
21
22
#include "conhost.h"
23
24
#include <commctrl.h>
25
#include <winreg.h>
26
27
#include "wine/debug.h"
28
29
WINE_DEFAULT_DEBUG_CHANNEL(console);
30
31
#define WM_UPDATE_CONFIG (WM_USER + 1)
32
33
enum update_state
34
{
35
UPDATE_NONE,
36
UPDATE_PENDING,
37
UPDATE_BUSY
38
};
39
40
struct console_window
41
{
42
HDC mem_dc; /* memory DC holding the bitmap below */
43
HBITMAP bitmap; /* bitmap of display window content */
44
HFONT font; /* font used for rendering, usually fixed */
45
HMENU popup_menu; /* popup menu triggered by right mouse click */
46
HBITMAP cursor_bitmap; /* bitmap used for the caret */
47
BOOL in_selection; /* an area is being selected */
48
COORD selection_start; /* selection coordinates */
49
COORD selection_end;
50
unsigned int ui_charset; /* default UI charset */
51
WCHAR *config_key; /* config registry key name */
52
LONG ext_leading; /* external leading for font */
53
54
BOOL quick_edit; /* whether mouse ops are sent to app or used for content selection */
55
unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
56
COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
57
unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
58
unsigned int win_height;
59
unsigned int cursor_size; /* in % of cell height */
60
int cursor_visible; /* cursor visibility */
61
unsigned int sb_width; /* active screen buffer width */
62
unsigned int sb_height; /* active screen buffer height */
63
COORD cursor_pos; /* cursor position */
64
unsigned int close_on_exit; /* whether conhost closes when all children have terminated */
65
66
RECT update; /* screen buffer update rect */
67
enum update_state update_state; /* update state */
68
};
69
70
struct console_config
71
{
72
DWORD color_map[16]; /* console color table */
73
unsigned int cell_width; /* width in pixels of a character */
74
unsigned int cell_height; /* height in pixels of a character */
75
unsigned int cursor_size; /* in % of cell height */
76
int cursor_visible; /* cursor visibility */
77
unsigned int attr; /* default fill attributes (screen colors) */
78
unsigned int popup_attr ; /* pop-up color attributes */
79
unsigned int history_size; /* number of commands in history buffer */
80
unsigned int history_mode; /* flag if commands are not stored twice in buffer */
81
unsigned int insert_mode; /* TRUE to insert text at the cursor location; FALSE to overwrite it */
82
unsigned int menu_mask; /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
83
unsigned int quick_edit; /* whether mouse ops are sent to app or used for content selection */
84
unsigned int sb_width; /* active screen buffer width */
85
unsigned int sb_height; /* active screen buffer height */
86
unsigned int win_width; /* size (in cells) of visible part of window (width & height) */
87
unsigned int win_height;
88
COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
89
unsigned int edition_mode; /* edition mode flavor while line editing */
90
unsigned int close_on_exit; /* whether conhost closes when all children have terminated */
91
unsigned int font_pitch_family;
92
unsigned int font_weight;
93
WCHAR face_name[LF_FACESIZE];
94
};
95
96
static const char *debugstr_config( const struct console_config *config )
97
{
98
return wine_dbg_sprintf( "cell=(%u,%u) cursor=(%d,%d) attr=%02x pop-up=%02x font=%s/%u/%u "
99
"hist=%u/%d flags=%c%c msk=%08x sb=(%u,%u) win=(%u,%u)x(%u,%u) edit=%u "
100
"close_on_exit=%u",
101
config->cell_width, config->cell_height, config->cursor_size,
102
config->cursor_visible, config->attr, config->popup_attr,
103
wine_dbgstr_w(config->face_name), config->font_pitch_family,
104
config->font_weight, config->history_size,
105
config->history_mode ? 1 : 2,
106
config->insert_mode ? 'I' : 'i',
107
config->quick_edit ? 'Q' : 'q',
108
config->menu_mask, config->sb_width, config->sb_height,
109
config->win_pos.X, config->win_pos.Y, config->win_width,
110
config->win_height, config->edition_mode, config->close_on_exit );
111
}
112
113
static const char *debugstr_logfont( const LOGFONTW *lf, unsigned int ft )
114
{
115
return wine_dbg_sprintf( "%s%s%s%s lfHeight=%ld lfWidth=%ld lfEscapement=%ld "
116
"lfOrientation=%ld lfWeight=%ld lfItalic=%u lfUnderline=%u "
117
"lfStrikeOut=%u lfCharSet=%u lfPitchAndFamily=%u lfFaceName=%s",
118
(ft & RASTER_FONTTYPE) ? "raster" : "",
119
(ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
120
((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
121
(ft & DEVICE_FONTTYPE) ? "|device" : "",
122
lf->lfHeight, lf->lfWidth, lf->lfEscapement, lf->lfOrientation,
123
lf->lfWeight, lf->lfItalic, lf->lfUnderline, lf->lfStrikeOut,
124
lf->lfCharSet, lf->lfPitchAndFamily, wine_dbgstr_w( lf->lfFaceName ));
125
}
126
127
static const char *debugstr_textmetric( const TEXTMETRICW *tm, unsigned int ft )
128
{
129
return wine_dbg_sprintf( "%s%s%s%s tmHeight=%ld tmAscent=%ld tmDescent=%ld "
130
"tmAveCharWidth=%ld tmMaxCharWidth=%ld tmWeight=%ld "
131
"tmPitchAndFamily=%u tmCharSet=%u",
132
(ft & RASTER_FONTTYPE) ? "raster" : "",
133
(ft & TRUETYPE_FONTTYPE) ? "truetype" : "",
134
((ft & (RASTER_FONTTYPE|TRUETYPE_FONTTYPE)) == 0) ? "vector" : "",
135
(ft & DEVICE_FONTTYPE) ? "|device" : "",
136
tm->tmHeight, tm->tmAscent, tm->tmDescent, tm->tmAveCharWidth,
137
tm->tmMaxCharWidth, tm->tmWeight, tm->tmPitchAndFamily,
138
tm->tmCharSet );
139
}
140
141
/* read the basic configuration from any console key or subkey */
142
static void load_registry_key( HKEY key, struct console_config *config )
143
{
144
DWORD type, count, val, i;
145
WCHAR color_name[13];
146
147
count = sizeof(val);
148
if (!RegQueryValueExW( key, L"CloseOnExit", 0, &type, (BYTE *)&val, &count ))
149
config->close_on_exit = val;
150
151
for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
152
{
153
wsprintfW( color_name, L"ColorTable%02d", i );
154
count = sizeof(val);
155
if (!RegQueryValueExW( key, color_name, 0, &type, (BYTE *)&val, &count ))
156
config->color_map[i] = val;
157
}
158
159
count = sizeof(val);
160
if (!RegQueryValueExW( key, L"CursorSize", 0, &type, (BYTE *)&val, &count ))
161
config->cursor_size = val;
162
163
count = sizeof(val);
164
if (!RegQueryValueExW( key, L"CursorVisible", 0, &type, (BYTE *)&val, &count ))
165
config->cursor_visible = val;
166
167
count = sizeof(val);
168
if (!RegQueryValueExW( key, L"EditionMode", 0, &type, (BYTE *)&val, &count ))
169
config->edition_mode = val;
170
171
count = sizeof(config->face_name);
172
RegQueryValueExW( key, L"FaceName", 0, &type, (BYTE *)&config->face_name, &count );
173
174
count = sizeof(val);
175
if (!RegQueryValueExW( key, L"FontFamily", 0, &type, (BYTE *)&val, &count ) ||
176
!RegQueryValueExW( key, L"FontPitchFamily", 0, &type, (BYTE *)&val, &count ))
177
config->font_pitch_family = val;
178
179
count = sizeof(val);
180
if (!RegQueryValueExW( key, L"FontSize", 0, &type, (BYTE *)&val, &count ))
181
{
182
int height = HIWORD(val);
183
int width = LOWORD(val);
184
/* A value of zero reflects the default settings */
185
if (height) config->cell_height = MulDiv( height, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
186
if (width) config->cell_width = MulDiv( width, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
187
}
188
189
count = sizeof(val);
190
if (!RegQueryValueExW( key, L"FontWeight", 0, &type, (BYTE *)&val, &count ))
191
config->font_weight = val;
192
193
count = sizeof(val);
194
if (!RegQueryValueExW( key, L"HistoryBufferSize", 0, &type, (BYTE *)&val, &count ))
195
config->history_size = val;
196
197
count = sizeof(val);
198
if (!RegQueryValueExW( key, L"HistoryNoDup", 0, &type, (BYTE *)&val, &count ))
199
config->history_mode = val;
200
201
count = sizeof(val);
202
if (!RegQueryValueExW( key, L"wszInsertMode", 0, &type, (BYTE *)&val, &count ))
203
config->insert_mode = val;
204
205
count = sizeof(val);
206
if (!RegQueryValueExW( key, L"MenuMask", 0, &type, (BYTE *)&val, &count ))
207
config->menu_mask = val;
208
209
count = sizeof(val);
210
if (!RegQueryValueExW( key, L"PopupColors", 0, &type, (BYTE *)&val, &count ))
211
config->popup_attr = val;
212
213
count = sizeof(val);
214
if (!RegQueryValueExW( key, L"QuickEdit", 0, &type, (BYTE *)&val, &count ))
215
config->quick_edit = val;
216
217
count = sizeof(val);
218
if (!RegQueryValueExW( key, L"ScreenBufferSize", 0, &type, (BYTE *)&val, &count ))
219
{
220
config->sb_height = HIWORD(val);
221
config->sb_width = LOWORD(val);
222
}
223
224
count = sizeof(val);
225
if (!RegQueryValueExW( key, L"ScreenColors", 0, &type, (BYTE *)&val, &count ))
226
config->attr = val;
227
228
count = sizeof(val);
229
if (!RegQueryValueExW( key, L"WindowSize", 0, &type, (BYTE *)&val, &count ))
230
{
231
config->win_height = HIWORD(val);
232
config->win_width = LOWORD(val);
233
}
234
}
235
236
/* load config from registry */
237
static void load_config( const WCHAR *key_name, struct console_config *config )
238
{
239
static const COLORREF color_map[] =
240
{
241
RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
242
RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0xC0, 0xC0, 0xC0),
243
RGB(0x80, 0x80, 0x80), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
244
RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF)
245
};
246
247
HKEY key, app_key;
248
249
TRACE( "Loading default console settings\n" );
250
251
memcpy( config->color_map, color_map, sizeof(color_map) );
252
memset( config->face_name, 0, sizeof(config->face_name) );
253
config->cursor_size = 25;
254
config->cursor_visible = 1;
255
config->font_pitch_family = FIXED_PITCH | FF_DONTCARE;
256
config->cell_height = MulDiv( 16, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
257
config->cell_width = MulDiv( 8, GetDpiForSystem(), USER_DEFAULT_SCREEN_DPI );
258
config->font_weight = FW_NORMAL;
259
260
config->history_size = 50;
261
config->history_mode = 0;
262
config->insert_mode = 1;
263
config->menu_mask = 0;
264
config->popup_attr = 0xF5;
265
config->quick_edit = 0;
266
config->sb_height = 150;
267
config->sb_width = 80;
268
config->attr = 0x000F;
269
config->win_height = 25;
270
config->win_width = 80;
271
config->win_pos.X = 0;
272
config->win_pos.Y = 0;
273
config->edition_mode = 0;
274
config->close_on_exit= 1;
275
276
/* Load default console settings */
277
if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Console", &key ))
278
{
279
load_registry_key( key, config );
280
281
/* Load app-specific console settings (if any) */
282
if (key_name && !RegOpenKeyW( key, key_name, &app_key ))
283
{
284
TRACE( "Loading %s console settings\n", wine_dbgstr_w(key_name) );
285
load_registry_key( app_key, config );
286
RegCloseKey( app_key );
287
}
288
RegCloseKey( key );
289
}
290
TRACE( "%s\n", debugstr_config( config ));
291
}
292
293
static void save_registry_key( HKEY key, const struct console_config *config, BOOL save_all )
294
{
295
struct console_config default_config;
296
DWORD val, width, height, i;
297
WCHAR color_name[13];
298
299
TRACE( "%s\n", debugstr_config( config ));
300
301
if (!save_all)
302
load_config( NULL, &default_config );
303
304
if (save_all || config->close_on_exit != default_config.close_on_exit)
305
{
306
val = config->close_on_exit;
307
RegSetValueExW( key, L"CloseOnExit", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
308
}
309
310
for (i = 0; i < ARRAY_SIZE(config->color_map); i++)
311
{
312
if (save_all || config->color_map[i] != default_config.color_map[i])
313
{
314
wsprintfW( color_name, L"ColorTable%02d", i );
315
val = config->color_map[i];
316
RegSetValueExW( key, color_name, 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
317
}
318
}
319
320
if (save_all || config->cursor_size != default_config.cursor_size)
321
{
322
val = config->cursor_size;
323
RegSetValueExW( key, L"CursorSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
324
}
325
326
if (save_all || config->cursor_visible != default_config.cursor_visible)
327
{
328
val = config->cursor_visible;
329
RegSetValueExW( key, L"CursorVisible", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
330
}
331
332
if (save_all || config->edition_mode != default_config.edition_mode)
333
{
334
val = config->edition_mode;
335
RegSetValueExW( key, L"EditionMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
336
}
337
338
if (save_all || lstrcmpW( config->face_name, default_config.face_name ))
339
{
340
RegSetValueExW( key, L"FaceName", 0, REG_SZ, (BYTE *)&config->face_name,
341
(lstrlenW(config->face_name) + 1) * sizeof(WCHAR) );
342
}
343
344
if (save_all || config->font_pitch_family != default_config.font_pitch_family)
345
{
346
val = config->font_pitch_family;
347
RegSetValueExW( key, L"FontFamily", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
348
}
349
350
if (save_all || config->cell_height != default_config.cell_height ||
351
config->cell_width != default_config.cell_width)
352
{
353
width = MulDiv( config->cell_width, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
354
height = MulDiv( config->cell_height, USER_DEFAULT_SCREEN_DPI, GetDpiForSystem() );
355
val = MAKELONG( width, height );
356
357
RegSetValueExW( key, L"FontSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
358
}
359
360
if (save_all || config->font_weight != default_config.font_weight)
361
{
362
val = config->font_weight;
363
RegSetValueExW( key, L"FontWeight", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
364
}
365
366
if (save_all || config->history_size != default_config.history_size)
367
{
368
val = config->history_size;
369
RegSetValueExW( key, L"HistoryBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
370
}
371
372
if (save_all || config->history_mode != default_config.history_mode)
373
{
374
val = config->history_mode;
375
RegSetValueExW( key, L"HistoryNoDup", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
376
}
377
378
if (save_all || config->insert_mode != default_config.insert_mode)
379
{
380
val = config->insert_mode;
381
RegSetValueExW( key, L"InsertMode", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
382
}
383
384
if (save_all || config->menu_mask != default_config.menu_mask)
385
{
386
val = config->menu_mask;
387
RegSetValueExW( key, L"MenuMask", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
388
}
389
390
if (save_all || config->popup_attr != default_config.popup_attr)
391
{
392
val = config->popup_attr;
393
RegSetValueExW( key, L"PopupColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
394
}
395
396
if (save_all || config->quick_edit != default_config.quick_edit)
397
{
398
val = config->quick_edit;
399
RegSetValueExW( key, L"QuickEdit", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
400
}
401
402
if (save_all || config->sb_width != default_config.sb_width ||
403
config->sb_height != default_config.sb_height)
404
{
405
val = MAKELONG(config->sb_width, config->sb_height);
406
RegSetValueExW( key, L"ScreenBufferSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
407
}
408
409
if (save_all || config->attr != default_config.attr)
410
{
411
val = config->attr;
412
RegSetValueExW( key, L"ScreenColors", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
413
}
414
415
if (save_all || config->win_width != default_config.win_width ||
416
config->win_height != default_config.win_height)
417
{
418
val = MAKELONG( config->win_width, config->win_height );
419
RegSetValueExW( key, L"WindowSize", 0, REG_DWORD, (BYTE *)&val, sizeof(val) );
420
}
421
}
422
423
static void save_config( const WCHAR *key_name, const struct console_config *config )
424
{
425
HKEY key, app_key;
426
427
TRACE( "Saving %s console settings\n", key_name ? debugstr_w( key_name ) : "default" );
428
429
if (RegCreateKeyW( HKEY_CURRENT_USER, L"Console", &key ))
430
{
431
ERR("Can't open registry for saving\n");
432
return;
433
}
434
435
if (key_name)
436
{
437
if (RegCreateKeyW( key, key_name, &app_key ))
438
{
439
ERR("Can't open registry for saving\n");
440
}
441
else
442
{
443
save_registry_key( app_key, config, FALSE );
444
RegCloseKey( app_key );
445
}
446
}
447
else save_registry_key( key, config, TRUE );
448
RegCloseKey(key);
449
}
450
451
/* fill memory DC with current cells values */
452
static void fill_mem_dc( struct console *console, const RECT *update )
453
{
454
unsigned int i, j, k;
455
unsigned int attr;
456
char_info_t *cell;
457
HFONT old_font;
458
HBRUSH brush;
459
WCHAR *line;
460
INT *dx;
461
RECT r;
462
463
if (!console->window->font || !console->window->bitmap)
464
return;
465
466
if (!(line = malloc( (update->right - update->left + 1) * sizeof(WCHAR))) ) return;
467
dx = malloc( (update->right - update->left + 1) * sizeof(*dx) );
468
469
old_font = SelectObject( console->window->mem_dc, console->window->font );
470
for (j = update->top; j <= update->bottom; j++)
471
{
472
cell = &console->active->data[j * console->active->width];
473
for (i = update->left; i <= update->right; i++)
474
{
475
attr = cell[i].attr;
476
SetBkColor( console->window->mem_dc, console->active->color_map[(attr >> 4) & 0x0F] );
477
SetTextColor( console->window->mem_dc, console->active->color_map[attr & 0x0F] );
478
for (k = i; k <= update->right && cell[k].attr == attr; k++)
479
{
480
line[k - i] = cell[k].ch;
481
dx[k - i] = console->active->font.width;
482
}
483
ExtTextOutW( console->window->mem_dc, i * console->active->font.width,
484
j * console->active->font.height, 0, NULL, line, k - i, dx );
485
if (console->window->ext_leading &&
486
(brush = CreateSolidBrush( console->active->color_map[(attr >> 4) & 0x0F] )))
487
{
488
r.left = i * console->active->font.width;
489
r.top = (j + 1) * console->active->font.height - console->window->ext_leading;
490
r.right = k * console->active->font.width;
491
r.bottom = (j + 1) * console->active->font.height;
492
FillRect( console->window->mem_dc, &r, brush );
493
DeleteObject( brush );
494
}
495
i = k - 1;
496
}
497
}
498
SelectObject( console->window->mem_dc, old_font );
499
free( dx );
500
free( line );
501
}
502
503
/* set a new position for the cursor */
504
static void update_window_cursor( struct console *console )
505
{
506
if (!console->active->cursor_visible || console->win != GetFocus()) return;
507
508
SetCaretPos( (get_bounded_cursor_x( console->active ) - console->active->win.left) * console->active->font.width,
509
(console->active->cursor_y - console->active->win.top) * console->active->font.height );
510
ShowCaret( console->win );
511
}
512
513
/* sets a new shape for the cursor */
514
static void shape_cursor( struct console *console )
515
{
516
int size = console->active->cursor_size;
517
518
if (console->active->cursor_visible && console->win == GetFocus()) DestroyCaret();
519
if (console->window->cursor_bitmap) DeleteObject( console->window->cursor_bitmap );
520
console->window->cursor_bitmap = NULL;
521
console->window->cursor_visible = FALSE;
522
523
if (size != 100)
524
{
525
int w16b; /* number of bytes per row, aligned on word size */
526
int i, j, nbl;
527
BYTE *ptr;
528
529
w16b = ((console->active->font.width + 15) & ~15) / 8;
530
ptr = calloc( w16b, console->active->font.height );
531
if (!ptr) return;
532
nbl = max( (console->active->font.height * size) / 100, 1 );
533
for (j = console->active->font.height - nbl; j < console->active->font.height; j++)
534
{
535
for (i = 0; i < console->active->font.width; i++)
536
{
537
ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
538
}
539
}
540
console->window->cursor_bitmap = CreateBitmap( console->active->font.width,
541
console->active->font.height, 1, 1, ptr );
542
free(ptr);
543
}
544
}
545
546
static void update_window( struct console *console )
547
{
548
unsigned int win_width, win_height;
549
BOOL update_all = FALSE;
550
int dx, dy;
551
RECT r;
552
553
console->window->update_state = UPDATE_BUSY;
554
555
if (console->window->sb_width != console->active->width ||
556
console->window->sb_height != console->active->height ||
557
(!console->window->bitmap && IsWindowVisible( console->win )))
558
{
559
console->window->sb_width = console->active->width;
560
console->window->sb_height = console->active->height;
561
562
if (console->active->width && console->active->height && console->window->font)
563
{
564
HBITMAP bitmap;
565
HDC dc;
566
RECT r;
567
568
if (!(dc = GetDC( console->win ))) return;
569
570
bitmap = CreateCompatibleBitmap( dc,
571
console->active->width * console->active->font.width,
572
console->active->height * console->active->font.height );
573
ReleaseDC( console->win, dc );
574
SelectObject( console->window->mem_dc, bitmap );
575
576
if (console->window->bitmap) DeleteObject( console->window->bitmap );
577
console->window->bitmap = bitmap;
578
SetRect( &r, 0, 0, console->active->width - 1, console->active->height - 1 );
579
fill_mem_dc( console, &r );
580
}
581
582
empty_update_rect( console->active, &console->window->update );
583
update_all = TRUE;
584
}
585
586
/* compute window size from desired client size */
587
win_width = console->active->win.right - console->active->win.left + 1;
588
win_height = console->active->win.bottom - console->active->win.top + 1;
589
590
if (update_all || win_width != console->window->win_width ||
591
win_height != console->window->win_height)
592
{
593
console->window->win_width = win_width;
594
console->window->win_height = win_height;
595
596
r.left = r.top = 0;
597
r.right = win_width * console->active->font.width;
598
r.bottom = win_height * console->active->font.height;
599
AdjustWindowRect( &r, GetWindowLongW( console->win, GWL_STYLE ), FALSE );
600
601
dx = dy = 0;
602
if (console->active->width > win_width)
603
{
604
dy = GetSystemMetrics( SM_CYHSCROLL );
605
SetScrollRange( console->win, SB_HORZ, 0, console->active->width - win_width, FALSE );
606
SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
607
ShowScrollBar( console->win, SB_HORZ, TRUE );
608
}
609
else
610
{
611
ShowScrollBar( console->win, SB_HORZ, FALSE );
612
}
613
614
if (console->active->height > win_height)
615
{
616
dx = GetSystemMetrics( SM_CXVSCROLL );
617
SetScrollRange( console->win, SB_VERT, 0, console->active->height - win_height, FALSE );
618
SetScrollPos( console->win, SB_VERT, console->active->win.top, FALSE );
619
ShowScrollBar( console->win, SB_VERT, TRUE );
620
}
621
else
622
ShowScrollBar( console->win, SB_VERT, FALSE );
623
624
dx += r.right - r.left;
625
dy += r.bottom - r.top;
626
SetWindowPos( console->win, 0, 0, 0, dx, dy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
627
628
SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0 );
629
console->active->max_width = (r.right - r.left) / console->active->font.width;
630
console->active->max_height = (r.bottom - r.top - GetSystemMetrics( SM_CYCAPTION )) /
631
console->active->font.height;
632
633
InvalidateRect( console->win, NULL, FALSE );
634
UpdateWindow( console->win );
635
update_all = TRUE;
636
}
637
else if (console->active->win.left != console->window->win_pos.X ||
638
console->active->win.top != console->window->win_pos.Y)
639
{
640
ScrollWindow( console->win,
641
(console->window->win_pos.X - console->active->win.left) * console->active->font.width,
642
(console->window->win_pos.Y - console->active->win.top) * console->active->font.height,
643
NULL, NULL );
644
SetScrollPos( console->win, SB_HORZ, console->active->win.left, TRUE );
645
SetScrollPos( console->win, SB_VERT, console->active->win.top, TRUE );
646
InvalidateRect( console->win, NULL, FALSE );
647
}
648
649
console->window->win_pos.X = console->active->win.left;
650
console->window->win_pos.Y = console->active->win.top;
651
652
if (console->window->update.top <= console->window->update.bottom &&
653
console->window->update.left <= console->window->update.right)
654
{
655
RECT *update = &console->window->update;
656
r.left = (update->left - console->active->win.left) * console->active->font.width;
657
r.right = (update->right - console->active->win.left + 1) * console->active->font.width;
658
r.top = (update->top - console->active->win.top) * console->active->font.height;
659
r.bottom = (update->bottom - console->active->win.top + 1) * console->active->font.height;
660
fill_mem_dc( console, update );
661
empty_update_rect( console->active, &console->window->update );
662
InvalidateRect( console->win, &r, FALSE );
663
UpdateWindow( console->win );
664
}
665
666
if (update_all || console->active->cursor_size != console->window->cursor_size)
667
{
668
console->window->cursor_size = console->active->cursor_size;
669
shape_cursor( console );
670
}
671
672
if (console->active->cursor_visible != console->window->cursor_visible)
673
{
674
console->window->cursor_visible = console->active->cursor_visible;
675
if (console->win == GetFocus())
676
{
677
if (console->window->cursor_visible)
678
{
679
CreateCaret( console->win, console->window->cursor_bitmap,
680
console->active->font.width, console->active->font.height );
681
update_window_cursor( console );
682
}
683
else
684
DestroyCaret();
685
}
686
}
687
688
if (update_all || get_bounded_cursor_x( console->active ) != console->window->cursor_pos.X ||
689
console->active->cursor_y != console->window->cursor_pos.Y)
690
{
691
console->window->cursor_pos.X = get_bounded_cursor_x( console->active );
692
console->window->cursor_pos.Y = console->active->cursor_y;
693
update_window_cursor( console );
694
}
695
696
console->window->update_state = UPDATE_NONE;
697
}
698
699
/* get the relevant information from the font described in lf and store them in config */
700
static HFONT select_font_config( struct console_config *config, unsigned int cp, HWND hwnd,
701
const LOGFONTW *lf )
702
{
703
HFONT font, old_font;
704
TEXTMETRICW tm;
705
CPINFO cpinfo;
706
HDC dc;
707
708
if (!(dc = GetDC( hwnd ))) return NULL;
709
if (!(font = CreateFontIndirectW( lf )))
710
{
711
ReleaseDC( hwnd, dc );
712
return NULL;
713
}
714
715
old_font = SelectObject( dc, font );
716
GetTextMetricsW( dc, &tm );
717
SelectObject( dc, old_font );
718
ReleaseDC( hwnd, dc );
719
720
config->cell_width = tm.tmAveCharWidth;
721
config->cell_height = tm.tmHeight + tm.tmExternalLeading;
722
config->font_weight = tm.tmWeight;
723
lstrcpyW( config->face_name, lf->lfFaceName );
724
725
/* FIXME: use maximum width for DBCS codepages since some chars take two cells */
726
if (GetCPInfo( cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
727
config->cell_width = tm.tmMaxCharWidth;
728
729
return font;
730
}
731
732
static void fill_logfont( LOGFONTW *lf, const WCHAR *face_name, size_t face_name_size,
733
unsigned int height, unsigned int weight )
734
{
735
lf->lfHeight = height;
736
lf->lfWidth = 0;
737
lf->lfEscapement = 0;
738
lf->lfOrientation = 0;
739
lf->lfWeight = weight;
740
lf->lfItalic = FALSE;
741
lf->lfUnderline = FALSE;
742
lf->lfStrikeOut = FALSE;
743
lf->lfCharSet = DEFAULT_CHARSET;
744
lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
745
lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
746
lf->lfQuality = DEFAULT_QUALITY;
747
lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
748
face_name_size = min( face_name_size, sizeof(lf->lfFaceName) - sizeof(WCHAR) );
749
memcpy( lf->lfFaceName, face_name, face_name_size );
750
lf->lfFaceName[face_name_size / sizeof(WCHAR)] = 0;
751
}
752
753
static BOOL set_console_font( struct console *console, const LOGFONTW *logfont )
754
{
755
struct font_info *font_info = &console->active->font;
756
HFONT font, old_font;
757
TEXTMETRICW tm;
758
WCHAR face_name[LF_FACESIZE];
759
CPINFO cpinfo;
760
HDC dc;
761
762
TRACE( "%s\n", debugstr_logfont( logfont, 0 ));
763
764
if (console->window->font && logfont->lfHeight == console->active->font.height &&
765
logfont->lfWeight == console->active->font.weight &&
766
!logfont->lfItalic && !logfont->lfUnderline && !logfont->lfStrikeOut &&
767
console->active->font.face_len == wcslen( logfont->lfFaceName ) &&
768
!memcmp( logfont->lfFaceName, console->active->font.face_name,
769
console->active->font.face_len * sizeof(WCHAR) ))
770
{
771
TRACE( "equal to current\n" );
772
return TRUE;
773
}
774
775
if (!(dc = GetDC( console->win ))) return FALSE;
776
if (!(font = CreateFontIndirectW( logfont )))
777
{
778
ReleaseDC( console->win, dc );
779
return FALSE;
780
}
781
782
old_font = SelectObject( dc, font );
783
GetTextMetricsW( dc, &tm );
784
font_info->face_len = GetTextFaceW( dc, ARRAY_SIZE(face_name), face_name ) - 1;
785
SelectObject( dc, old_font );
786
ReleaseDC( console->win, dc );
787
788
font_info->width = tm.tmAveCharWidth;
789
font_info->height = tm.tmHeight + tm.tmExternalLeading;
790
font_info->pitch_family = tm.tmPitchAndFamily;
791
font_info->weight = tm.tmWeight;
792
793
free( font_info->face_name );
794
font_info->face_name = malloc( font_info->face_len * sizeof(WCHAR) );
795
memcpy( font_info->face_name, face_name, font_info->face_len * sizeof(WCHAR) );
796
797
/* FIXME: use maximum width for DBCS codepages since some chars take two cells */
798
if (GetCPInfo( console->output_cp, &cpinfo ) && cpinfo.MaxCharSize == 2)
799
font_info->width = tm.tmMaxCharWidth;
800
801
if (console->window->font) DeleteObject( console->window->font );
802
console->window->font = font;
803
console->window->ext_leading = tm.tmExternalLeading;
804
805
if (console->window->bitmap)
806
{
807
DeleteObject(console->window->bitmap);
808
console->window->bitmap = NULL;
809
}
810
return TRUE;
811
}
812
813
struct font_chooser
814
{
815
struct console *console;
816
unsigned int weight;
817
LOGFONTW lf;
818
};
819
820
/* check if the font family described in lf and tm is usable as a font for the renderer */
821
static BOOL validate_font( struct console *console, const LOGFONTW *lf,
822
const TEXTMETRICW *tm, DWORD type, int *weight )
823
{
824
int w = 0x1;
825
826
if (!tm) w |= 0x6;
827
else if (!(type & RASTER_FONTTYPE))
828
{
829
w |= 0x2;
830
if (tm->tmMaxCharWidth * (console->active->win.right - console->active->win.left + 1)
831
< GetSystemMetrics(SM_CXSCREEN)
832
&& tm->tmHeight * (console->active->win.bottom - console->active->win.top + 1)
833
< GetSystemMetrics(SM_CYSCREEN))
834
w |= 0x4;
835
}
836
if ((lf->lfPitchAndFamily & 3) == FIXED_PITCH
837
&& (!tm || (!tm->tmItalic && !tm->tmUnderlined && !tm->tmStruckOut)))
838
w |= 0x8;
839
if (lf->lfCharSet == console->window->ui_charset
840
&& (!tm || tm->tmCharSet == console->window->ui_charset))
841
w |= 0x10;
842
if (lf->lfFaceName[0] != '@')
843
w |= 0x20;
844
845
if (weight) *weight = w;
846
return w == 0x3f;
847
}
848
849
static int CALLBACK enum_first_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
850
DWORD font_type, LPARAM lparam )
851
{
852
struct font_chooser *fc = (struct font_chooser *)lparam;
853
int weight;
854
BOOL ret;
855
856
TRACE( "%s\n", debugstr_logfont( lf, font_type ));
857
TRACE( "%s\n", debugstr_textmetric( tm, font_type ));
858
859
ret = validate_font( fc->console, lf, tm, font_type, &weight );
860
if (weight > fc->weight)
861
{
862
fc->weight = weight;
863
fc->lf = *lf;
864
}
865
return !ret;
866
}
867
868
static void set_first_font( struct console *console, struct console_config *config )
869
{
870
LOGFONTW lf;
871
struct font_chooser fc;
872
873
TRACE("Looking for a suitable console font\n");
874
875
memset( &lf, 0, sizeof(lf) );
876
lf.lfCharSet = DEFAULT_CHARSET;
877
lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
878
879
memset( &fc, 0, sizeof(fc) );
880
fc.console = console;
881
882
EnumFontFamiliesExW( console->window->mem_dc, &lf, enum_first_font_proc, (LPARAM)&fc, 0);
883
884
fc.lf.lfHeight = config->cell_height;
885
fc.lf.lfWidth = config->cell_width;
886
if (!fc.weight || !set_console_font( console, &fc.lf ))
887
ERR("Unable to find a valid console font\n");
888
889
/* Update active configuration */
890
config->cell_width = console->active->font.width;
891
config->cell_height = console->active->font.height;
892
config->font_pitch_family = console->active->font.pitch_family;
893
memcpy( config->face_name, console->active->font.face_name,
894
console->active->font.face_len * sizeof(WCHAR) );
895
config->face_name[console->active->font.face_len] = 0;
896
897
/* Save default console configuration to the registry */
898
save_config( NULL, config );
899
}
900
901
/* Sets the font specified in the LOGFONT as the new console font */
902
void update_console_font( struct console *console, const WCHAR *face_name, size_t face_name_size,
903
unsigned int height, unsigned int weight )
904
{
905
LOGFONTW lf;
906
907
if (!console->window) return;
908
909
fill_logfont( &lf, face_name, face_name_size, height, weight );
910
911
set_console_font( console, &lf );
912
}
913
914
/* get a cell from a relative coordinate in window (takes into account the scrolling) */
915
static COORD get_cell( struct console *console, LPARAM lparam )
916
{
917
COORD c;
918
c.X = console->active->win.left + (short)LOWORD(lparam) / console->active->font.width;
919
c.Y = console->active->win.top + (short)HIWORD(lparam) / console->active->font.height;
920
return c;
921
}
922
923
/* get the console bit mask equivalent to the VK_ status in key state */
924
static DWORD get_ctrl_state( BYTE *key_state)
925
{
926
unsigned int ret = 0;
927
928
GetKeyboardState(key_state);
929
if (key_state[VK_SHIFT] & 0x80) ret |= SHIFT_PRESSED;
930
if (key_state[VK_LCONTROL] & 0x80) ret |= LEFT_CTRL_PRESSED;
931
if (key_state[VK_RCONTROL] & 0x80) ret |= RIGHT_CTRL_PRESSED;
932
if (key_state[VK_LMENU] & 0x80) ret |= LEFT_ALT_PRESSED;
933
if (key_state[VK_RMENU] & 0x80) ret |= RIGHT_ALT_PRESSED;
934
if (key_state[VK_CAPITAL] & 0x01) ret |= CAPSLOCK_ON;
935
if (key_state[VK_NUMLOCK] & 0x01) ret |= NUMLOCK_ON;
936
if (key_state[VK_SCROLL] & 0x01) ret |= SCROLLLOCK_ON;
937
938
return ret;
939
}
940
941
/* get the selection rectangle */
942
static void get_selection_rect( struct console *console, RECT *r )
943
{
944
r->left = (min(console->window->selection_start.X, console->window->selection_end.X) -
945
console->active->win.left) * console->active->font.width;
946
r->top = (min(console->window->selection_start.Y, console->window->selection_end.Y) -
947
console->active->win.top) * console->active->font.height;
948
r->right = (max(console->window->selection_start.X, console->window->selection_end.X) + 1 -
949
console->active->win.left) * console->active->font.width;
950
r->bottom = (max(console->window->selection_start.Y, console->window->selection_end.Y) + 1 -
951
console->active->win.top) * console->active->font.height;
952
}
953
954
static void update_selection( struct console *console, HDC ref_dc )
955
{
956
HDC dc;
957
RECT r;
958
959
get_selection_rect( console, &r );
960
dc = ref_dc ? ref_dc : GetDC( console->win );
961
if (!dc) return;
962
963
if (console->win == GetFocus() && console->active->cursor_visible)
964
HideCaret( console->win );
965
InvertRect( dc, &r );
966
if (dc != ref_dc)
967
ReleaseDC( console->win, dc );
968
if (console->win == GetFocus() && console->active->cursor_visible)
969
ShowCaret( console->win );
970
}
971
972
static void move_selection( struct console *console, COORD c1, COORD c2 )
973
{
974
RECT r;
975
HDC dc;
976
977
if (c1.X < 0 || c1.X >= console->active->width ||
978
c2.X < 0 || c2.X >= console->active->width ||
979
c1.Y < 0 || c1.Y >= console->active->height ||
980
c2.Y < 0 || c2.Y >= console->active->height)
981
return;
982
983
get_selection_rect( console, &r );
984
dc = GetDC( console->win );
985
if (dc)
986
{
987
if (console->win == GetFocus() && console->active->cursor_visible)
988
HideCaret( console->win );
989
InvertRect( dc, &r );
990
}
991
console->window->selection_start = c1;
992
console->window->selection_end = c2;
993
if (dc)
994
{
995
get_selection_rect( console, &r );
996
InvertRect( dc, &r );
997
ReleaseDC( console->win, dc );
998
if (console->win == GetFocus() && console->active->cursor_visible)
999
ShowCaret( console->win );
1000
}
1001
}
1002
1003
/* copies the current selection into the clipboard */
1004
static void copy_selection( struct console *console )
1005
{
1006
unsigned int w, h;
1007
WCHAR *p, *buf;
1008
HANDLE mem;
1009
1010
w = abs( console->window->selection_start.X - console->window->selection_end.X ) + 1;
1011
h = abs( console->window->selection_start.Y - console->window->selection_end.Y ) + 1;
1012
1013
if (!OpenClipboard( console->win )) return;
1014
EmptyClipboard();
1015
1016
mem = GlobalAlloc( GMEM_MOVEABLE, (w + 1) * h * sizeof(WCHAR) );
1017
if (mem && (p = buf = GlobalLock( mem )))
1018
{
1019
int x, y;
1020
COORD c;
1021
1022
c.X = min( console->window->selection_start.X, console->window->selection_end.X );
1023
c.Y = min( console->window->selection_start.Y, console->window->selection_end.Y );
1024
1025
for (y = c.Y; y < c.Y + h; y++)
1026
{
1027
WCHAR *end;
1028
1029
for (x = c.X; x < c.X + w; x++)
1030
p[x - c.X] = console->active->data[y * console->active->width + x].ch;
1031
1032
/* strip spaces from the end of the line */
1033
end = p + w;
1034
while (end > p && *(end - 1) == ' ')
1035
end--;
1036
*end = (y < c.Y + h - 1) ? '\n' : '\0';
1037
p = end + 1;
1038
}
1039
1040
TRACE( "%s\n", debugstr_w( buf ));
1041
if (p - buf != (w + 1) * h)
1042
{
1043
HANDLE new_mem;
1044
new_mem = GlobalReAlloc( mem, (p - buf) * sizeof(WCHAR), GMEM_MOVEABLE );
1045
if (new_mem) mem = new_mem;
1046
}
1047
GlobalUnlock( mem );
1048
SetClipboardData( CF_UNICODETEXT, mem );
1049
}
1050
CloseClipboard();
1051
}
1052
1053
static void paste_clipboard( struct console *console )
1054
{
1055
WCHAR *ptr;
1056
HANDLE h;
1057
1058
if (!OpenClipboard( console->win )) return;
1059
h = GetClipboardData( CF_UNICODETEXT );
1060
if (h && (ptr = GlobalLock( h )))
1061
{
1062
unsigned int i, len = GlobalSize(h) / sizeof(WCHAR);
1063
INPUT_RECORD ir[2];
1064
SHORT sh;
1065
1066
ir[0].EventType = KEY_EVENT;
1067
ir[0].Event.KeyEvent.wRepeatCount = 0;
1068
ir[0].Event.KeyEvent.dwControlKeyState = 0;
1069
ir[0].Event.KeyEvent.bKeyDown = TRUE;
1070
1071
/* generate the corresponding input records */
1072
for (i = 0; i < len; i++)
1073
{
1074
/* FIXME: the modifying keys are not generated (shift, ctrl...) */
1075
sh = VkKeyScanW( ptr[i] );
1076
ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1077
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1078
ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
1079
1080
ir[1] = ir[0];
1081
ir[1].Event.KeyEvent.bKeyDown = FALSE;
1082
1083
write_console_input( console, ir, 2, i == len - 1 );
1084
}
1085
GlobalUnlock( h );
1086
}
1087
1088
CloseClipboard();
1089
}
1090
1091
/* handle keys while selecting an area */
1092
static void handle_selection_key( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1093
{
1094
BYTE key_state[256];
1095
COORD c1, c2;
1096
DWORD state;
1097
1098
if (!down) return;
1099
state = get_ctrl_state( key_state ) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
1100
1101
switch (state)
1102
{
1103
case 0:
1104
switch (wparam)
1105
{
1106
case VK_RETURN:
1107
console->window->in_selection = FALSE;
1108
update_selection( console, 0 );
1109
copy_selection( console );
1110
return;
1111
case VK_RIGHT:
1112
c1 = console->window->selection_start;
1113
c2 = console->window->selection_end;
1114
c1.X++; c2.X++;
1115
move_selection( console, c1, c2 );
1116
return;
1117
case VK_LEFT:
1118
c1 = console->window->selection_start;
1119
c2 = console->window->selection_end;
1120
c1.X--; c2.X--;
1121
move_selection( console, c1, c2 );
1122
return;
1123
case VK_UP:
1124
c1 = console->window->selection_start;
1125
c2 = console->window->selection_end;
1126
c1.Y--; c2.Y--;
1127
move_selection( console, c1, c2 );
1128
return;
1129
case VK_DOWN:
1130
c1 = console->window->selection_start;
1131
c2 = console->window->selection_end;
1132
c1.Y++; c2.Y++;
1133
move_selection( console, c1, c2 );
1134
return;
1135
}
1136
break;
1137
case SHIFT_PRESSED:
1138
switch (wparam)
1139
{
1140
case VK_RIGHT:
1141
c1 = console->window->selection_start;
1142
c2 = console->window->selection_end;
1143
c2.X++;
1144
move_selection( console, c1, c2 );
1145
return;
1146
case VK_LEFT:
1147
c1 = console->window->selection_start;
1148
c2 = console->window->selection_end;
1149
c2.X--;
1150
move_selection( console, c1, c2 );
1151
return;
1152
case VK_UP:
1153
c1 = console->window->selection_start;
1154
c2 = console->window->selection_end;
1155
c2.Y--;
1156
move_selection( console, c1, c2 );
1157
return;
1158
case VK_DOWN:
1159
c1 = console->window->selection_start;
1160
c2 = console->window->selection_end;
1161
c2.Y++;
1162
move_selection( console, c1, c2 );
1163
return;
1164
}
1165
break;
1166
}
1167
1168
if (wparam < VK_SPACE) /* Shift, Alt, Ctrl, Num Lock etc. */
1169
return;
1170
1171
update_selection( console, 0 );
1172
console->window->in_selection = FALSE;
1173
}
1174
1175
/* generate input_record from windows WM_KEYUP/WM_KEYDOWN messages */
1176
static void record_key_input( struct console *console, BOOL down, WPARAM wparam, LPARAM lparam )
1177
{
1178
static WCHAR last; /* keep last char seen as feed for key up message */
1179
BYTE key_state[256];
1180
INPUT_RECORD ir;
1181
WCHAR buf[2];
1182
1183
ir.EventType = KEY_EVENT;
1184
ir.Event.KeyEvent.bKeyDown = down;
1185
ir.Event.KeyEvent.wRepeatCount = LOWORD(lparam);
1186
ir.Event.KeyEvent.wVirtualKeyCode = wparam;
1187
ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lparam) & 0xFF;
1188
ir.Event.KeyEvent.uChar.UnicodeChar = 0;
1189
ir.Event.KeyEvent.dwControlKeyState = get_ctrl_state( key_state );
1190
if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1191
1192
if (down)
1193
{
1194
switch (ToUnicode(wparam, HIWORD(lparam), key_state, buf, 2, 0))
1195
{
1196
case 2:
1197
/* FIXME: should generate two events */
1198
/* fall through */
1199
case 1:
1200
last = buf[0];
1201
break;
1202
default:
1203
last = 0;
1204
break;
1205
}
1206
}
1207
ir.Event.KeyEvent.uChar.UnicodeChar = last;
1208
if (!down) last = 0; /* FIXME: buggy HACK */
1209
1210
write_console_input( console, &ir, 1, TRUE );
1211
}
1212
1213
/* generate input_record from WM_CHAR message. */
1214
static void record_char_input( struct console *console, WCHAR ch, LPARAM lparam )
1215
{
1216
INPUT_RECORD ir;
1217
SHORT sh = VkKeyScanW( ch );
1218
1219
if (sh == ~0) return;
1220
ir.EventType = KEY_EVENT;
1221
ir.Event.KeyEvent.bKeyDown = TRUE;
1222
ir.Event.KeyEvent.wRepeatCount = 0;
1223
ir.Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
1224
ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW( LOBYTE(sh), 0 );
1225
ir.Event.KeyEvent.uChar.UnicodeChar = ch;
1226
ir.Event.KeyEvent.dwControlKeyState = 0;
1227
if (lparam & (1u << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
1228
1229
write_console_input( console, &ir, 1, TRUE );
1230
}
1231
1232
static void record_mouse_input( struct console *console, COORD c, WPARAM wparam, DWORD event )
1233
{
1234
BYTE key_state[256];
1235
INPUT_RECORD ir;
1236
1237
/* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
1238
if (!(console->mode & ENABLE_MOUSE_INPUT)) return;
1239
1240
ir.EventType = MOUSE_EVENT;
1241
ir.Event.MouseEvent.dwMousePosition = c;
1242
ir.Event.MouseEvent.dwButtonState = 0;
1243
if (wparam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
1244
if (wparam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
1245
if (wparam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
1246
if (wparam & MK_CONTROL) ir.Event.MouseEvent.dwButtonState |= LEFT_CTRL_PRESSED;
1247
if (wparam & MK_SHIFT) ir.Event.MouseEvent.dwButtonState |= SHIFT_PRESSED;
1248
if (event == MOUSE_WHEELED) ir.Event.MouseEvent.dwButtonState |= wparam & 0xFFFF0000;
1249
ir.Event.MouseEvent.dwControlKeyState = get_ctrl_state( key_state );
1250
ir.Event.MouseEvent.dwEventFlags = event;
1251
1252
write_console_input( console, &ir, 1, TRUE );
1253
}
1254
1255
struct dialog_info
1256
{
1257
struct console *console;
1258
struct console_config config;
1259
HWND dialog; /* handle to active propsheet */
1260
};
1261
1262
/* dialog proc for the option property sheet */
1263
static INT_PTR WINAPI option_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1264
{
1265
struct dialog_info *di;
1266
unsigned int idc;
1267
1268
switch (msg)
1269
{
1270
case WM_INITDIALOG:
1271
di = (struct dialog_info *)((PROPSHEETPAGEA *)lparam)->lParam;
1272
di->dialog = dialog;
1273
SetWindowLongPtrW( dialog, DWLP_USER, (LONG_PTR)di );
1274
1275
SendMessageW( GetDlgItem( dialog, IDC_OPT_HIST_SIZE_UD ), UDM_SETRANGE, 0, MAKELPARAM(500, 0) );
1276
1277
if (di->config.cursor_size <= 25) idc = IDC_OPT_CURSOR_SMALL;
1278
else if (di->config.cursor_size <= 50) idc = IDC_OPT_CURSOR_MEDIUM;
1279
else idc = IDC_OPT_CURSOR_LARGE;
1280
1281
SendDlgItemMessageW( dialog, idc, BM_SETCHECK, BST_CHECKED, 0 );
1282
SetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, di->config.history_size, FALSE );
1283
SendDlgItemMessageW( dialog, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
1284
(di->config.history_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1285
SendDlgItemMessageW( dialog, IDC_OPT_INSERT_MODE, BM_SETCHECK,
1286
(di->config.insert_mode) ? BST_CHECKED : BST_UNCHECKED, 0 );
1287
SendDlgItemMessageW( dialog, IDC_OPT_CONF_CTRL, BM_SETCHECK,
1288
(di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0 );
1289
SendDlgItemMessageW( dialog, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
1290
(di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0 );
1291
SendDlgItemMessageW( dialog, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
1292
(di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0 );
1293
return FALSE; /* because we set the focus */
1294
1295
case WM_COMMAND:
1296
break;
1297
1298
case WM_NOTIFY:
1299
{
1300
NMHDR *nmhdr = (NMHDR*)lparam;
1301
DWORD val;
1302
BOOL done;
1303
1304
di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1305
1306
switch (nmhdr->code)
1307
{
1308
case PSN_SETACTIVE:
1309
/* needed in propsheet to keep properly the selected radio button
1310
* otherwise, the focus would be set to the first tab stop in the
1311
* propsheet, which would always activate the first radio button
1312
*/
1313
if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED)
1314
idc = IDC_OPT_CURSOR_SMALL;
1315
else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED)
1316
idc = IDC_OPT_CURSOR_MEDIUM;
1317
else
1318
idc = IDC_OPT_CURSOR_LARGE;
1319
PostMessageW( dialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem( dialog, idc ), TRUE );
1320
di->dialog = dialog;
1321
break;
1322
case PSN_APPLY:
1323
if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_SMALL ) == BST_CHECKED) val = 25;
1324
else if (IsDlgButtonChecked( dialog, IDC_OPT_CURSOR_MEDIUM ) == BST_CHECKED) val = 50;
1325
else val = 100;
1326
di->config.cursor_size = val;
1327
1328
val = GetDlgItemInt( dialog, IDC_OPT_HIST_SIZE, &done, FALSE );
1329
if (done) di->config.history_size = val;
1330
1331
val = (IsDlgButtonChecked( dialog, IDC_OPT_HIST_NODOUBLE ) & BST_CHECKED) != 0;
1332
di->config.history_mode = val;
1333
1334
val = (IsDlgButtonChecked( dialog, IDC_OPT_INSERT_MODE ) & BST_CHECKED) != 0;
1335
di->config.insert_mode = val;
1336
1337
val = 0;
1338
if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_CTRL ) & BST_CHECKED) val |= MK_CONTROL;
1339
if (IsDlgButtonChecked( dialog, IDC_OPT_CONF_SHIFT ) & BST_CHECKED) val |= MK_SHIFT;
1340
di->config.menu_mask = val;
1341
1342
val = (IsDlgButtonChecked( dialog, IDC_OPT_QUICK_EDIT ) & BST_CHECKED) != 0;
1343
di->config.quick_edit = val;
1344
1345
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1346
return TRUE;
1347
default:
1348
return FALSE;
1349
}
1350
break;
1351
}
1352
default:
1353
return FALSE;
1354
}
1355
return TRUE;
1356
}
1357
1358
static COLORREF get_color( struct dialog_info *di, unsigned int idc )
1359
{
1360
LONG_PTR index;
1361
1362
index = GetWindowLongW(GetDlgItem( di->dialog, idc ), 0);
1363
return di->config.color_map[index];
1364
}
1365
1366
/* window proc for font previewer in font property sheet */
1367
static LRESULT WINAPI font_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1368
{
1369
switch (msg)
1370
{
1371
case WM_CREATE:
1372
SetWindowLongPtrW( hwnd, 0, 0 );
1373
break;
1374
1375
case WM_GETFONT:
1376
return GetWindowLongPtrW( hwnd, 0 );
1377
1378
case WM_SETFONT:
1379
SetWindowLongPtrW( hwnd, 0, wparam );
1380
if (LOWORD(lparam))
1381
{
1382
InvalidateRect( hwnd, NULL, TRUE );
1383
UpdateWindow( hwnd );
1384
}
1385
break;
1386
1387
case WM_DESTROY:
1388
{
1389
HFONT font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1390
if (font) DeleteObject( font );
1391
break;
1392
}
1393
1394
case WM_PAINT:
1395
{
1396
struct dialog_info *di;
1397
HFONT font, old_font;
1398
PAINTSTRUCT ps;
1399
1400
di = (struct dialog_info *)GetWindowLongPtrW( GetParent( hwnd ), DWLP_USER );
1401
BeginPaint( hwnd, &ps );
1402
1403
font = (HFONT)GetWindowLongPtrW( hwnd, 0 );
1404
if (font)
1405
{
1406
static const WCHAR ascii[] = L"ASCII: abcXYZ";
1407
COLORREF bkcolor;
1408
WCHAR buf[256];
1409
int len;
1410
1411
old_font = SelectObject( ps.hdc, font );
1412
bkcolor = get_color( di, IDC_FNT_COLOR_BK );
1413
FillRect( ps.hdc, &ps.rcPaint, CreateSolidBrush( bkcolor ));
1414
SetBkColor( ps.hdc, bkcolor );
1415
SetTextColor( ps.hdc, get_color( di, IDC_FNT_COLOR_FG ));
1416
len = LoadStringW( GetModuleHandleW(NULL), IDS_FNT_PREVIEW, buf, ARRAY_SIZE(buf) );
1417
if (len) TextOutW( ps.hdc, 0, 0, buf, len );
1418
TextOutW( ps.hdc, 0, di->config.cell_height, ascii, ARRAY_SIZE(ascii) - 1 );
1419
SelectObject( ps.hdc, old_font );
1420
}
1421
EndPaint( hwnd, &ps );
1422
break;
1423
}
1424
1425
default:
1426
return DefWindowProcW( hwnd, msg, wparam, lparam );
1427
}
1428
return 0;
1429
}
1430
1431
/* window proc for color previewer */
1432
static LRESULT WINAPI color_preview_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
1433
{
1434
switch (msg)
1435
{
1436
case WM_PAINT:
1437
{
1438
struct dialog_info *di;
1439
PAINTSTRUCT ps;
1440
RECT client, r;
1441
int i, step;
1442
HBRUSH brush;
1443
1444
BeginPaint( hwnd, &ps );
1445
GetClientRect( hwnd, &client );
1446
step = client.right / 8;
1447
1448
di = (struct dialog_info *)GetWindowLongPtrW( GetParent(hwnd), DWLP_USER );
1449
1450
for (i = 0; i < 16; i++)
1451
{
1452
r.top = (i / 8) * (client.bottom / 2);
1453
r.bottom = r.top + client.bottom / 2;
1454
r.left = (i & 7) * step;
1455
r.right = r.left + step;
1456
brush = CreateSolidBrush( di->config.color_map[i] );
1457
FillRect( ps.hdc, &r, brush );
1458
DeleteObject( brush );
1459
if (GetWindowLongW( hwnd, 0 ) == i)
1460
{
1461
HPEN old_pen;
1462
int i = 2;
1463
1464
old_pen = SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1465
r.right--; r.bottom--;
1466
for (;;)
1467
{
1468
MoveToEx( ps.hdc, r.left, r.bottom, NULL );
1469
LineTo( ps.hdc, r.left, r.top );
1470
LineTo( ps.hdc, r.right, r.top );
1471
SelectObject( ps.hdc, GetStockObject( BLACK_PEN ));
1472
LineTo( ps.hdc, r.right, r.bottom );
1473
LineTo( ps.hdc, r.left, r.bottom );
1474
if (--i == 0) break;
1475
r.left++; r.top++; r.right--; r.bottom--;
1476
SelectObject( ps.hdc, GetStockObject( WHITE_PEN ));
1477
}
1478
SelectObject( ps.hdc, old_pen );
1479
}
1480
}
1481
EndPaint( hwnd, &ps );
1482
break;
1483
}
1484
1485
case WM_LBUTTONDOWN:
1486
{
1487
int i, step;
1488
RECT client;
1489
1490
GetClientRect( hwnd, &client );
1491
step = client.right / 8;
1492
i = (HIWORD(lparam) >= client.bottom / 2) ? 8 : 0;
1493
i += LOWORD(lparam) / step;
1494
SetWindowLongW( hwnd, 0, i );
1495
InvalidateRect( GetDlgItem( GetParent( hwnd ), IDC_FNT_PREVIEW ), NULL, FALSE );
1496
InvalidateRect( hwnd, NULL, FALSE );
1497
break;
1498
}
1499
1500
default:
1501
return DefWindowProcW( hwnd, msg, wparam, lparam );
1502
}
1503
return 0;
1504
}
1505
1506
static BOOL select_font( struct dialog_info *di )
1507
{
1508
int font_idx, size_idx;
1509
WCHAR face_name[LF_FACESIZE], height_buf[4];
1510
size_t len;
1511
unsigned int font_height;
1512
LOGFONTW lf;
1513
HFONT font, old_font;
1514
DWORD_PTR args[2];
1515
WCHAR buf[256];
1516
WCHAR fmt[128];
1517
1518
font_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0, 0 );
1519
size_idx = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0, 0 );
1520
1521
if (font_idx < 0 || size_idx < 0)
1522
return FALSE;
1523
1524
len = SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_GETTEXT, font_idx, (LPARAM)&face_name );
1525
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_GETTEXT, size_idx, (LPARAM)&height_buf );
1526
font_height = _wtoi( height_buf );
1527
1528
fill_logfont( &lf, face_name, len * sizeof(WCHAR), font_height, FW_NORMAL );
1529
font = select_font_config( &di->config, di->console->output_cp, di->console->win, &lf );
1530
if (!font) return FALSE;
1531
1532
if (di->config.cell_height != font_height)
1533
TRACE( "mismatched heights (%u<>%u)\n", di->config.cell_height, font_height );
1534
1535
old_font = (HFONT)SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_GETFONT, 0, 0 );
1536
SendDlgItemMessageW( di->dialog, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)font, TRUE );
1537
if (old_font) DeleteObject( old_font );
1538
1539
LoadStringW( GetModuleHandleW(NULL), IDS_FNT_DISPLAY, fmt, ARRAY_SIZE(fmt) );
1540
args[0] = di->config.cell_width;
1541
args[1] = di->config.cell_height;
1542
FormatMessageW( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
1543
fmt, 0, 0, buf, ARRAY_SIZE(buf), (va_list *)args );
1544
1545
SendDlgItemMessageW( di->dialog, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf );
1546
return TRUE;
1547
}
1548
1549
static BOOL fill_list_size( struct dialog_info *di, BOOL init )
1550
{
1551
if (init)
1552
{
1553
static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
1554
unsigned int i, idx = 4;
1555
WCHAR buf[4];
1556
1557
for (i = 0; i < ARRAY_SIZE(sizes); i++)
1558
{
1559
wsprintfW( buf, L"%u", sizes[i] );
1560
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, -1, (LPARAM)buf );
1561
1562
if (di->config.cell_height == sizes[i]) idx = i;
1563
}
1564
1565
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0 );
1566
}
1567
1568
select_font( di );
1569
1570
return TRUE;
1571
}
1572
1573
static int CALLBACK enum_list_font_proc( const LOGFONTW *lf, const TEXTMETRICW *tm,
1574
DWORD font_type, LPARAM lparam )
1575
{
1576
struct dialog_info *di = (struct dialog_info *)lparam;
1577
1578
TRACE( "%s\n", debugstr_logfont( lf, font_type ));
1579
1580
if (validate_font( di->console, lf, NULL, 0, NULL ))
1581
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_ADDSTRING, 0, (LPARAM)lf->lfFaceName );
1582
1583
return 1;
1584
}
1585
1586
static BOOL fill_list_font( struct dialog_info *di )
1587
{
1588
LOGFONTW lf;
1589
1590
memset( &lf, 0, sizeof(lf) );
1591
lf.lfCharSet = DEFAULT_CHARSET;
1592
lf.lfFaceName[0] = 0;
1593
lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
1594
1595
EnumFontFamiliesExW( di->console->window->mem_dc, &lf, enum_list_font_proc, (LPARAM)di, 0 );
1596
1597
if (SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
1598
-1, (LPARAM)di->config.face_name ) == LB_ERR)
1599
SendDlgItemMessageW( di->dialog, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0, 0 );
1600
1601
fill_list_size( di, TRUE );
1602
1603
return TRUE;
1604
}
1605
1606
/* dialog proc for the font property sheet */
1607
static INT_PTR WINAPI font_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1608
{
1609
struct dialog_info *di;
1610
1611
switch (msg)
1612
{
1613
case WM_INITDIALOG:
1614
di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1615
di->dialog = dialog;
1616
SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1617
/* use default system font until user-selected font is applied */
1618
SendDlgItemMessageW( dialog, IDC_FNT_PREVIEW, WM_SETFONT, 0, 0 );
1619
fill_list_font( di );
1620
SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0, (di->config.attr >> 4) & 0x0F );
1621
SetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0, di->config.attr & 0x0F );
1622
break;
1623
1624
case WM_COMMAND:
1625
di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1626
switch (LOWORD(wparam))
1627
{
1628
case IDC_FNT_LIST_FONT:
1629
if (HIWORD(wparam) == LBN_SELCHANGE)
1630
fill_list_size( di, FALSE );
1631
break;
1632
case IDC_FNT_LIST_SIZE:
1633
if (HIWORD(wparam) == LBN_SELCHANGE)
1634
select_font( di );
1635
break;
1636
}
1637
break;
1638
1639
case WM_NOTIFY:
1640
{
1641
NMHDR *nmhdr = (NMHDR*)lparam;
1642
DWORD val;
1643
1644
di = (struct dialog_info*)GetWindowLongPtrW( dialog, DWLP_USER );
1645
switch (nmhdr->code)
1646
{
1647
case PSN_SETACTIVE:
1648
di->dialog = dialog;
1649
break;
1650
case PSN_APPLY:
1651
val = (GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_BK ), 0 ) << 4) |
1652
GetWindowLongW( GetDlgItem( dialog, IDC_FNT_COLOR_FG ), 0 );
1653
di->config.attr = val;
1654
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1655
return TRUE;
1656
default:
1657
return FALSE;
1658
}
1659
break;
1660
}
1661
default:
1662
return FALSE;
1663
}
1664
return TRUE;
1665
}
1666
1667
/* dialog proc for the config property sheet */
1668
static INT_PTR WINAPI config_dialog_proc( HWND dialog, UINT msg, WPARAM wparam, LPARAM lparam )
1669
{
1670
struct dialog_info *di;
1671
int max_ud = 2000;
1672
1673
switch (msg)
1674
{
1675
case WM_INITDIALOG:
1676
di = (struct dialog_info *)((PROPSHEETPAGEA*)lparam)->lParam;
1677
di->dialog = dialog;
1678
1679
SetWindowLongPtrW( dialog, DWLP_USER, (DWORD_PTR)di );
1680
SetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, di->config.sb_width, FALSE );
1681
SetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, di->config.sb_height, FALSE );
1682
SetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, di->config.win_width, FALSE );
1683
SetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE );
1684
1685
SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1686
SendMessageW( GetDlgItem(dialog, IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1687
SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1688
SendMessageW( GetDlgItem(dialog, IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM(max_ud, 0));
1689
1690
SendDlgItemMessageW( dialog, IDC_CNF_CLOSE_EXIT, BM_SETCHECK, di->config.close_on_exit ? BST_CHECKED : BST_UNCHECKED, 0 );
1691
1692
SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Win32" );
1693
SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_ADDSTRING, 0, (LPARAM)L"Emacs" );
1694
SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE, CB_SETCURSEL, di->config.edition_mode, 0 );
1695
break;
1696
1697
case WM_NOTIFY:
1698
{
1699
NMHDR *nmhdr = (NMHDR*)lparam;
1700
int win_w, win_h, sb_w, sb_h;
1701
BOOL st1, st2;
1702
DWORD val;
1703
1704
di = (struct dialog_info *)GetWindowLongPtrW( dialog, DWLP_USER );
1705
switch (nmhdr->code)
1706
{
1707
case PSN_SETACTIVE:
1708
di->dialog = dialog;
1709
break;
1710
case PSN_APPLY:
1711
sb_w = GetDlgItemInt( dialog, IDC_CNF_SB_WIDTH, &st1, FALSE );
1712
sb_h = GetDlgItemInt( dialog, IDC_CNF_SB_HEIGHT, &st2, FALSE );
1713
if (!st1 || ! st2)
1714
{
1715
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1716
return TRUE;
1717
}
1718
win_w = GetDlgItemInt( dialog, IDC_CNF_WIN_WIDTH, &st1, FALSE );
1719
win_h = GetDlgItemInt( dialog, IDC_CNF_WIN_HEIGHT, &st2, FALSE );
1720
if (!st1 || !st2)
1721
{
1722
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1723
return TRUE;
1724
}
1725
if (win_w > sb_w || win_h > sb_h)
1726
{
1727
WCHAR cap[256];
1728
WCHAR txt[256];
1729
1730
LoadStringW( GetModuleHandleW(NULL), IDS_DLG_TIT_ERROR, cap, ARRAY_SIZE(cap) );
1731
LoadStringW( GetModuleHandleW(NULL), IDS_DLG_ERR_SBWINSIZE, txt, ARRAY_SIZE(txt) );
1732
1733
MessageBoxW( dialog, txt, cap, MB_OK );
1734
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_INVALID );
1735
return TRUE;
1736
}
1737
di->config.win_width = win_w;
1738
di->config.win_height = win_h;
1739
di->config.sb_width = sb_w;
1740
di->config.sb_height = sb_h;
1741
1742
val = (IsDlgButtonChecked( dialog, IDC_CNF_CLOSE_EXIT ) & BST_CHECKED) != 0;
1743
di->config.close_on_exit = val;
1744
1745
di->config.edition_mode = SendDlgItemMessageW( dialog, IDC_CNF_EDITION_MODE,
1746
CB_GETCURSEL, 0, 0 );
1747
SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR );
1748
return TRUE;
1749
default:
1750
return FALSE;
1751
}
1752
break;
1753
}
1754
default:
1755
return FALSE;
1756
}
1757
return TRUE;
1758
}
1759
1760
static void apply_config( struct console *console, const struct console_config *config )
1761
{
1762
if (console->active->width != config->sb_width || console->active->height != config->sb_height)
1763
change_screen_buffer_size( console->active, config->sb_width, config->sb_height );
1764
1765
console->window->menu_mask = config->menu_mask;
1766
console->window->quick_edit = config->quick_edit;
1767
console->window->close_on_exit = config->close_on_exit;
1768
1769
console->edition_mode = config->edition_mode;
1770
console->history_mode = config->history_mode;
1771
1772
if (console->history_size != config->history_size)
1773
{
1774
struct history_line **mem = NULL;
1775
int i, delta;
1776
1777
if (config->history_size && (mem = malloc( config->history_size * sizeof(*mem) )))
1778
{
1779
memset( mem, 0, config->history_size * sizeof(*mem) );
1780
1781
delta = (console->history_index > config->history_size)
1782
? (console->history_index - config->history_size) : 0;
1783
1784
for (i = delta; i < console->history_index; i++)
1785
{
1786
mem[i - delta] = console->history[i];
1787
console->history[i] = NULL;
1788
}
1789
console->history_index -= delta;
1790
1791
for (i = 0; i < console->history_size; i++)
1792
free( console->history[i] );
1793
free( console->history );
1794
console->history = mem;
1795
console->history_size = config->history_size;
1796
}
1797
}
1798
1799
if (config->insert_mode)
1800
console->mode |= ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS;
1801
else
1802
console->mode &= ~ENABLE_INSERT_MODE;
1803
1804
console->active->cursor_size = config->cursor_size;
1805
console->active->cursor_visible = config->cursor_visible;
1806
console->active->attr = config->attr;
1807
console->active->popup_attr = config->popup_attr;
1808
console->active->win.left = config->win_pos.X;
1809
console->active->win.top = config->win_pos.Y;
1810
console->active->win.right = config->win_pos.X + config->win_width - 1;
1811
console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
1812
memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
1813
1814
if (console->active->font.width != config->cell_width ||
1815
console->active->font.height != config->cell_height ||
1816
console->active->font.weight != config->font_weight ||
1817
console->active->font.pitch_family != config->font_pitch_family ||
1818
console->active->font.face_len != wcslen( config->face_name ) ||
1819
memcmp( console->active->font.face_name, config->face_name,
1820
console->active->font.face_len * sizeof(WCHAR) ))
1821
{
1822
update_console_font( console, config->face_name, wcslen(config->face_name) * sizeof(WCHAR),
1823
config->cell_height, config->font_weight );
1824
}
1825
1826
update_window( console );
1827
1828
notify_screen_buffer_size( console->active );
1829
}
1830
1831
static void current_config( struct console *console, struct console_config *config )
1832
{
1833
size_t len;
1834
1835
config->menu_mask = console->window->menu_mask;
1836
config->quick_edit = console->window->quick_edit;
1837
config->close_on_exit = console->window->close_on_exit;
1838
1839
config->edition_mode = console->edition_mode;
1840
config->history_mode = console->history_mode;
1841
config->history_size = console->history_size;
1842
1843
config->insert_mode = (console->mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) ==
1844
(ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS);
1845
1846
config->cursor_size = console->active->cursor_size;
1847
config->cursor_visible = console->active->cursor_visible;
1848
config->attr = console->active->attr;
1849
config->popup_attr = console->active->popup_attr;
1850
memcpy( config->color_map, console->active->color_map, sizeof(config->color_map) );
1851
1852
config->cell_width = console->active->font.width;
1853
config->cell_height = console->active->font.height;
1854
config->font_weight = console->active->font.weight;
1855
config->font_pitch_family = console->active->font.pitch_family;
1856
len = min( ARRAY_SIZE(config->face_name) - 1, console->active->font.face_len );
1857
if (len) memcpy( config->face_name, console->active->font.face_name, len * sizeof(WCHAR) );
1858
config->face_name[len] = 0;
1859
1860
config->sb_width = console->active->width;
1861
config->sb_height = console->active->height;
1862
1863
config->win_width = console->active->win.right - console->active->win.left + 1;
1864
config->win_height = console->active->win.bottom - console->active->win.top + 1;
1865
config->win_pos.X = console->active->win.left;
1866
config->win_pos.Y = console->active->win.top;
1867
}
1868
1869
/* run the dialog box to set up the console options */
1870
static BOOL config_dialog( struct console *console, BOOL current )
1871
{
1872
struct console_config prev_config;
1873
struct dialog_info di;
1874
PROPSHEETHEADERW header;
1875
HPROPSHEETPAGE pages[3];
1876
PROPSHEETPAGEW psp;
1877
WNDCLASSW wndclass;
1878
WCHAR buff[256];
1879
1880
InitCommonControls();
1881
1882
memset( &di, 0, sizeof(di) );
1883
di.console = console;
1884
1885
if (current)
1886
current_config( console, &di.config );
1887
else
1888
load_config( NULL, &di.config );
1889
1890
prev_config = di.config;
1891
1892
wndclass.style = 0;
1893
wndclass.lpfnWndProc = font_preview_proc;
1894
wndclass.cbClsExtra = 0;
1895
wndclass.cbWndExtra = sizeof(HFONT);
1896
wndclass.hInstance = GetModuleHandleW( NULL );
1897
wndclass.hIcon = 0;
1898
wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1899
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1900
wndclass.lpszMenuName = NULL;
1901
wndclass.lpszClassName = L"WineConFontPreview";
1902
RegisterClassW( &wndclass );
1903
1904
wndclass.style = 0;
1905
wndclass.lpfnWndProc = color_preview_proc;
1906
wndclass.cbClsExtra = 0;
1907
wndclass.cbWndExtra = sizeof(DWORD);
1908
wndclass.hInstance = GetModuleHandleW( NULL );
1909
wndclass.hIcon = 0;
1910
wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
1911
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
1912
wndclass.lpszMenuName = NULL;
1913
wndclass.lpszClassName = L"WineConColorPreview";
1914
RegisterClassW( &wndclass );
1915
1916
memset( &psp, 0, sizeof(psp) );
1917
psp.dwSize = sizeof(psp);
1918
psp.dwFlags = 0;
1919
psp.hInstance = wndclass.hInstance;
1920
psp.lParam = (LPARAM)&di;
1921
1922
psp.pszTemplate = MAKEINTRESOURCEW(IDD_OPTION);
1923
psp.pfnDlgProc = option_dialog_proc;
1924
pages[0] = CreatePropertySheetPageW( &psp );
1925
1926
psp.pszTemplate = MAKEINTRESOURCEW(IDD_FONT);
1927
psp.pfnDlgProc = font_dialog_proc;
1928
pages[1] = CreatePropertySheetPageW( &psp );
1929
1930
psp.pszTemplate = MAKEINTRESOURCEW(IDD_CONFIG);
1931
psp.pfnDlgProc = config_dialog_proc;
1932
pages[2] = CreatePropertySheetPageW( &psp );
1933
1934
memset( &header, 0, sizeof(header) );
1935
header.dwSize = sizeof(header);
1936
1937
if (!LoadStringW( GetModuleHandleW( NULL ),
1938
current ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
1939
buff, ARRAY_SIZE(buff) ))
1940
wcscpy( buff, L"Setup" );
1941
1942
header.pszCaption = buff;
1943
header.nPages = 3;
1944
header.hwndParent = console->win;
1945
header.phpage = pages;
1946
header.dwFlags = PSH_NOAPPLYNOW;
1947
if (PropertySheetW( &header ) < 1)
1948
return TRUE;
1949
1950
if (!memcmp( &prev_config, &di.config, sizeof(prev_config) ))
1951
return TRUE;
1952
1953
TRACE( "%s\n", debugstr_config(&di.config) );
1954
1955
if (current)
1956
{
1957
apply_config( console, &di.config );
1958
update_window( di.console );
1959
}
1960
1961
save_config( current ? console->window->config_key : NULL, &di.config );
1962
1963
return TRUE;
1964
}
1965
1966
static void resize_window( struct console *console, int width, int height )
1967
{
1968
struct console_config config;
1969
1970
current_config( console, &config );
1971
config.win_width = width;
1972
config.win_height = height;
1973
1974
/* auto size screen-buffer if it's now smaller than window */
1975
if (config.sb_width < config.win_width)
1976
config.sb_width = config.win_width;
1977
if (config.sb_height < config.win_height)
1978
config.sb_height = config.win_height;
1979
1980
/* and reset window pos so that we don't display outside of the screen-buffer */
1981
if (config.win_pos.X + config.win_width > config.sb_width)
1982
config.win_pos.X = config.sb_width - config.win_width;
1983
if (config.win_pos.Y + config.win_height > config.sb_height)
1984
config.win_pos.Y = config.sb_height - config.win_height;
1985
1986
apply_config( console, &config );
1987
}
1988
1989
/* grays / ungrays the menu items according to their state */
1990
static void set_menu_details( struct console *console, HMENU menu )
1991
{
1992
EnableMenuItem( menu, IDS_COPY, MF_BYCOMMAND |
1993
(console->window->in_selection ? MF_ENABLED : MF_GRAYED) );
1994
EnableMenuItem( menu, IDS_PASTE, MF_BYCOMMAND |
1995
(IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED) );
1996
EnableMenuItem( menu, IDS_SCROLL, MF_BYCOMMAND | MF_GRAYED );
1997
EnableMenuItem( menu, IDS_SEARCH, MF_BYCOMMAND | MF_GRAYED );
1998
}
1999
2000
static BOOL fill_menu( HMENU menu, BOOL sep )
2001
{
2002
HINSTANCE module = GetModuleHandleW( NULL );
2003
HMENU sub_menu;
2004
WCHAR buff[256];
2005
2006
if (!menu) return FALSE;
2007
2008
sub_menu = CreateMenu();
2009
if (!sub_menu) return FALSE;
2010
2011
LoadStringW( module, IDS_MARK, buff, ARRAY_SIZE(buff) );
2012
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff );
2013
LoadStringW( module, IDS_COPY, buff, ARRAY_SIZE(buff) );
2014
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff );
2015
LoadStringW( module, IDS_PASTE, buff, ARRAY_SIZE(buff) );
2016
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff );
2017
LoadStringW( module, IDS_SELECTALL, buff, ARRAY_SIZE(buff) );
2018
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff );
2019
LoadStringW( module, IDS_SCROLL, buff, ARRAY_SIZE(buff) );
2020
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff );
2021
LoadStringW( module, IDS_SEARCH, buff, ARRAY_SIZE(buff) );
2022
InsertMenuW( sub_menu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff );
2023
2024
if (sep) InsertMenuW( menu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL );
2025
LoadStringW( module, IDS_EDIT, buff, ARRAY_SIZE(buff) );
2026
InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)sub_menu, buff );
2027
LoadStringW( module, IDS_DEFAULT, buff, ARRAY_SIZE(buff) );
2028
InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff );
2029
LoadStringW( module, IDS_PROPERTIES, buff, ARRAY_SIZE(buff) );
2030
InsertMenuW( menu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTIES, buff );
2031
2032
return TRUE;
2033
}
2034
2035
static LRESULT window_create( HWND hwnd, const CREATESTRUCTW *create )
2036
{
2037
struct console *console = create->lpCreateParams;
2038
HMENU sys_menu;
2039
2040
TRACE( "%p\n", hwnd );
2041
2042
SetWindowLongPtrW( hwnd, 0, (DWORD_PTR)console );
2043
console->win = hwnd;
2044
2045
if (console->window)
2046
{
2047
sys_menu = GetSystemMenu( hwnd, FALSE );
2048
if (!sys_menu) return 0;
2049
console->window->popup_menu = CreatePopupMenu();
2050
if (!console->window->popup_menu) return 0;
2051
2052
fill_menu( sys_menu, TRUE );
2053
fill_menu( console->window->popup_menu, FALSE );
2054
2055
console->window->mem_dc = CreateCompatibleDC( 0 );
2056
}
2057
return 0;
2058
}
2059
2060
static LRESULT WINAPI window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
2061
{
2062
struct console *console = (struct console *)GetWindowLongPtrW( hwnd, 0 );
2063
2064
switch (msg)
2065
{
2066
case WM_CREATE:
2067
return window_create( hwnd, (const CREATESTRUCTW *)lparam );
2068
2069
case WM_DESTROY:
2070
console->win = NULL;
2071
PostQuitMessage( 0 );
2072
break;
2073
2074
case WM_TIMER:
2075
case WM_UPDATE_CONFIG:
2076
if (console->window && console->window->update_state == UPDATE_PENDING)
2077
update_window( console );
2078
break;
2079
2080
case WM_PAINT:
2081
{
2082
PAINTSTRUCT ps;
2083
2084
if (!console->window) break;
2085
2086
BeginPaint( console->win, &ps );
2087
BitBlt( ps.hdc, 0, 0,
2088
(console->active->win.right - console->active->win.left + 1) * console->active->font.width,
2089
(console->active->win.bottom - console->active->win.top + 1) * console->active->font.height,
2090
console->window->mem_dc,
2091
console->active->win.left * console->active->font.width,
2092
console->active->win.top * console->active->font.height,
2093
SRCCOPY );
2094
if (console->window->in_selection) update_selection( console, ps.hdc );
2095
EndPaint( console->win, &ps );
2096
break;
2097
}
2098
2099
case WM_SHOWWINDOW:
2100
if (!console->window) break;
2101
if (wparam)
2102
update_window( console );
2103
else
2104
{
2105
if (console->window->bitmap) DeleteObject( console->window->bitmap );
2106
console->window->bitmap = NULL;
2107
}
2108
break;
2109
2110
case WM_KEYDOWN:
2111
case WM_KEYUP:
2112
if (console->window && console->window->in_selection)
2113
handle_selection_key( console, msg == WM_KEYDOWN, wparam, lparam );
2114
else
2115
record_key_input( console, msg == WM_KEYDOWN, wparam, lparam );
2116
break;
2117
2118
case WM_SYSKEYDOWN:
2119
case WM_SYSKEYUP:
2120
record_key_input( console, msg == WM_SYSKEYDOWN, wparam, lparam );
2121
break;
2122
2123
case WM_CHAR:
2124
if (console->window && console->window->in_selection)
2125
handle_selection_key( console, TRUE, LOBYTE( VkKeyScanW( (WCHAR)wparam ) ), lparam );
2126
else
2127
record_char_input( console, (WCHAR)wparam, lparam );
2128
break;
2129
2130
case WM_LBUTTONDOWN:
2131
if (console->window && (console->window->quick_edit || console->window->in_selection))
2132
{
2133
if (console->window->in_selection)
2134
update_selection( console, 0 );
2135
2136
if (console->window->quick_edit && console->window->in_selection)
2137
{
2138
console->window->in_selection = FALSE;
2139
}
2140
else
2141
{
2142
console->window->selection_end = get_cell( console, lparam );
2143
console->window->selection_start = console->window->selection_end;
2144
SetCapture( console->win );
2145
update_selection( console, 0 );
2146
console->window->in_selection = TRUE;
2147
}
2148
}
2149
else
2150
{
2151
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2152
}
2153
break;
2154
2155
case WM_MOUSEMOVE:
2156
if (console->window && (console->window->quick_edit || console->window->in_selection))
2157
{
2158
if (GetCapture() == console->win && console->window->in_selection &&
2159
(wparam & MK_LBUTTON))
2160
{
2161
move_selection( console, console->window->selection_start,
2162
get_cell(console, lparam) );
2163
}
2164
}
2165
else
2166
{
2167
record_mouse_input( console, get_cell(console, lparam), wparam, MOUSE_MOVED );
2168
}
2169
break;
2170
2171
case WM_LBUTTONUP:
2172
if (console->window && (console->window->quick_edit || console->window->in_selection))
2173
{
2174
if (GetCapture() == console->win && console->window->in_selection)
2175
{
2176
move_selection( console, console->window->selection_start,
2177
get_cell(console, lparam) );
2178
ReleaseCapture();
2179
}
2180
}
2181
else
2182
{
2183
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2184
}
2185
break;
2186
2187
case WM_RBUTTONDOWN:
2188
if (console->window && (wparam & (MK_CONTROL|MK_SHIFT)) == console->window->menu_mask)
2189
{
2190
POINT pt;
2191
pt.x = (short)LOWORD(lparam);
2192
pt.y = (short)HIWORD(lparam);
2193
ClientToScreen( hwnd, &pt );
2194
set_menu_details( console, console->window->popup_menu );
2195
TrackPopupMenu( console->window->popup_menu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RIGHTBUTTON,
2196
pt.x, pt.y, 0, hwnd, NULL );
2197
}
2198
else
2199
{
2200
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2201
}
2202
break;
2203
2204
case WM_RBUTTONUP:
2205
/* no need to track for rbutton up when opening the popup... the event will be
2206
* swallowed by TrackPopupMenu */
2207
case WM_MBUTTONDOWN:
2208
case WM_MBUTTONUP:
2209
record_mouse_input( console, get_cell(console, lparam), wparam, 0 );
2210
break;
2211
2212
case WM_LBUTTONDBLCLK:
2213
case WM_MBUTTONDBLCLK:
2214
case WM_RBUTTONDBLCLK:
2215
record_mouse_input( console, get_cell(console, lparam), wparam, DOUBLE_CLICK );
2216
break;
2217
2218
case WM_SETFOCUS:
2219
if (console->window && console->active->cursor_visible)
2220
{
2221
CreateCaret( console->win, console->window->cursor_bitmap,
2222
console->active->font.width, console->active->font.height );
2223
update_window_cursor( console );
2224
}
2225
break;
2226
2227
case WM_KILLFOCUS:
2228
if (console->window && console->active->cursor_visible)
2229
DestroyCaret();
2230
break;
2231
2232
case WM_SIZE:
2233
if (console->window && console->window->update_state != UPDATE_BUSY)
2234
resize_window( console,
2235
max( LOWORD(lparam) / console->active->font.width, 20 ),
2236
max( HIWORD(lparam) / console->active->font.height, 20 ));
2237
break;
2238
2239
case WM_HSCROLL:
2240
{
2241
int win_width = console->active->win.right - console->active->win.left + 1;
2242
int x = console->active->win.left;
2243
2244
if (!console->window) break;
2245
switch (LOWORD(wparam))
2246
{
2247
case SB_PAGEUP: x -= 8; break;
2248
case SB_PAGEDOWN: x += 8; break;
2249
case SB_LINEUP: x--; break;
2250
case SB_LINEDOWN: x++; break;
2251
case SB_THUMBTRACK: x = HIWORD(wparam); break;
2252
default: break;
2253
}
2254
x = min( max( x, 0 ), console->active->width - win_width );
2255
if (x != console->active->win.left)
2256
{
2257
console->active->win.left = x;
2258
console->active->win.right = x + win_width - 1;
2259
update_window( console );
2260
}
2261
break;
2262
}
2263
2264
case WM_MOUSEWHEEL:
2265
if (console->active->height <= console->active->win.bottom - console->active->win.top + 1)
2266
{
2267
record_mouse_input(console, get_cell(console, lparam), wparam, MOUSE_WHEELED);
2268
break;
2269
}
2270
/* else fallthrough */
2271
case WM_VSCROLL:
2272
{
2273
int win_height = console->active->win.bottom - console->active->win.top + 1;
2274
int y = console->active->win.top;
2275
2276
if (!console->window) break;
2277
2278
if (msg == WM_MOUSEWHEEL)
2279
{
2280
UINT scroll_lines = 3;
2281
SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0 );
2282
scroll_lines *= -GET_WHEEL_DELTA_WPARAM(wparam) / WHEEL_DELTA;
2283
y += scroll_lines;
2284
}
2285
else
2286
{
2287
switch (LOWORD(wparam))
2288
{
2289
case SB_PAGEUP: y -= 8; break;
2290
case SB_PAGEDOWN: y += 8; break;
2291
case SB_LINEUP: y--; break;
2292
case SB_LINEDOWN: y++; break;
2293
case SB_THUMBTRACK: y = HIWORD(wparam); break;
2294
default: break;
2295
}
2296
}
2297
2298
y = min( max( y, 0 ), console->active->height - win_height );
2299
if (y != console->active->win.top)
2300
{
2301
console->active->win.top = y;
2302
console->active->win.bottom = y + win_height - 1;
2303
update_window( console );
2304
}
2305
break;
2306
}
2307
2308
case WM_SYSCOMMAND:
2309
if (!console->window) break;
2310
switch (wparam)
2311
{
2312
case IDS_DEFAULT:
2313
config_dialog( console, FALSE );
2314
break;
2315
case IDS_PROPERTIES:
2316
config_dialog( console, TRUE );
2317
break;
2318
default:
2319
return DefWindowProcW( hwnd, msg, wparam, lparam );
2320
}
2321
break;
2322
2323
case WM_COMMAND:
2324
if (!console->window) break;
2325
switch (wparam)
2326
{
2327
case IDS_DEFAULT:
2328
config_dialog( console, FALSE );
2329
break;
2330
case IDS_PROPERTIES:
2331
config_dialog( console, TRUE );
2332
break;
2333
case IDS_MARK:
2334
console->window->selection_start.X = console->window->selection_start.Y = 0;
2335
console->window->selection_end.X = console->window->selection_end.Y = 0;
2336
update_selection( console, 0 );
2337
console->window->in_selection = TRUE;
2338
break;
2339
case IDS_COPY:
2340
if (console->window->in_selection)
2341
{
2342
console->window->in_selection = FALSE;
2343
update_selection( console, 0 );
2344
copy_selection( console );
2345
}
2346
break;
2347
case IDS_PASTE:
2348
paste_clipboard( console );
2349
break;
2350
case IDS_SELECTALL:
2351
console->window->selection_start.X = console->window->selection_start.Y = 0;
2352
console->window->selection_end.X = console->active->width - 1;
2353
console->window->selection_end.Y = console->active->height - 1;
2354
update_selection( console, 0 );
2355
console->window->in_selection = TRUE;
2356
break;
2357
case IDS_SCROLL:
2358
case IDS_SEARCH:
2359
FIXME( "Unhandled yet command: %Ix\n", wparam );
2360
break;
2361
default:
2362
return DefWindowProcW( hwnd, msg, wparam, lparam );
2363
}
2364
break;
2365
2366
case WM_INITMENUPOPUP:
2367
if (!console->window || !HIWORD(lparam)) return DefWindowProcW( hwnd, msg, wparam, lparam );
2368
set_menu_details( console, GetSystemMenu(console->win, FALSE) );
2369
break;
2370
2371
default:
2372
return DefWindowProcW( hwnd, msg, wparam, lparam );
2373
}
2374
2375
return 0;
2376
}
2377
2378
void update_window_config( struct console *console, BOOL delay )
2379
{
2380
const int delay_timeout = 50;
2381
2382
if (!console->window || console->window->update_state != UPDATE_NONE) return;
2383
console->window->update_state = UPDATE_PENDING;
2384
if (delay)
2385
SetTimer( console->win, 1, delay_timeout, NULL );
2386
else
2387
PostMessageW( console->win, WM_UPDATE_CONFIG, 0, 0 );
2388
}
2389
2390
void update_window_region( struct console *console, const RECT *update )
2391
{
2392
RECT *window_rect = &console->window->update;
2393
window_rect->left = min( window_rect->left, update->left );
2394
window_rect->top = min( window_rect->top, update->top );
2395
window_rect->right = max( window_rect->right, update->right );
2396
window_rect->bottom = max( window_rect->bottom, update->bottom );
2397
update_window_config( console, TRUE );
2398
}
2399
2400
BOOL init_window( struct console *console )
2401
{
2402
struct console_config config;
2403
WNDCLASSW wndclass;
2404
STARTUPINFOW si;
2405
CHARSETINFO ci;
2406
2407
static struct console_window console_window;
2408
2409
console->window = &console_window;
2410
if (!TranslateCharsetInfo( (DWORD *)(INT_PTR)GetACP(), &ci, TCI_SRCCODEPAGE ))
2411
return FALSE;
2412
2413
console->window->ui_charset = ci.ciCharset;
2414
2415
GetStartupInfoW(&si);
2416
if (si.lpTitle)
2417
{
2418
size_t i, title_len = wcslen( si.lpTitle );
2419
if (!(console->window->config_key = malloc( (title_len + 1) * sizeof(WCHAR) )))
2420
return FALSE;
2421
for (i = 0; i < title_len; i++)
2422
console->window->config_key[i] = si.lpTitle[i] == '\\' ? '_' : si.lpTitle[i];
2423
console->window->config_key[title_len] = 0;
2424
}
2425
2426
load_config( console->window->config_key, &config );
2427
if (si.dwFlags & STARTF_USECOUNTCHARS)
2428
{
2429
config.sb_width = si.dwXCountChars;
2430
config.sb_height = si.dwYCountChars;
2431
}
2432
if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
2433
config.attr = si.dwFillAttribute;
2434
2435
wndclass.style = CS_DBLCLKS;
2436
wndclass.lpfnWndProc = window_proc;
2437
wndclass.cbClsExtra = 0;
2438
wndclass.cbWndExtra = sizeof(DWORD_PTR);
2439
wndclass.hInstance = GetModuleHandleW(NULL);
2440
wndclass.hIcon = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO );
2441
wndclass.hCursor = LoadCursorW( 0, (const WCHAR *)IDC_ARROW );
2442
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2443
wndclass.lpszMenuName = NULL;
2444
wndclass.lpszClassName = L"WineConsoleClass";
2445
RegisterClassW(&wndclass);
2446
2447
if (!CreateWindowW( wndclass.lpszClassName, NULL,
2448
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2449
WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2450
0, 0, 0, 0, wndclass.hInstance, console ))
2451
return FALSE;
2452
2453
if (!config.face_name[0])
2454
set_first_font( console, &config );
2455
2456
apply_config( console, &config );
2457
return TRUE;
2458
}
2459
2460
void init_message_window( struct console *console )
2461
{
2462
WNDCLASSW wndclass;
2463
2464
wndclass.style = CS_DBLCLKS;
2465
wndclass.lpfnWndProc = window_proc;
2466
wndclass.cbClsExtra = 0;
2467
wndclass.cbWndExtra = sizeof(DWORD_PTR);
2468
wndclass.hInstance = GetModuleHandleW( NULL );
2469
wndclass.hIcon = 0;
2470
wndclass.hCursor = 0;
2471
wndclass.hbrBackground = GetStockObject( BLACK_BRUSH );
2472
wndclass.lpszMenuName = NULL;
2473
wndclass.lpszClassName = L"WineConsoleClass";
2474
RegisterClassW(&wndclass);
2475
2476
CreateWindowW( wndclass.lpszClassName, NULL,
2477
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|
2478
WS_MAXIMIZEBOX|WS_HSCROLL|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,
2479
0, 0, HWND_MESSAGE, 0, wndclass.hInstance, console );
2480
}
2481
2482
void teardown_window( struct console *console )
2483
{
2484
if (console->window && !console->window->close_on_exit)
2485
{
2486
MSG msg;
2487
2488
while (GetMessageW( &msg, 0, 0, 0 ))
2489
{
2490
if (msg.message == WM_QUIT) return;
2491
TranslateMessage( &msg );
2492
DispatchMessageW( &msg );
2493
}
2494
}
2495
}
2496
2497