1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <tui/extern.h>
28 #include <tui/tui.h>
29 #include "../tui-priv.h"
30 #include <klib/rc.h>
31 #include <sysalloc.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <windows.h>
36 #include <assert.h>
37
38
39 /**********************************************************************************/
40
tui_color_to_win_fg(KTUI_color c)41 static WORD tui_color_to_win_fg( KTUI_color c)
42 {
43 switch ( c )
44 {
45 case KTUI_c_light_gray : return FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED;
46 case KTUI_c_gray : return FOREGROUND_INTENSITY;
47 case KTUI_c_white : return FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY;
48
49 case KTUI_c_dark_red : return FOREGROUND_RED;
50 case KTUI_c_red : return FOREGROUND_RED|FOREGROUND_INTENSITY;
51
52 case KTUI_c_dark_green : return FOREGROUND_GREEN;
53 case KTUI_c_green : return FOREGROUND_GREEN|FOREGROUND_INTENSITY;
54
55 case KTUI_c_brown : return FOREGROUND_RED|FOREGROUND_GREEN;
56 case KTUI_c_yellow : return FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY;
57
58 case KTUI_c_dark_blue : return FOREGROUND_BLUE;
59 case KTUI_c_blue : return FOREGROUND_BLUE|FOREGROUND_INTENSITY;
60
61 case KTUI_c_dark_magenta : return FOREGROUND_RED|FOREGROUND_BLUE;
62 case KTUI_c_magenta : return FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY;
63
64 case KTUI_c_dark_cyan : return FOREGROUND_GREEN|FOREGROUND_BLUE;
65 case KTUI_c_cyan : return FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY;
66
67
68 case KTUI_c_black :
69 default : return 0;
70 }
71 }
72
73
tui_color_to_win_bg(KTUI_color c)74 static WORD tui_color_to_win_bg( KTUI_color c )
75 {
76 switch ( c )
77 {
78 case KTUI_c_light_gray : return BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED;
79 case KTUI_c_gray : return BACKGROUND_INTENSITY;
80 case KTUI_c_white : return BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED|BACKGROUND_INTENSITY;
81
82 case KTUI_c_dark_red : return BACKGROUND_RED;
83 case KTUI_c_red : return BACKGROUND_RED|BACKGROUND_INTENSITY;
84
85 case KTUI_c_dark_green : return BACKGROUND_GREEN;
86 case KTUI_c_green : return BACKGROUND_GREEN|BACKGROUND_INTENSITY;
87
88 case KTUI_c_brown : return BACKGROUND_RED|BACKGROUND_GREEN;
89 case KTUI_c_yellow : return BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_INTENSITY;
90
91 case KTUI_c_dark_blue : return BACKGROUND_BLUE;
92 case KTUI_c_blue : return BACKGROUND_BLUE|BACKGROUND_INTENSITY;
93
94 case KTUI_c_dark_magenta : return BACKGROUND_RED|BACKGROUND_BLUE;
95 case KTUI_c_magenta : return BACKGROUND_RED|BACKGROUND_BLUE|BACKGROUND_INTENSITY;
96
97 case KTUI_c_dark_cyan : return BACKGROUND_GREEN|BACKGROUND_BLUE;
98 case KTUI_c_cyan : return BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY;
99
100
101 case KTUI_c_black :
102 default : return 0;
103 }
104 }
105
106
set_tui_attrib_and_colors(HANDLE h,tui_ac * curr,KTUI_attrib attr,KTUI_color color_fg,KTUI_color color_bg)107 static void set_tui_attrib_and_colors( HANDLE h, tui_ac * curr,
108 KTUI_attrib attr,
109 KTUI_color color_fg,
110 KTUI_color color_bg )
111 {
112 if ( curr->attr != attr || curr->fg != color_fg || curr->bg != color_bg )
113 {
114 bool reverse = ( attr & KTUI_a_underline ) || ( attr & KTUI_a_inverse );
115
116 if ( reverse )
117 SetConsoleTextAttribute( h, tui_color_to_win_fg( color_bg ) |
118 tui_color_to_win_bg( color_fg ) );
119 else
120 SetConsoleTextAttribute( h, tui_color_to_win_fg( color_fg ) |
121 tui_color_to_win_bg( color_bg ) );
122
123 curr->attr = attr;
124 curr->fg = color_fg;
125 curr->bg = color_bg;
126 }
127 }
128
129
tui_send_strip(int x,int y,int count,tui_ac * curr,tui_ac * v,const char * s)130 void CC tui_send_strip( int x, int y, int count, tui_ac * curr, tui_ac * v,
131 const char * s )
132 {
133 HANDLE h = GetStdHandle( STD_OUTPUT_HANDLE );
134 if ( h != INVALID_HANDLE_VALUE )
135 {
136 DWORD nBytesWritten;
137 COORD curpos = { (SHORT)x, (SHORT)y };
138
139 set_tui_attrib_and_colors( h, curr, v->attr, v->fg, v->bg );
140 SetConsoleCursorPosition( h, curpos );
141 WriteConsoleA( h, s, ( DWORD )count, &nBytesWritten, NULL );
142 }
143 }
144
145
146 /**********************************************************************************/
147
148
149 typedef struct KTUI_pf
150 {
151 CONSOLE_SCREEN_BUFFER_INFO sbinfo;
152 CONSOLE_CURSOR_INFO curinfo;
153 DWORD bitsConsoleInputMode;
154 int esc_count;
155
156 int prev_x, prev_y;
157 KTUI_mouse_button prev_button;
158 KTUI_mouse_action prev_action;
159 } KTUI_pf;
160
161
store_mouse_event(struct KTUI_pf * pf,int x,int y,KTUI_mouse_button b,KTUI_mouse_action a)162 static void store_mouse_event( struct KTUI_pf * pf, int x, int y, KTUI_mouse_button b, KTUI_mouse_action a )
163 {
164 pf -> prev_x = x;
165 pf -> prev_y = y;
166 pf -> prev_button = b;
167 pf -> prev_action = a;
168 }
169
different_mouse_event(struct KTUI_pf * pf,int x,int y,KTUI_mouse_button b,KTUI_mouse_action a)170 static bool different_mouse_event( struct KTUI_pf * pf, int x, int y, KTUI_mouse_button b, KTUI_mouse_action a )
171 {
172 return ( pf -> prev_x != x ||
173 pf -> prev_y != y ||
174 pf -> prev_button != b ||
175 pf -> prev_action != a );
176 }
177
178
179 static KTUI_key g_VirtualCodeTable[ 256 ]; /* if max VK_* constant value is greater than 0xFF, then this code must be revised */
180
181
InitTableRange(int * table,size_t offset_first,size_t offset_last,int val)182 static void InitTableRange( int* table, size_t offset_first, size_t offset_last, int val )
183 {
184 size_t i;
185 assert( offset_first < 256 );
186 assert( offset_last < 256 );
187
188 for ( i = offset_first; i <= offset_last; ++i )
189 table[ i ] = val;
190 }
191
192
InitVKTable(KTUI_key * table,size_t size)193 static void InitVKTable( KTUI_key* table, size_t size )
194 {
195 /*
196 the table is supposed to be used in a "white-list approach",
197 so it initializes every code that is supposed to be processed
198 */
199 size_t i;
200 for ( i = 0; i < size; ++i )
201 table[ i ] = ktui_none;
202
203 /* special key virtual codes */
204 table[VK_DOWN] = ktui_down;
205 table[VK_UP] = ktui_up;
206 table[VK_LEFT] = ktui_left;
207 table[VK_RIGHT] = ktui_right;
208 table[VK_HOME] = ktui_home;
209 table[VK_END] = ktui_end;
210 table[VK_BACK] = ktui_bksp;
211 table[VK_F1] = ktui_F1;
212 table[VK_F2] = ktui_F2;
213 table[VK_F3] = ktui_F3;
214 table[VK_F4] = ktui_F4;
215 table[VK_F5] = ktui_F5;
216 table[VK_F6] = ktui_F6;
217 table[VK_F7] = ktui_F7;
218 table[VK_F8] = ktui_F8;
219 table[VK_F9] = ktui_F9;
220 table[VK_F10] = ktui_F10;
221 table[VK_F11] = ktui_F11;
222 table[VK_F12] = ktui_F12;
223 table[VK_DELETE] = ktui_del;
224 table[VK_INSERT] = ktui_ins;
225 table[VK_NEXT] = ktui_pgdn;
226 table[VK_PRIOR] = ktui_pgup;
227 table[VK_RETURN] = ktui_enter;
228 table[VK_TAB] = ktui_tab;
229 /*
230 for the numpad windows reports the same ascii characters
231 as for standart number keys, so treat them as ktui_alpha
232 */
233 table[VK_NUMPAD0] = ktui_alpha;
234 table[VK_NUMPAD1] = ktui_alpha;
235 table[VK_NUMPAD2] = ktui_alpha;
236 table[VK_NUMPAD3] = ktui_alpha;
237 table[VK_NUMPAD4] = ktui_alpha;
238 table[VK_NUMPAD5] = ktui_alpha;
239 table[VK_NUMPAD6] = ktui_alpha;
240 table[VK_NUMPAD7] = ktui_alpha;
241 table[VK_NUMPAD8] = ktui_alpha;
242 table[VK_NUMPAD9] = ktui_alpha;
243 table[VK_MULTIPLY] = ktui_alpha;
244 table[VK_ADD] = ktui_alpha;
245 table[VK_SUBTRACT] = ktui_alpha;
246 table[VK_DECIMAL] = ktui_alpha;
247 table[VK_DIVIDE] = ktui_alpha;
248
249 /* some other keys translated to ASCII */
250 table[VK_SPACE] = ktui_alpha;
251 table[VK_OEM_1] = ktui_alpha;
252 table[VK_OEM_PLUS] = ktui_alpha;
253 table[VK_OEM_COMMA] = ktui_alpha;
254 table[VK_OEM_MINUS] = ktui_alpha;
255 table[VK_OEM_PERIOD] = ktui_alpha;
256 table[VK_OEM_2] = ktui_alpha;
257 table[VK_OEM_3] = ktui_alpha;
258 table[VK_OEM_4] = ktui_alpha;
259 table[VK_OEM_5] = ktui_alpha;
260 table[VK_OEM_6] = ktui_alpha;
261 table[VK_OEM_7] = ktui_alpha;
262 table[VK_OEM_8] = ktui_alpha;
263 table[VK_OEM_102] = ktui_alpha;
264 table[VK_OEM_CLEAR] = ktui_alpha;
265 table[VK_ESCAPE] = ktui_alpha;
266
267 /* keys */
268 InitTableRange( table, 0x30, 0x39, ktui_alpha );
269 InitTableRange( table, 0x41, 0x5A, ktui_alpha );
270 }
271
272
TranslateVKtoKTUI(WORD wVirtualKeyCode)273 static KTUI_key TranslateVKtoKTUI( WORD wVirtualKeyCode )
274 {
275 KTUI_key res;
276 if ( wVirtualKeyCode < _countof( g_VirtualCodeTable ) )
277 res = g_VirtualCodeTable[ wVirtualKeyCode ];
278 else
279 res = ktui_none;
280 return res;
281 }
282
283
save_current_console_settings(HANDLE hStdOut,HANDLE hStdIn,KTUI_pf * pWinSettings,KTUI * pCommonSettings)284 static void save_current_console_settings( HANDLE hStdOut, HANDLE hStdIn, KTUI_pf * pWinSettings, KTUI * pCommonSettings )
285 {
286 GetConsoleScreenBufferInfo( hStdOut, &pWinSettings->sbinfo );
287 GetConsoleCursorInfo( hStdOut, &pWinSettings->curinfo );
288 GetConsoleMode( hStdIn, &pWinSettings->bitsConsoleInputMode );
289
290 pCommonSettings->lines = ( pWinSettings->sbinfo.srWindow.Bottom - pWinSettings->sbinfo.srWindow.Top );
291 pCommonSettings->cols = ( pWinSettings->sbinfo.srWindow.Right - pWinSettings->sbinfo.srWindow.Left );
292 }
293
294
set_tui_settings(HANDLE hStdOut,HANDLE hStdIn,KTUI_pf const * pWinSettings)295 static void set_tui_settings( HANDLE hStdOut, HANDLE hStdIn, KTUI_pf const * pWinSettings )
296 {
297 DWORD bitsMode = pWinSettings->bitsConsoleInputMode; /* use mostly default windows settings */
298 CONSOLE_CURSOR_INFO curinfo = { 1, FALSE };
299
300 bitsMode &= ~ENABLE_ECHO_INPUT; /* disable echo */
301 bitsMode &= ~ENABLE_LINE_INPUT; /* something like raw mode? TODO: ask Wolfgang */
302 bitsMode &= ~ENABLE_PROCESSED_INPUT; /* capture Ctrl-C by application rather than system, shold be reset along with ENABLE_LINE_INPUT */
303
304 bitsMode |= ENABLE_MOUSE_INPUT; /* explicitly enabling mouse for the case when it was disabled in windows */
305 /*bitsMode |= ENABLE_QUICK_EDIT_MODE; /* explicitly enabling user to use the mouse for text selection and editing*/
306 bitsMode |= ENABLE_WINDOW_INPUT; /* process console screen buffer changes (?)*/
307
308 SetConsoleMode( hStdIn, bitsMode );
309 SetConsoleCursorInfo( hStdOut, &curinfo ); /* cursor off */
310 }
311
312
restore_console_settings(HANDLE hStdOut,HANDLE hStdIn,KTUI_pf const * pWinSettings)313 static void restore_console_settings( HANDLE hStdOut, HANDLE hStdIn, KTUI_pf const * pWinSettings )
314 {
315 SetConsoleMode( hStdIn, pWinSettings->bitsConsoleInputMode );
316
317 SetConsoleCursorPosition( hStdOut, pWinSettings->sbinfo.dwCursorPosition );
318 SetConsoleCursorInfo( hStdOut, &pWinSettings->curinfo );
319 SetConsoleTextAttribute( hStdOut, pWinSettings->sbinfo.wAttributes );
320 SetConsoleMode( hStdIn, pWinSettings->bitsConsoleInputMode );
321 }
322
323
324 /* This is from MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022%28v=vs.85%29.aspx */
cls(HANDLE hConsole)325 void cls( HANDLE hConsole )
326 {
327 COORD coordScreen = { 0, 0 }; // home for the cursor
328 DWORD cCharsWritten;
329 CONSOLE_SCREEN_BUFFER_INFO csbi;
330 DWORD dwConSize;
331
332 /* Get the number of character cells in the current buffer. */
333
334 if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
335 {
336 return;
337 }
338
339 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
340
341 /* Fill the entire screen with blanks. */
342
343 if( !FillConsoleOutputCharacter( hConsole, /* Handle to console screen buffer */
344 (TCHAR) ' ', /* Character to write to the buffer */
345 dwConSize, /* Number of cells to write */
346 coordScreen, /* Coordinates of first cell */
347 &cCharsWritten ))/* Receive number of characters written */
348 {
349 return;
350 }
351
352 /* Get the current text attribute. */
353
354 if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
355 {
356 return;
357 }
358
359 /* Set the buffer's attributes accordingly. */
360
361 if( !FillConsoleOutputAttribute( hConsole, /* Handle to console screen buffer */
362 csbi.wAttributes, /* Character attributes to use */
363 dwConSize, /* Number of cells to set attribute */
364 coordScreen, /* Coordinates of first cell */
365 &cCharsWritten )) /* Receive number of characters written */
366 {
367 return;
368 }
369
370 /* Put the cursor at its home coordinates. */
371
372 SetConsoleCursorPosition( hConsole, coordScreen );
373 }
374
375
KTUI_Init_platform(KTUI * self)376 rc_t CC KTUI_Init_platform( KTUI * self )
377 {
378 HANDLE hStdOut = INVALID_HANDLE_VALUE;
379 HANDLE hStdIn = INVALID_HANDLE_VALUE;
380 rc_t rc = 0;
381 struct KTUI_pf * pf = malloc( sizeof(*pf) );
382 if ( pf == NULL )
383 rc = RC( rcApp, rcAttr, rcCreating, rcMemory, rcExhausted );
384 else
385 {
386 memset( pf, 0, sizeof( *pf ) );
387 hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
388 hStdIn = GetStdHandle( STD_INPUT_HANDLE );
389 if ( hStdOut != INVALID_HANDLE_VALUE && hStdIn != INVALID_HANDLE_VALUE )
390 {
391 save_current_console_settings( hStdOut, hStdIn, pf, self );
392 set_tui_settings( hStdOut, hStdIn, pf );
393 }
394
395 self->pf = pf;
396 InitVKTable( g_VirtualCodeTable, _countof( g_VirtualCodeTable ) );
397 store_mouse_event( pf, 0, 0, ktui_mouse_button_none, ktui_mouse_action_none );
398 }
399 return rc;
400 }
401
402
KTUI_Destroy_platform(struct KTUI_pf * pf)403 rc_t CC KTUI_Destroy_platform ( struct KTUI_pf * pf )
404 {
405 HANDLE hStdOut = INVALID_HANDLE_VALUE;
406 HANDLE hStdIn = INVALID_HANDLE_VALUE;
407
408 if ( pf != NULL )
409 {
410 hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
411 hStdIn = GetStdHandle( STD_INPUT_HANDLE );
412 if ( hStdOut != INVALID_HANDLE_VALUE && hStdIn != INVALID_HANDLE_VALUE )
413 {
414 restore_console_settings( hStdOut, hStdIn, pf );
415 cls( hStdOut );
416 }
417 free( ( void * ) pf );
418 }
419
420 return 0;
421 }
422
423
KeyEventProc(KEY_EVENT_RECORD const * pEvent,struct KTUI * self)424 static BOOL KeyEventProc( KEY_EVENT_RECORD const* pEvent, struct KTUI * self )
425 {
426 BOOL ret = FALSE;
427 if ( pEvent->bKeyDown )
428 {
429 struct KTUI_pf * pf = ( self->pf );
430 int key = 0;
431
432 KTUI_key code = TranslateVKtoKTUI( pEvent->wVirtualKeyCode );
433
434 if ( code == ktui_alpha )
435 {
436 key = ( int )( pEvent->uChar.AsciiChar );
437
438 /* we artificially let the user press ESC twice to make it do the same as a posix console */
439 if ( key == 27 )
440 {
441 if ( pf->esc_count == 0 )
442 {
443 code = ktui_none;
444 pf->esc_count = 1;
445 }
446 else
447 pf->esc_count = 0;
448 }
449 else
450 pf->esc_count = 0;
451 }
452 else
453 pf->esc_count = 0;
454
455 if ( code == ktui_tab && ( ( pEvent->dwControlKeyState & SHIFT_PRESSED ) == SHIFT_PRESSED ) )
456 code = ktui_shift_tab;
457
458 if ( code != ktui_none )
459 {
460 size_t i;
461 for ( i = 0; i < pEvent->wRepeatCount; ++i )
462 {
463 put_kb_event( self, key, code );
464 ret = TRUE;
465 }
466 }
467 }
468 return ret;
469 }
470
471
get_button(DWORD btn_flags)472 static KTUI_mouse_button get_button( DWORD btn_flags )
473 {
474 KTUI_mouse_button res = ktui_mouse_button_none;
475 switch( btn_flags )
476 {
477 case FROM_LEFT_1ST_BUTTON_PRESSED : res = ktui_mouse_button_left; break;
478 case FROM_LEFT_2ND_BUTTON_PRESSED : res = ktui_mouse_button_middle; break;
479 case RIGHTMOST_BUTTON_PRESSED : res = ktui_mouse_button_right; break;
480 case 0 : res = ktui_mouse_button_up; break;
481 }
482 return res;
483 }
484
get_action(DWORD ev_flags,KTUI_mouse_button button)485 static KTUI_mouse_action get_action( DWORD ev_flags, KTUI_mouse_button button )
486 {
487 KTUI_mouse_action res = ktui_mouse_action_none;
488
489 if ( ev_flags == 0 || ( ( ev_flags & DOUBLE_CLICK ) == DOUBLE_CLICK ) )
490 {
491 res = ktui_mouse_action_button;
492 }
493 else if ( ( ev_flags & MOUSE_MOVED ) == MOUSE_MOVED )
494 {
495 /* to make the behavior the same as on posix:
496 if not mouse-buttons is pressed, do not report a move action... */
497 if ( button != ktui_mouse_button_up )
498 res = ktui_mouse_action_move;
499 }
500 else if ( ( ev_flags & MOUSE_WHEELED ) == MOUSE_WHEELED )
501 {
502 res = ktui_mouse_action_scroll;
503 }
504 return res;
505 }
506
MouseEventProc(MOUSE_EVENT_RECORD const * pEvent,struct KTUI * self)507 static void MouseEventProc( MOUSE_EVENT_RECORD const* pEvent, struct KTUI* self )
508 {
509 KTUI_mouse_button button = get_button( pEvent->dwButtonState );
510 KTUI_mouse_action action = get_action( pEvent->dwEventFlags, button );
511
512 if ( button != ktui_mouse_button_none && action != ktui_mouse_action_none )
513 {
514 int x = pEvent->dwMousePosition.X;
515 int y = pEvent->dwMousePosition.Y;
516 if ( different_mouse_event( self->pf, x, y, button, action ) )
517 {
518 put_mouse_event( self, x, y, button, action,
519 ( uint32_t )( pEvent->dwEventFlags & 0xFFFFFFFF ) );
520 store_mouse_event( self->pf, x, y, button, action );
521 }
522 }
523 }
524
525
WindowBufferSizeEventProc(WINDOW_BUFFER_SIZE_RECORD const * pEvent,struct KTUI * self)526 static void WindowBufferSizeEventProc( WINDOW_BUFFER_SIZE_RECORD const* pEvent, struct KTUI* self )
527 {
528 put_window_event( self, pEvent->dwSize.Y, pEvent->dwSize.X );
529 }
530
531
532 #define INPUT_EVENT_BUF_SIZE 10
533
ReadAndProcessEvents(struct KTUI * self,HANDLE h)534 static BOOL ReadAndProcessEvents( struct KTUI * self, HANDLE h )
535 {
536 DWORD nEventsRead;
537 INPUT_RECORD arrInputEvents[ INPUT_EVENT_BUF_SIZE ];
538 PINPUT_RECORD pInputEvents = arrInputEvents;
539 BOOL res = ReadConsoleInput( h, pInputEvents, INPUT_EVENT_BUF_SIZE, &nEventsRead );
540 if ( res )
541 {
542 DWORD i;
543 for ( i = 0; i < nEventsRead; ++i )
544 {
545 switch ( pInputEvents[ i ].EventType )
546 {
547 case KEY_EVENT : KeyEventProc( &pInputEvents[ i ].Event.KeyEvent, self ); break;
548 case MOUSE_EVENT : MouseEventProc( &pInputEvents[ i ].Event.MouseEvent, self ); break;
549 case WINDOW_BUFFER_SIZE_EVENT : WindowBufferSizeEventProc( &pInputEvents[ i ].Event.WindowBufferSizeEvent, self ); break;
550 }
551 }
552 }
553 return res;
554 }
555
556
read_from_stdin(struct KTUI * self,uint32_t timeout)557 void CC read_from_stdin( struct KTUI * self, uint32_t timeout )
558 {
559 BOOL resEventProc;
560 DWORD dwStartedWaitingTime, dwEffectiveTimeout, dwTimeElapsed, dwWaitRes;
561 HANDLE h = INVALID_HANDLE_VALUE;
562 DWORD const dwMinimumTimeout = 10;
563
564 h = GetStdHandle( STD_INPUT_HANDLE );
565 if ( h == INVALID_HANDLE_VALUE )
566 return;
567
568 /* blocking waiting with the timeout */
569 dwEffectiveTimeout = min( ( DWORD )( timeout / 1000 ), dwMinimumTimeout );
570 dwStartedWaitingTime = GetTickCount();
571 dwTimeElapsed = 0;
572 for ( ; ; )
573 {
574 dwWaitRes = WaitForSingleObject( h, dwEffectiveTimeout - dwTimeElapsed );
575 if ( dwWaitRes == WAIT_OBJECT_0 )
576 {
577 resEventProc = ReadAndProcessEvents( self, h );
578 if ( resEventProc )
579 break;
580 /*continue waiting for the remaining time */
581 dwTimeElapsed = GetTickCount() - dwStartedWaitingTime;
582 if ( dwTimeElapsed >= dwEffectiveTimeout )
583 break;
584 }
585 else /* timeout, error */
586 {
587 break;
588 }
589 }
590 }
591