Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

input.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1985 - 1999, Microsoft Corporation 00004 00005 Module Name: 00006 00007 input.c 00008 00009 Abstract: 00010 00011 This file implements the circular buffer management for 00012 input events. 00013 00014 The circular buffer is described by a header, 00015 which resides in the beginning of the memory allocated when the 00016 buffer is created. The header contains all of the 00017 per-buffer information, such as reader, writer, and 00018 reference counts, and also holds the pointers into 00019 the circular buffer proper. 00020 00021 When the in and out pointers are equal, the circular buffer 00022 is empty. When the in pointer trails the out pointer 00023 by 1, the buffer is full. Thus, a 512 byte buffer can hold 00024 only 511 bytes; one byte is lost so that full and empty 00025 conditions can be distinguished. So that the user can 00026 put 512 bytes in a buffer that they created with a size 00027 of 512, we allow for this byte lost when allocating 00028 the memory. 00029 00030 Author: 00031 00032 Therese Stowell (thereses) 6-Nov-1990 00033 Adapted from OS/2 subsystem server\srvpipe.c 00034 00035 Revision History: 00036 00037 --*/ 00038 00039 #include "precomp.h" 00040 #pragma hdrstop 00041 00042 #define CTRL_BUT_NOT_ALT(n) \ 00043 (((n) & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) && \ 00044 !((n) & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))) 00045 00046 // 00047 // this boolean is TRUE while we are processing a WM_QUERYENDSESSION message. 00048 // since shutdown is guaranteed to be done serially (one window at a time), 00049 // we can use one boolean. 00050 // 00051 00052 UINT ProgmanHandleMessage; 00053 00054 int DialogBoxCount; 00055 00056 LPTHREAD_START_ROUTINE CtrlRoutine; // address of client side ctrl-thread routine 00057 00058 DWORD InputThreadTlsIndex; 00059 00060 #define MAX_CHARS_FROM_1_KEYSTROKE 6 00061 00062 00063 // 00064 // the following data structures are a hack to work around the fact that 00065 // MapVirtualKey does not return the correct virtual key code in many cases. 00066 // we store the correct info (from the keydown message) in the CONSOLE_KEY_INFO 00067 // structure when a keydown message is translated. then when we receive a 00068 // wm_[sys][dead]char message, we retrieve it and clear out the record. 00069 // 00070 00071 #define CONSOLE_FREE_KEY_INFO 0 00072 #define CONSOLE_MAX_KEY_INFO 32 00073 00074 typedef struct _CONSOLE_KEY_INFO { 00075 HWND hWnd; 00076 WORD wVirtualKeyCode; 00077 WORD wVirtualScanCode; 00078 } CONSOLE_KEY_INFO, *PCONSOLE_KEY_INFO; 00079 00080 CONSOLE_KEY_INFO ConsoleKeyInfo[CONSOLE_MAX_KEY_INFO]; 00081 00082 VOID 00083 UserExitWorkerThread(VOID); 00084 00085 BOOL 00086 InitWindowClass( VOID ); 00087 00088 #if !defined(FE_SB) 00089 NTSTATUS 00090 ReadBuffer( 00091 IN PINPUT_INFORMATION InputInformation, 00092 OUT PVOID Buffer, 00093 IN ULONG Length, 00094 OUT PULONG EventsRead, 00095 IN BOOL Peek, 00096 IN BOOL StreamRead, 00097 OUT PBOOL ResetWaitEvent 00098 ); 00099 #endif 00100 00101 00102 NTSTATUS 00103 CreateInputBuffer( 00104 IN ULONG NumberOfEvents OPTIONAL, 00105 IN PINPUT_INFORMATION InputBufferInformation 00106 #if defined(FE_SB) 00107 , 00108 IN PCONSOLE_INFORMATION Console 00109 #endif 00110 ) 00111 00112 /*++ 00113 00114 Routine Description: 00115 00116 This routine creates an input buffer. It allocates the circular 00117 buffer and initializes the information fields. 00118 00119 Arguments: 00120 00121 NumberOfEvents - Size of input buffer in events. 00122 00123 InputBufferInformation - Pointer to input buffer information structure. 00124 00125 Return Value: 00126 00127 00128 --*/ 00129 00130 { 00131 ULONG BufferSize; 00132 NTSTATUS Status; 00133 00134 if (NumberOfEvents == 0) { 00135 NumberOfEvents = DEFAULT_NUMBER_OF_EVENTS; 00136 } 00137 00138 // allocate memory for circular buffer 00139 00140 BufferSize = sizeof(INPUT_RECORD) * (NumberOfEvents+1); 00141 InputBufferInformation->InputBuffer = (PINPUT_RECORD)ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ),BufferSize); 00142 if (InputBufferInformation->InputBuffer == NULL) { 00143 return STATUS_NO_MEMORY; 00144 } 00145 Status = NtCreateEvent(&InputBufferInformation->InputWaitEvent, 00146 EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 00147 if (!NT_SUCCESS(Status)) { 00148 ConsoleHeapFree(InputBufferInformation->InputBuffer); 00149 return STATUS_NO_MEMORY; 00150 } 00151 InitializeListHead(&InputBufferInformation->ReadWaitQueue); 00152 00153 // initialize buffer header 00154 00155 InputBufferInformation->InputBufferSize = NumberOfEvents; 00156 InputBufferInformation->ShareAccess.OpenCount = 0; 00157 InputBufferInformation->ShareAccess.Readers = 0; 00158 InputBufferInformation->ShareAccess.Writers = 0; 00159 InputBufferInformation->ShareAccess.SharedRead = 0; 00160 InputBufferInformation->ShareAccess.SharedWrite = 0; 00161 InputBufferInformation->InputMode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT; 00162 InputBufferInformation->AllocatedBufferSize = BufferSize; 00163 InputBufferInformation->RefCount = 0; 00164 InputBufferInformation->First = (ULONG_PTR) InputBufferInformation->InputBuffer; 00165 InputBufferInformation->In = (ULONG_PTR) InputBufferInformation->InputBuffer; 00166 InputBufferInformation->Out = (ULONG_PTR) InputBufferInformation->InputBuffer; 00167 InputBufferInformation->Last = (ULONG_PTR) InputBufferInformation->InputBuffer + BufferSize; 00168 #if defined(FE_SB) 00169 #if defined(FE_IME) 00170 InputBufferInformation->ImeMode.Disable = FALSE; 00171 InputBufferInformation->ImeMode.Unavailable = FALSE; 00172 InputBufferInformation->ImeMode.Open = FALSE; 00173 InputBufferInformation->ImeMode.ReadyConversion = FALSE; 00174 #endif // FE_IME 00175 InputBufferInformation->Console = Console; 00176 RtlZeroMemory(&InputBufferInformation->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD)); 00177 RtlZeroMemory(&InputBufferInformation->WriteConInpDbcsLeadByte,sizeof(INPUT_RECORD)); 00178 #endif 00179 00180 return STATUS_SUCCESS; 00181 } 00182 00183 NTSTATUS 00184 ReinitializeInputBuffer( 00185 OUT PINPUT_INFORMATION InputBufferInformation 00186 ) 00187 00188 /*++ 00189 00190 Routine Description: 00191 00192 This routine resets the input buffer information fields to their 00193 initial values. 00194 00195 Arguments: 00196 00197 InputBufferInformation - Pointer to input buffer information structure. 00198 00199 Return Value: 00200 00201 Note: 00202 00203 The console lock must be held when calling this routine. 00204 00205 --*/ 00206 00207 { 00208 NtClearEvent(InputBufferInformation->InputWaitEvent); 00209 InputBufferInformation->ShareAccess.OpenCount = 0; 00210 InputBufferInformation->ShareAccess.Readers = 0; 00211 InputBufferInformation->ShareAccess.Writers = 0; 00212 InputBufferInformation->ShareAccess.SharedRead = 0; 00213 InputBufferInformation->ShareAccess.SharedWrite = 0; 00214 InputBufferInformation->InputMode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT; 00215 InputBufferInformation->In = (ULONG_PTR) InputBufferInformation->InputBuffer; 00216 InputBufferInformation->Out = (ULONG_PTR) InputBufferInformation->InputBuffer; 00217 return STATUS_SUCCESS; 00218 } 00219 00220 VOID 00221 FreeInputBuffer( 00222 IN PINPUT_INFORMATION InputBufferInformation 00223 ) 00224 00225 /*++ 00226 00227 Routine Description: 00228 00229 This routine frees the resources associated with an input buffer. 00230 00231 Arguments: 00232 00233 InputBufferInformation - Pointer to input buffer information structure. 00234 00235 Return Value: 00236 00237 00238 --*/ 00239 00240 { 00241 ASSERT(InputBufferInformation->RefCount == 0); 00242 CloseHandle(InputBufferInformation->InputWaitEvent); 00243 ConsoleHeapFree(InputBufferInformation->InputBuffer); 00244 } 00245 00246 00247 NTSTATUS 00248 WaitForMoreToRead( 00249 IN PINPUT_INFORMATION InputInformation, 00250 IN PCSR_API_MSG Message OPTIONAL, 00251 IN CSR_WAIT_ROUTINE WaitRoutine OPTIONAL, 00252 IN PVOID WaitParameter OPTIONAL, 00253 IN ULONG WaitParameterLength OPTIONAL, 00254 IN BOOLEAN WaitBlockExists OPTIONAL 00255 ) 00256 00257 /*++ 00258 00259 Routine Description: 00260 00261 This routine waits for a writer to add data to the buffer. 00262 00263 Arguments: 00264 00265 InputInformation - buffer to wait for 00266 00267 Console - Pointer to console buffer information. 00268 00269 Message - if called from dll (not InputThread), points to api 00270 message. this parameter is used for wait block processing. 00271 00272 WaitRoutine - Routine to call when wait is woken up. 00273 00274 WaitParameter - Parameter to pass to wait routine. 00275 00276 WaitParameterLength - Length of wait parameter. 00277 00278 WaitBlockExists - TRUE if wait block has already been created. 00279 00280 Return Value: 00281 00282 STATUS_WAIT - call was from client and wait block has been created. 00283 00284 STATUS_SUCCESS - call was from server and wait has been satisfied. 00285 00286 --*/ 00287 00288 { 00289 PVOID WaitParameterBuffer; 00290 00291 if (!WaitBlockExists) { 00292 WaitParameterBuffer = (PVOID)ConsoleHeapAlloc(MAKE_TAG( WAIT_TAG ),WaitParameterLength); 00293 if (WaitParameterBuffer == NULL) { 00294 return STATUS_NO_MEMORY; 00295 } 00296 RtlCopyMemory(WaitParameterBuffer,WaitParameter,WaitParameterLength); 00297 #if defined(FE_SB) 00298 if (WaitParameterLength == sizeof(COOKED_READ_DATA) && 00299 InputInformation->Console->lpCookedReadData == WaitParameter) { 00300 InputInformation->Console->lpCookedReadData = WaitParameterBuffer; 00301 } 00302 #endif 00303 if (!CsrCreateWait(&InputInformation->ReadWaitQueue, 00304 WaitRoutine, 00305 CSR_SERVER_QUERYCLIENTTHREAD(), 00306 Message, 00307 WaitParameterBuffer, 00308 NULL 00309 )) { 00310 ConsoleHeapFree(WaitParameterBuffer); 00311 #if defined(FE_SB) 00312 InputInformation->Console->lpCookedReadData = NULL; 00313 #endif 00314 return STATUS_NO_MEMORY; 00315 } 00316 } 00317 return CONSOLE_STATUS_WAIT; 00318 } 00319 00320 00321 VOID 00322 WakeUpReadersWaitingForData( 00323 IN PCONSOLE_INFORMATION Console, 00324 PINPUT_INFORMATION InputInformation 00325 ) 00326 00327 /*++ 00328 00329 Routine Description: 00330 00331 This routine wakes up readers waiting for data to read. 00332 00333 Arguments: 00334 00335 InputInformation - buffer to alert readers for 00336 00337 Return Value: 00338 00339 TRUE - The operation was successful 00340 00341 FALSE/NULL - The operation failed. 00342 00343 --*/ 00344 00345 { 00346 BOOLEAN WaitSatisfied; 00347 WaitSatisfied = CsrNotifyWait(&InputInformation->ReadWaitQueue, 00348 FALSE, 00349 NULL, 00350 NULL 00351 ); 00352 if (WaitSatisfied) { 00353 // #334370 under stress, WaitQueue may already hold the satisfied waits 00354 ASSERT ((Console->WaitQueue == NULL) || 00355 (Console->WaitQueue == &InputInformation->ReadWaitQueue)); 00356 Console->WaitQueue = &InputInformation->ReadWaitQueue; 00357 } 00358 } 00359 00360 00361 NTSTATUS 00362 GetNumberOfReadyEvents( 00363 IN PINPUT_INFORMATION InputInformation, 00364 OUT PULONG NumberOfEvents 00365 ) 00366 00367 /*++ 00368 00369 Routine Description: 00370 00371 This routine returns the number of events in the input buffer. 00372 00373 Arguments: 00374 00375 InputInformation - Pointer to input buffer information structure. 00376 00377 NumberOfEvents - On output contains the number of events. 00378 00379 Return Value: 00380 00381 Note: 00382 00383 The console lock must be held when calling this routine. 00384 00385 --*/ 00386 00387 { 00388 if (InputInformation->In < InputInformation->Out) { 00389 *NumberOfEvents = (ULONG)(InputInformation->Last - InputInformation->Out); 00390 *NumberOfEvents += (ULONG)(InputInformation->In - InputInformation->First); 00391 } 00392 else { 00393 *NumberOfEvents = (ULONG)(InputInformation->In - InputInformation->Out); 00394 } 00395 *NumberOfEvents /= sizeof(INPUT_RECORD); 00396 00397 return STATUS_SUCCESS; 00398 } 00399 00400 NTSTATUS 00401 FlushAllButKeys( 00402 PINPUT_INFORMATION InputInformation 00403 ) 00404 00405 /*++ 00406 00407 Routine Description: 00408 00409 This routine removes all but the key events from the buffer. 00410 00411 Arguments: 00412 00413 InputInformation - Pointer to input buffer information structure. 00414 00415 Return Value: 00416 00417 Note: 00418 00419 The console lock must be held when calling this routine. 00420 00421 --*/ 00422 00423 { 00424 ULONG NumberOfEventsRead,i; 00425 NTSTATUS Status; 00426 PINPUT_RECORD TmpInputBuffer,InPtr,TmpInputBufferPtr; 00427 ULONG BufferSize; 00428 BOOL Dummy; 00429 00430 if (InputInformation->In != InputInformation->Out) { 00431 00432 // 00433 // allocate memory for temp buffer 00434 // 00435 00436 BufferSize = sizeof(INPUT_RECORD) * (InputInformation->InputBufferSize+1); 00437 TmpInputBuffer = (PINPUT_RECORD)ConsoleHeapAlloc(MAKE_TAG( TMP_TAG ),BufferSize); 00438 if (TmpInputBuffer == NULL) { 00439 return STATUS_NO_MEMORY; 00440 } 00441 TmpInputBufferPtr = TmpInputBuffer; 00442 00443 // 00444 // copy input buffer. 00445 // let ReadBuffer do any compaction work. 00446 // 00447 00448 Status = ReadBuffer(InputInformation, 00449 TmpInputBuffer, 00450 InputInformation->InputBufferSize, 00451 &NumberOfEventsRead, 00452 TRUE, 00453 FALSE, 00454 &Dummy 00455 #if defined(FE_SB) 00456 , 00457 TRUE 00458 #endif 00459 ); 00460 00461 if (!NT_SUCCESS(Status)) { 00462 ConsoleHeapFree(TmpInputBuffer); 00463 return Status; 00464 } 00465 00466 InputInformation->Out = (ULONG_PTR) InputInformation->InputBuffer; 00467 InPtr = InputInformation->InputBuffer; 00468 for (i=0;i<NumberOfEventsRead;i++) { 00469 if (TmpInputBuffer->EventType == KEY_EVENT) { 00470 *InPtr = *TmpInputBuffer; 00471 InPtr++; 00472 } 00473 TmpInputBuffer++; 00474 } 00475 InputInformation->In = (ULONG_PTR) InPtr; 00476 if (InputInformation->In == InputInformation->Out) { 00477 NtClearEvent(InputInformation->InputWaitEvent); 00478 } 00479 ConsoleHeapFree(TmpInputBufferPtr); 00480 } 00481 return STATUS_SUCCESS; 00482 } 00483 00484 NTSTATUS 00485 FlushInputBuffer( 00486 PINPUT_INFORMATION InputInformation 00487 ) 00488 00489 /*++ 00490 00491 Routine Description: 00492 00493 This routine empties the input buffer 00494 00495 Arguments: 00496 00497 InputInformation - Pointer to input buffer information structure. 00498 00499 Return Value: 00500 00501 Note: 00502 00503 The console lock must be held when calling this routine. 00504 00505 --*/ 00506 00507 { 00508 InputInformation->In = (ULONG_PTR) InputInformation->InputBuffer; 00509 InputInformation->Out = (ULONG_PTR) InputInformation->InputBuffer; 00510 NtClearEvent(InputInformation->InputWaitEvent); 00511 return STATUS_SUCCESS; 00512 } 00513 00514 00515 NTSTATUS 00516 SetInputBufferSize( 00517 IN PINPUT_INFORMATION InputInformation, 00518 IN ULONG Size 00519 ) 00520 00521 /*++ 00522 00523 Routine Description: 00524 00525 This routine resizes the input buffer. 00526 00527 Arguments: 00528 00529 InputInformation - Pointer to input buffer information structure. 00530 00531 Size - New size in number of events. 00532 00533 Return Value: 00534 00535 Note: 00536 00537 The console lock must be held when calling this routine. 00538 00539 --*/ 00540 00541 { 00542 ULONG NumberOfEventsRead; 00543 NTSTATUS Status; 00544 PINPUT_RECORD InputBuffer; 00545 ULONG BufferSize; 00546 BOOL Dummy; 00547 00548 #if DBG 00549 ULONG_PTR NumberOfEvents; 00550 if (InputInformation->In < InputInformation->Out) { 00551 NumberOfEvents = InputInformation->Last - InputInformation->Out; 00552 NumberOfEvents += InputInformation->In - InputInformation->First; 00553 } 00554 else { 00555 NumberOfEvents = InputInformation->In - InputInformation->Out; 00556 } 00557 NumberOfEvents /= sizeof(INPUT_RECORD); 00558 #endif 00559 ASSERT( Size > InputInformation->InputBufferSize ); 00560 00561 // 00562 // allocate memory for new input buffer 00563 // 00564 00565 BufferSize = sizeof(INPUT_RECORD) * (Size+1); 00566 InputBuffer = (PINPUT_RECORD)ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ),BufferSize); 00567 if (InputBuffer == NULL) { 00568 return STATUS_NO_MEMORY; 00569 } 00570 00571 // 00572 // copy old input buffer. 00573 // let the ReadBuffer do any compaction work. 00574 // 00575 00576 Status = ReadBuffer(InputInformation, 00577 InputBuffer, 00578 Size, 00579 &NumberOfEventsRead, 00580 TRUE, 00581 FALSE, 00582 &Dummy 00583 #if defined(FE_SB) 00584 , 00585 TRUE 00586 #endif 00587 ); 00588 00589 if (!NT_SUCCESS(Status)) { 00590 ConsoleHeapFree(InputBuffer); 00591 return Status; 00592 } 00593 InputInformation->Out = (ULONG_PTR)InputBuffer; 00594 InputInformation->In = (ULONG_PTR)InputBuffer + sizeof(INPUT_RECORD) * NumberOfEventsRead; 00595 00596 // 00597 // adjust pointers 00598 // 00599 00600 InputInformation->First = (ULONG_PTR) InputBuffer; 00601 InputInformation->Last = (ULONG_PTR) InputBuffer + BufferSize; 00602 00603 // 00604 // free old input buffer 00605 // 00606 00607 ConsoleHeapFree(InputInformation->InputBuffer); 00608 InputInformation->InputBufferSize = Size; 00609 InputInformation->AllocatedBufferSize = BufferSize; 00610 InputInformation->InputBuffer = InputBuffer; 00611 return Status; 00612 } 00613 00614 00615 NTSTATUS 00616 ReadBuffer( 00617 IN PINPUT_INFORMATION InputInformation, 00618 OUT PVOID Buffer, 00619 IN ULONG Length, 00620 OUT PULONG EventsRead, 00621 IN BOOL Peek, 00622 IN BOOL StreamRead, 00623 OUT PBOOL ResetWaitEvent 00624 #ifdef FE_SB 00625 , IN BOOLEAN Unicode 00626 #endif 00627 ) 00628 /*++ 00629 00630 Routine Description: 00631 00632 This routine reads from a buffer. It does the actual circular buffer 00633 manipulation. 00634 00635 Arguments: 00636 00637 InputInformation - buffer to read from 00638 00639 Buffer - buffer to read into 00640 00641 Length - length of buffer in events 00642 00643 EventsRead - where to store number of events read 00644 00645 Peek - if TRUE, don't remove data from buffer, just copy it. 00646 00647 StreamRead - if TRUE, events with repeat counts > 1 are returned 00648 as multiple events. also, EventsRead == 1. 00649 00650 ResetWaitEvent - on exit, TRUE if buffer became empty. 00651 00652 Return Value: 00653 00654 ?? 00655 00656 Note: 00657 00658 The console lock must be held when calling this routine. 00659 00660 --*/ 00661 00662 { 00663 ULONG TransferLength,OldTransferLength; 00664 ULONG BufferLengthInBytes; 00665 #ifdef FE_SB 00666 PCONSOLE_INFORMATION Console; 00667 ULONG Length2; 00668 PINPUT_RECORD BufferRecords; 00669 PINPUT_RECORD QueueRecords; 00670 WCHAR UniChar; 00671 WORD EventType; 00672 #endif 00673 00674 #ifdef FE_SB 00675 Console = InputInformation->Console; 00676 #endif 00677 *ResetWaitEvent = FALSE; 00678 00679 // 00680 // if StreamRead, just return one record. if repeat count is greater 00681 // than one, just decrement it. the repeat count is > 1 if more than 00682 // one event of the same type was merged. we need to expand them back 00683 // to individual events here. 00684 // 00685 00686 if (StreamRead && 00687 ((PINPUT_RECORD)(InputInformation->Out))->EventType == KEY_EVENT) { 00688 00689 ASSERT(Length == 1); 00690 ASSERT(InputInformation->In != InputInformation->Out); 00691 RtlMoveMemory((PBYTE)Buffer, 00692 (PBYTE)InputInformation->Out, 00693 sizeof(INPUT_RECORD) 00694 ); 00695 InputInformation->Out += sizeof(INPUT_RECORD); 00696 if (InputInformation->Last == InputInformation->Out) { 00697 InputInformation->Out = InputInformation->First; 00698 } 00699 if (InputInformation->Out == InputInformation->In) { 00700 *ResetWaitEvent = TRUE; 00701 } 00702 *EventsRead = 1; 00703 return STATUS_SUCCESS; 00704 } 00705 00706 BufferLengthInBytes = Length * sizeof(INPUT_RECORD); 00707 00708 // 00709 // if in > out, buffer looks like this: 00710 // 00711 // out in 00712 // ______ _____________ 00713 // | | | | 00714 // | free | data | free | 00715 // |______|______|______| 00716 // 00717 // we transfer the requested number of events or the amount in the buffer 00718 // 00719 00720 if (InputInformation->In > InputInformation->Out) { 00721 if ((InputInformation->In - InputInformation->Out) > BufferLengthInBytes) { 00722 TransferLength = BufferLengthInBytes; 00723 } 00724 else { 00725 TransferLength = (ULONG)(InputInformation->In - InputInformation->Out); 00726 } 00727 #ifdef FE_SB 00728 if (!Unicode) { 00729 BufferLengthInBytes = 0; 00730 OldTransferLength = TransferLength / sizeof(INPUT_RECORD); 00731 BufferRecords = (PINPUT_RECORD)Buffer; 00732 QueueRecords = (PINPUT_RECORD)InputInformation->Out; 00733 00734 while (BufferLengthInBytes < Length && 00735 OldTransferLength) { 00736 UniChar = QueueRecords->Event.KeyEvent.uChar.UnicodeChar; 00737 EventType = QueueRecords->EventType; 00738 *BufferRecords++ = *QueueRecords++; 00739 if (EventType == KEY_EVENT) { 00740 if (IsConsoleFullWidth(Console->hDC, 00741 Console->CP, 00742 UniChar)) { 00743 BufferLengthInBytes += 2; 00744 } 00745 else { 00746 BufferLengthInBytes++; 00747 } 00748 } 00749 else { 00750 BufferLengthInBytes++; 00751 } 00752 OldTransferLength--; 00753 } 00754 ASSERT(TransferLength >= OldTransferLength * sizeof(INPUT_RECORD)); 00755 TransferLength -= OldTransferLength * sizeof(INPUT_RECORD); 00756 } 00757 else 00758 #endif 00759 { 00760 RtlMoveMemory((PBYTE)Buffer, 00761 (PBYTE)InputInformation->Out, 00762 TransferLength 00763 ); 00764 } 00765 *EventsRead = TransferLength / sizeof(INPUT_RECORD); 00766 #ifdef FE_SB 00767 ASSERT(*EventsRead <= Length); 00768 #endif 00769 if (!Peek) { 00770 InputInformation->Out += TransferLength; 00771 #ifdef FE_SB 00772 ASSERT(InputInformation->Out <= InputInformation->Last); 00773 #endif 00774 } 00775 if (InputInformation->Out == InputInformation->In) { 00776 *ResetWaitEvent = TRUE; 00777 } 00778 return STATUS_SUCCESS; 00779 } 00780 00781 // 00782 // if out > in, buffer looks like this: 00783 // 00784 // in out 00785 // ______ _____________ 00786 // | | | | 00787 // | data | free | data | 00788 // |______|______|______| 00789 // 00790 // we read from the out pointer to the end of the buffer then from the 00791 // beginning of the buffer, until we hit the in pointer or enough bytes 00792 // are read. 00793 // 00794 00795 else { 00796 00797 if ((InputInformation->Last - InputInformation->Out) > BufferLengthInBytes) { 00798 TransferLength = BufferLengthInBytes; 00799 } 00800 else { 00801 TransferLength = (ULONG)(InputInformation->Last - InputInformation->Out); 00802 } 00803 #ifdef FE_SB 00804 if (!Unicode) { 00805 BufferLengthInBytes = 0; 00806 OldTransferLength = TransferLength / sizeof(INPUT_RECORD); 00807 BufferRecords = (PINPUT_RECORD)Buffer; 00808 QueueRecords = (PINPUT_RECORD)InputInformation->Out; 00809 00810 while (BufferLengthInBytes < Length && 00811 OldTransferLength) { 00812 UniChar = QueueRecords->Event.KeyEvent.uChar.UnicodeChar; 00813 EventType = QueueRecords->EventType; 00814 *BufferRecords++ = *QueueRecords++; 00815 if (EventType == KEY_EVENT) { 00816 if (IsConsoleFullWidth(Console->hDC, 00817 Console->CP, 00818 UniChar)) { 00819 BufferLengthInBytes += 2; 00820 } 00821 else { 00822 BufferLengthInBytes++; 00823 } 00824 } 00825 else { 00826 BufferLengthInBytes++; 00827 } 00828 OldTransferLength--; 00829 } 00830 ASSERT(TransferLength >= OldTransferLength * sizeof(INPUT_RECORD)); 00831 TransferLength -= OldTransferLength * sizeof(INPUT_RECORD); 00832 } 00833 else 00834 #endif 00835 { 00836 RtlMoveMemory((PBYTE)Buffer, 00837 (PBYTE)InputInformation->Out, 00838 TransferLength 00839 ); 00840 } 00841 *EventsRead = TransferLength / sizeof(INPUT_RECORD); 00842 #ifdef FE_SB 00843 ASSERT(*EventsRead <= Length); 00844 #endif 00845 00846 if (!Peek) { 00847 InputInformation->Out += TransferLength; 00848 #ifdef FE_SB 00849 ASSERT(InputInformation->Out <= InputInformation->Last); 00850 #endif 00851 if (InputInformation->Out == InputInformation->Last) { 00852 InputInformation->Out = InputInformation->First; 00853 } 00854 } 00855 #ifdef FE_SB 00856 if (!Unicode) { 00857 if (BufferLengthInBytes >= Length) { 00858 if (InputInformation->Out == InputInformation->In) { 00859 *ResetWaitEvent = TRUE; 00860 } 00861 return STATUS_SUCCESS; 00862 } 00863 } 00864 else 00865 #endif 00866 if (*EventsRead == Length) { 00867 if (InputInformation->Out == InputInformation->In) { 00868 *ResetWaitEvent = TRUE; 00869 } 00870 return STATUS_SUCCESS; 00871 } 00872 00873 // 00874 // hit end of buffer, read from beginning 00875 // 00876 00877 OldTransferLength = TransferLength; 00878 #ifdef FE_SB 00879 Length2 = Length; 00880 if (!Unicode) { 00881 ASSERT(Length > BufferLengthInBytes); 00882 Length -= BufferLengthInBytes; 00883 if (Length == 0) { 00884 if (InputInformation->Out == InputInformation->In) { 00885 *ResetWaitEvent = TRUE; 00886 } 00887 return STATUS_SUCCESS; 00888 } 00889 BufferLengthInBytes = Length * sizeof(INPUT_RECORD); 00890 00891 if ((InputInformation->In - InputInformation->First) > BufferLengthInBytes) { 00892 TransferLength = BufferLengthInBytes; 00893 } 00894 else { 00895 TransferLength = (ULONG)(InputInformation->In - InputInformation->First); 00896 } 00897 } 00898 else 00899 #endif 00900 if ((InputInformation->In - InputInformation->First) > (BufferLengthInBytes - OldTransferLength)) { 00901 TransferLength = BufferLengthInBytes - OldTransferLength; 00902 } 00903 else { 00904 TransferLength = (ULONG)(InputInformation->In - InputInformation->First); 00905 } 00906 #ifdef FE_SB 00907 if (!Unicode) { 00908 BufferLengthInBytes = 0; 00909 OldTransferLength = TransferLength / sizeof(INPUT_RECORD); 00910 QueueRecords = (PINPUT_RECORD)InputInformation->First; 00911 00912 while (BufferLengthInBytes < Length && 00913 OldTransferLength) { 00914 UniChar = QueueRecords->Event.KeyEvent.uChar.UnicodeChar; 00915 EventType = QueueRecords->EventType; 00916 *BufferRecords++ = *QueueRecords++; 00917 if (EventType == KEY_EVENT) { 00918 if (IsConsoleFullWidth(Console->hDC, 00919 Console->CP, 00920 UniChar)) { 00921 BufferLengthInBytes += 2; 00922 } 00923 else { 00924 BufferLengthInBytes++; 00925 } 00926 } 00927 else { 00928 BufferLengthInBytes++; 00929 } 00930 OldTransferLength--; 00931 } 00932 ASSERT(TransferLength >= OldTransferLength * sizeof(INPUT_RECORD)); 00933 TransferLength -= OldTransferLength * sizeof(INPUT_RECORD); 00934 } 00935 else 00936 #endif 00937 { 00938 RtlMoveMemory((PBYTE)Buffer+OldTransferLength, 00939 (PBYTE)InputInformation->First, 00940 TransferLength 00941 ); 00942 } 00943 *EventsRead += TransferLength / sizeof(INPUT_RECORD); 00944 #ifdef FE_SB 00945 ASSERT(*EventsRead <= Length2); 00946 #endif 00947 if (!Peek) { 00948 InputInformation->Out = InputInformation->First + TransferLength; 00949 } 00950 if (InputInformation->Out == InputInformation->In) { 00951 *ResetWaitEvent = TRUE; 00952 } 00953 return STATUS_SUCCESS; 00954 } 00955 } 00956 00957 00958 NTSTATUS 00959 ReadInputBuffer( 00960 IN PINPUT_INFORMATION InputInformation, 00961 OUT PINPUT_RECORD lpBuffer, 00962 IN OUT PDWORD nLength, 00963 IN BOOL Peek, 00964 IN BOOL WaitForData, 00965 IN BOOL StreamRead, 00966 IN PCONSOLE_INFORMATION Console, 00967 IN PHANDLE_DATA HandleData OPTIONAL, 00968 IN PCSR_API_MSG Message OPTIONAL, 00969 IN CSR_WAIT_ROUTINE WaitRoutine OPTIONAL, 00970 IN PVOID WaitParameter OPTIONAL, 00971 IN ULONG WaitParameterLength OPTIONAL, 00972 IN BOOLEAN WaitBlockExists OPTIONAL 00973 #if defined(FE_SB) 00974 , 00975 IN BOOLEAN Unicode 00976 #endif 00977 ) 00978 00979 /*++ 00980 00981 Routine Description: 00982 00983 This routine reads from the input buffer. 00984 00985 Arguments: 00986 00987 InputInformation - Pointer to input buffer information structure. 00988 00989 lpBuffer - Buffer to read into. 00990 00991 nLength - On input, number of events to read. On output, number of 00992 events read. 00993 00994 Peek - If TRUE, copy events to lpBuffer but don't remove them from 00995 the input buffer. 00996 00997 WaitForData - if TRUE, wait until an event is input. if FALSE, return 00998 immediately 00999 01000 StreamRead - if TRUE, events with repeat counts > 1 are returned 01001 as multiple events. also, EventsRead == 1. 01002 01003 Console - Pointer to console buffer information. 01004 01005 HandleData - Pointer to handle data structure. This parameter is 01006 optional if WaitForData is false. 01007 01008 Message - if called from dll (not InputThread), points to api 01009 message. this parameter is used for wait block processing. 01010 01011 WaitRoutine - Routine to call when wait is woken up. 01012 01013 WaitParameter - Parameter to pass to wait routine. 01014 01015 WaitParameterLength - Length of wait parameter. 01016 01017 WaitBlockExists - TRUE if wait block has already been created. 01018 01019 Return Value: 01020 01021 Note: 01022 01023 The console lock must be held when calling this routine. 01024 01025 --*/ 01026 01027 { 01028 ULONG EventsRead; 01029 NTSTATUS Status; 01030 BOOL ResetWaitEvent; 01031 01032 if (InputInformation->In == InputInformation->Out) { 01033 if (!WaitForData) { 01034 *nLength = 0; 01035 return STATUS_SUCCESS; 01036 } 01037 LockReadCount(HandleData); 01038 HandleData->InputReadData->ReadCount += 1; 01039 UnlockReadCount(HandleData); 01040 Status = WaitForMoreToRead(InputInformation, 01041 Message, 01042 WaitRoutine, 01043 WaitParameter, 01044 WaitParameterLength, 01045 WaitBlockExists 01046 ); 01047 01048 if (!NT_SUCCESS(Status)) { 01049 if (Status != CONSOLE_STATUS_WAIT) { 01050 /* 01051 * WaitForMoreToRead failed, restore ReadCount and bale out 01052 */ 01053 LockReadCount(HandleData); 01054 HandleData->InputReadData->ReadCount -= 1; 01055 UnlockReadCount(HandleData); 01056 } 01057 *nLength = 0; 01058 return Status; 01059 } 01060 01061 // 01062 // we will only get to this point if we were called by GetInput. 01063 // 01064 ASSERT(FALSE); // I say we never get here ! IANJA 01065 01066 LockConsole(Console); 01067 } 01068 01069 // 01070 // read from buffer 01071 // 01072 01073 Status = ReadBuffer(InputInformation, 01074 lpBuffer, 01075 *nLength, 01076 &EventsRead, 01077 Peek, 01078 StreamRead, 01079 &ResetWaitEvent 01080 #if defined(FE_SB) 01081 , 01082 Unicode 01083 #endif 01084 ); 01085 if (ResetWaitEvent) { 01086 NtClearEvent(InputInformation->InputWaitEvent); 01087 } 01088 01089 *nLength = EventsRead; 01090 return Status; 01091 } 01092 01093 01094 NTSTATUS 01095 WriteBuffer( 01096 OUT PINPUT_INFORMATION InputInformation, 01097 IN PVOID Buffer, 01098 IN ULONG Length, 01099 OUT PULONG EventsWritten, 01100 OUT PBOOL SetWaitEvent 01101 ) 01102 01103 /*++ 01104 01105 Routine Description: 01106 01107 This routine writes to a buffer. It does the actual circular buffer 01108 manipulation. 01109 01110 Arguments: 01111 01112 InputInformation - buffer to write to 01113 01114 Buffer - buffer to write from 01115 01116 Length - length of buffer in events 01117 01118 BytesRead - where to store number of bytes written. 01119 01120 SetWaitEvent - on exit, TRUE if buffer became non-empty. 01121 01122 Return Value: 01123 01124 ERROR_BROKEN_PIPE - no more readers. 01125 01126 Note: 01127 01128 The console lock must be held when calling this routine. 01129 01130 --*/ 01131 01132 { 01133 NTSTATUS Status; 01134 ULONG TransferLength; 01135 ULONG BufferLengthInBytes; 01136 #if defined(FE_SB) 01137 PCONSOLE_INFORMATION Console = InputInformation->Console; 01138 #endif 01139 01140 *SetWaitEvent = FALSE; 01141 01142 // 01143 // windows sends a mouse_move message each time a window is updated. 01144 // coalesce these. 01145 // 01146 01147 if (Length == 1 && InputInformation->Out != InputInformation->In) { 01148 PINPUT_RECORD InputEvent=Buffer; 01149 01150 if (InputEvent->EventType == MOUSE_EVENT && 01151 InputEvent->Event.MouseEvent.dwEventFlags == MOUSE_MOVED) { 01152 PINPUT_RECORD LastInputEvent; 01153 01154 if (InputInformation->In == InputInformation->First) { 01155 LastInputEvent = (PINPUT_RECORD) (InputInformation->Last - sizeof(INPUT_RECORD)); 01156 } 01157 else { 01158 LastInputEvent = (PINPUT_RECORD) (InputInformation->In - sizeof(INPUT_RECORD)); 01159 } 01160 if (LastInputEvent->EventType == MOUSE_EVENT && 01161 LastInputEvent->Event.MouseEvent.dwEventFlags == MOUSE_MOVED) { 01162 LastInputEvent->Event.MouseEvent.dwMousePosition.X = 01163 InputEvent->Event.MouseEvent.dwMousePosition.X; 01164 LastInputEvent->Event.MouseEvent.dwMousePosition.Y = 01165 InputEvent->Event.MouseEvent.dwMousePosition.Y; 01166 *EventsWritten = 1; 01167 return STATUS_SUCCESS; 01168 } 01169 } 01170 else if (InputEvent->EventType == KEY_EVENT && 01171 InputEvent->Event.KeyEvent.bKeyDown) { 01172 PINPUT_RECORD LastInputEvent; 01173 if (InputInformation->In == InputInformation->First) { 01174 LastInputEvent = (PINPUT_RECORD) (InputInformation->Last - sizeof(INPUT_RECORD)); 01175 } 01176 else { 01177 LastInputEvent = (PINPUT_RECORD) (InputInformation->In - sizeof(INPUT_RECORD)); 01178 } 01179 #if defined(FE_SB) 01180 if (IsConsoleFullWidth(Console->hDC, 01181 Console->CP,InputEvent->Event.KeyEvent.uChar.UnicodeChar)) { 01182 ; 01183 } 01184 else 01185 if (InputEvent->Event.KeyEvent.dwControlKeyState & NLS_IME_CONVERSION) { 01186 if (LastInputEvent->EventType == KEY_EVENT && 01187 LastInputEvent->Event.KeyEvent.bKeyDown && 01188 (LastInputEvent->Event.KeyEvent.uChar.UnicodeChar == 01189 InputEvent->Event.KeyEvent.uChar.UnicodeChar) && 01190 (LastInputEvent->Event.KeyEvent.dwControlKeyState == 01191 InputEvent->Event.KeyEvent.dwControlKeyState) ) { 01192 LastInputEvent->Event.KeyEvent.wRepeatCount += 01193 InputEvent->Event.KeyEvent.wRepeatCount; 01194 *EventsWritten = 1; 01195 return STATUS_SUCCESS; 01196 } 01197 } 01198 else 01199 #endif 01200 if (LastInputEvent->EventType == KEY_EVENT && 01201 LastInputEvent->Event.KeyEvent.bKeyDown && 01202 (LastInputEvent->Event.KeyEvent.wVirtualScanCode == // scancode same 01203 InputEvent->Event.KeyEvent.wVirtualScanCode) && 01204 (LastInputEvent->Event.KeyEvent.uChar.UnicodeChar == // character same 01205 InputEvent->Event.KeyEvent.uChar.UnicodeChar) && 01206 (LastInputEvent->Event.KeyEvent.dwControlKeyState == // ctrl/alt/shift state same 01207 InputEvent->Event.KeyEvent.dwControlKeyState) ) { 01208 LastInputEvent->Event.KeyEvent.wRepeatCount += 01209 InputEvent->Event.KeyEvent.wRepeatCount; 01210 *EventsWritten = 1; 01211 return STATUS_SUCCESS; 01212 } 01213 } 01214 } 01215 01216 BufferLengthInBytes = Length*sizeof(INPUT_RECORD); 01217 *EventsWritten = 0; 01218 while (*EventsWritten < Length) { 01219 01220 // 01221 // 01222 // if out > in, buffer looks like this: 01223 // 01224 // in out 01225 // ______ _____________ 01226 // | | | | 01227 // | data | free | data | 01228 // |______|______|______| 01229 // 01230 // we can write from in to out-1 01231 // 01232 01233 if (InputInformation->Out > InputInformation->In) { 01234 TransferLength = BufferLengthInBytes; 01235 if ((InputInformation->Out - InputInformation->In - sizeof(INPUT_RECORD)) 01236 < BufferLengthInBytes) { 01237 Status = SetInputBufferSize(InputInformation, 01238 InputInformation->InputBufferSize+Length+INPUT_BUFFER_SIZE_INCREMENT); 01239 if (!NT_SUCCESS(Status)) { 01240 KdPrint(("CONSRV: Couldn't grow input buffer, Status == %lX\n",Status)); 01241 TransferLength = (ULONG)(InputInformation->Out - InputInformation->In - sizeof(INPUT_RECORD)); 01242 if (TransferLength == 0) { 01243 return Status; 01244 } 01245 } else { 01246 goto OutPath; // after resizing, in > out 01247 } 01248 } 01249 RtlMoveMemory((PBYTE)InputInformation->In, 01250 (PBYTE)Buffer, 01251 TransferLength 01252 ); 01253 Buffer = (PVOID) (((PBYTE) Buffer)+TransferLength); 01254 *EventsWritten += TransferLength/sizeof(INPUT_RECORD); 01255 BufferLengthInBytes -= TransferLength; 01256 InputInformation->In += TransferLength; 01257 } 01258 01259 // 01260 // if in >= out, buffer looks like this: 01261 // 01262 // out in 01263 // ______ _____________ 01264 // | | | | 01265 // | free | data | free | 01266 // |______|______|______| 01267 // 01268 // we write from the in pointer to the end of the buffer then from the 01269 // beginning of the buffer, until we hit the out pointer or enough bytes 01270 // are written. 01271 // 01272 01273 else { 01274 if (InputInformation->Out == InputInformation->In) { 01275 *SetWaitEvent = TRUE; 01276 } 01277 OutPath: 01278 if ((InputInformation->Last - InputInformation->In) > BufferLengthInBytes) { 01279 TransferLength = BufferLengthInBytes; 01280 } 01281 else { 01282 if (InputInformation->First == InputInformation->Out && 01283 InputInformation->In == (InputInformation->Last-sizeof(INPUT_RECORD))) { 01284 TransferLength = BufferLengthInBytes; 01285 Status = SetInputBufferSize(InputInformation, 01286 InputInformation->InputBufferSize+Length+INPUT_BUFFER_SIZE_INCREMENT); 01287 if (!NT_SUCCESS(Status)) { 01288 KdPrint(("CONSRV: Couldn't grow input buffer, Status == %lX\n",Status)); 01289 return Status; 01290 } 01291 } 01292 else { 01293 TransferLength = (ULONG)(InputInformation->Last - InputInformation->In); 01294 if (InputInformation->First == InputInformation->Out) { 01295 TransferLength -= sizeof(INPUT_RECORD); 01296 } 01297 } 01298 } 01299 RtlMoveMemory((PBYTE)InputInformation->In, 01300 (PBYTE)Buffer, 01301 TransferLength 01302 ); 01303 Buffer = (PVOID) (((PBYTE) Buffer)+TransferLength); 01304 *EventsWritten += TransferLength/sizeof(INPUT_RECORD); 01305 BufferLengthInBytes -= TransferLength; 01306 InputInformation->In += TransferLength; 01307 if (InputInformation->In == InputInformation->Last) { 01308 InputInformation->In = InputInformation->First; 01309 } 01310 } 01311 if (TransferLength == 0) { 01312 ASSERT (FALSE); 01313 } 01314 } 01315 return STATUS_SUCCESS; 01316 } 01317 01318 01319 __inline BOOL 01320 IsSystemKey( 01321 WORD wVirtualKeyCode 01322 ) 01323 { 01324 switch (wVirtualKeyCode) { 01325 case VK_SHIFT: 01326 case VK_CONTROL: 01327 case VK_MENU: 01328 case VK_PAUSE: 01329 case VK_CAPITAL: 01330 case VK_LWIN: 01331 case VK_RWIN: 01332 case VK_NUMLOCK: 01333 case VK_SCROLL: 01334 return TRUE; 01335 } 01336 return FALSE; 01337 } 01338 01339 DWORD 01340 PreprocessInput( 01341 IN PCONSOLE_INFORMATION Console, 01342 IN PINPUT_RECORD InputEvent, 01343 IN DWORD nLength 01344 ) 01345 01346 /*++ 01347 01348 Routine Description: 01349 01350 This routine processes special characters in the input stream. 01351 01352 Arguments: 01353 01354 Console - Pointer to console structure. 01355 01356 InputEvent - Buffer to write from. 01357 01358 nLength - Number of events to write. 01359 01360 Return Value: 01361 01362 Number of events to write after special characters have been stripped. 01363 01364 Note: 01365 01366 The console lock must be held when calling this routine. 01367 01368 --*/ 01369 01370 { 01371 ULONG NumEvents; 01372 01373 01374 for (NumEvents = nLength; NumEvents != 0; NumEvents--) { 01375 if (InputEvent->EventType == KEY_EVENT && InputEvent->Event.KeyEvent.bKeyDown) { 01376 // 01377 // if output is suspended, any keyboard input releases it. 01378 // 01379 01380 if ((Console->Flags & CONSOLE_SUSPENDED) && 01381 !IsSystemKey(InputEvent->Event.KeyEvent.wVirtualKeyCode)) { 01382 01383 UnblockWriteConsole(Console, CONSOLE_OUTPUT_SUSPENDED); 01384 RtlMoveMemory(InputEvent, InputEvent + 1, (NumEvents - 1) * sizeof(INPUT_RECORD)); 01385 nLength--; 01386 continue; 01387 } 01388 01389 // 01390 // intercept control-s 01391 // 01392 01393 if ((Console->InputBuffer.InputMode & ENABLE_LINE_INPUT) && 01394 (InputEvent->Event.KeyEvent.wVirtualKeyCode == VK_PAUSE || 01395 IsPauseKey(&InputEvent->Event.KeyEvent))) { 01396 01397 Console->Flags |= CONSOLE_OUTPUT_SUSPENDED; 01398 RtlMoveMemory(InputEvent, InputEvent + 1, (NumEvents - 1) * sizeof(INPUT_RECORD)); 01399 nLength--; 01400 continue; 01401 } 01402 } 01403 InputEvent++; 01404 } 01405 return nLength; 01406 } 01407 01408 01409 DWORD 01410 PrependInputBuffer( 01411 IN PCONSOLE_INFORMATION Console, 01412 IN PINPUT_INFORMATION InputInformation, 01413 IN PINPUT_RECORD lpBuffer, 01414 IN DWORD nLength 01415 ) 01416 01417 /*++ 01418 01419 Routine Description: 01420 01421 This routine writes to the beginning of the input buffer. 01422 01423 Arguments: 01424 01425 InputInformation - Pointer to input buffer information structure. 01426 01427 lpBuffer - Buffer to write from. 01428 01429 nLength - On input, number of events to write. On output, number of 01430 events written. 01431 01432 Return Value: 01433 01434 Note: 01435 01436 The console lock must be held when calling this routine. 01437 01438 --*/ 01439 01440 { 01441 NTSTATUS Status; 01442 ULONG EventsWritten,EventsRead; 01443 BOOL SetWaitEvent; 01444 ULONG NumExistingEvents; 01445 PINPUT_RECORD pExistingEvents; 01446 BOOL Dummy; 01447 01448 nLength = PreprocessInput(Console, lpBuffer, nLength); 01449 if (nLength == 0) { 01450 return 0; 01451 } 01452 01453 Status = GetNumberOfReadyEvents(InputInformation, 01454 &NumExistingEvents 01455 ); 01456 01457 if (NumExistingEvents) { 01458 01459 pExistingEvents = ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ),NumExistingEvents * sizeof(INPUT_RECORD)); 01460 if (pExistingEvents == NULL) 01461 return (DWORD)STATUS_NO_MEMORY; 01462 Status = ReadBuffer(InputInformation, 01463 pExistingEvents, 01464 NumExistingEvents, 01465 &EventsRead, 01466 FALSE, 01467 FALSE, 01468 &Dummy 01469 #if defined(FE_SB) 01470 , 01471 TRUE 01472 #endif 01473 ); 01474 01475 if (!NT_SUCCESS(Status)) { 01476 ConsoleHeapFree(pExistingEvents); 01477 return Status; 01478 } 01479 } else { 01480 pExistingEvents = NULL; 01481 } 01482 01483 // 01484 // write new info to buffer 01485 // 01486 01487 Status = WriteBuffer(InputInformation, 01488 lpBuffer, 01489 nLength, 01490 &EventsWritten, 01491 &SetWaitEvent 01492 ); 01493 01494 // 01495 // write existing info to buffer 01496 // 01497 01498 if (pExistingEvents) { 01499 Status = WriteBuffer(InputInformation, 01500 pExistingEvents, 01501 EventsRead, 01502 &EventsWritten, 01503 &Dummy 01504 ); 01505 ConsoleHeapFree(pExistingEvents); 01506 } 01507 01508 if (SetWaitEvent) { 01509 NtSetEvent(InputInformation->InputWaitEvent,NULL); 01510 } 01511 01512 // 01513 // alert any writers waiting for space 01514 // 01515 01516 WakeUpReadersWaitingForData(Console,InputInformation); 01517 01518 return nLength; 01519 } 01520 01521 DWORD 01522 WriteInputBuffer( 01523 IN PCONSOLE_INFORMATION Console, 01524 IN PINPUT_INFORMATION InputInformation, 01525 IN PINPUT_RECORD lpBuffer, 01526 IN DWORD nLength 01527 ) 01528 01529 /*++ 01530 01531 Routine Description: 01532 01533 This routine writes to the input buffer. 01534 01535 Arguments: 01536 01537 InputInformation - Pointer to input buffer information structure. 01538 01539 lpBuffer - Buffer to write from. 01540 01541 nLength - On input, number of events to write. On output, number of 01542 events written. 01543 01544 Return Value: 01545 01546 Note: 01547 01548 The console lock must be held when calling this routine. 01549 01550 --*/ 01551 01552 { 01553 ULONG EventsWritten; 01554 BOOL SetWaitEvent; 01555 01556 nLength = PreprocessInput(Console, lpBuffer, nLength); 01557 if (nLength == 0) { 01558 return 0; 01559 } 01560 01561 // 01562 // write to buffer 01563 // 01564 01565 WriteBuffer(InputInformation, 01566 lpBuffer, 01567 nLength, 01568 &EventsWritten, 01569 &SetWaitEvent 01570 ); 01571 01572 if (SetWaitEvent) { 01573 NtSetEvent(InputInformation->InputWaitEvent,NULL); 01574 } 01575 01576 // 01577 // alert any writers waiting for space 01578 // 01579 01580 WakeUpReadersWaitingForData(Console,InputInformation); 01581 01582 01583 return EventsWritten; 01584 } 01585 01586 VOID 01587 StoreKeyInfo( 01588 IN PMSG msg 01589 ) 01590 { 01591 int i; 01592 01593 for (i=0;i<CONSOLE_MAX_KEY_INFO;i++) { 01594 if (ConsoleKeyInfo[i].hWnd == CONSOLE_FREE_KEY_INFO || 01595 ConsoleKeyInfo[i].hWnd == msg->hwnd) { 01596 break; 01597 } 01598 } 01599 if (i!=CONSOLE_MAX_KEY_INFO) { 01600 ConsoleKeyInfo[i].hWnd = msg->hwnd; 01601 ConsoleKeyInfo[i].wVirtualKeyCode = LOWORD(msg->wParam); 01602 ConsoleKeyInfo[i].wVirtualScanCode = (BYTE)(HIWORD(msg->lParam)); 01603 } else { 01604 KdPrint(("CONSRV: ConsoleKeyInfo buffer is full\n")); 01605 } 01606 } 01607 01608 VOID 01609 RetrieveKeyInfo( 01610 IN HWND hWnd, 01611 OUT PWORD pwVirtualKeyCode, 01612 OUT PWORD pwVirtualScanCode, 01613 IN BOOL FreeKeyInfo 01614 ) 01615 { 01616 int i; 01617 01618 for (i=0;i<CONSOLE_MAX_KEY_INFO;i++) { 01619 if (ConsoleKeyInfo[i].hWnd == hWnd) { 01620 break; 01621 } 01622 } 01623 if (i!=CONSOLE_MAX_KEY_INFO) { 01624 *pwVirtualKeyCode = ConsoleKeyInfo[i].wVirtualKeyCode; 01625 *pwVirtualScanCode = ConsoleKeyInfo[i].wVirtualScanCode; 01626 if (FreeKeyInfo) 01627 ConsoleKeyInfo[i].hWnd = CONSOLE_FREE_KEY_INFO; 01628 } else { 01629 *pwVirtualKeyCode = (WORD)MapVirtualKey(*pwVirtualScanCode, 3); 01630 } 01631 } 01632 01633 VOID 01634 ClearKeyInfo( 01635 IN HWND hWnd 01636 ) 01637 { 01638 int i; 01639 01640 for (i=0;i<CONSOLE_MAX_KEY_INFO;i++) { 01641 if (ConsoleKeyInfo[i].hWnd == hWnd) { 01642 ConsoleKeyInfo[i].hWnd = CONSOLE_FREE_KEY_INFO; 01643 } 01644 } 01645 } 01646 01647 01648 /***************************************************************************\ 01649 * ProcessCreateConsoleWindow 01650 * 01651 * This routine processes a CM_CREATE_CONSOLE_WINDOW message. It is called 01652 * from the InputThread message loop under normal circumstances and from 01653 * the DialogHookProc if we have a dialog box up. The USER critical section 01654 * should not be held when calling this routine. 01655 \***************************************************************************/ 01656 VOID 01657 ProcessCreateConsoleWindow( 01658 IN LPMSG lpMsg 01659 ) 01660 { 01661 NTSTATUS Status; 01662 // make sure this is a valid message 01663 PCONSOLE_INFORMATION pConsole; 01664 01665 if (NT_SUCCESS(RevalidateConsole((HANDLE)lpMsg->wParam, &pConsole))) { 01666 01667 // 01668 // Make sure the console doesn't already have a window. 01669 // 01670 01671 if (pConsole->hWnd) { 01672 RIPMSG1(RIP_WARNING, "Console %#p already has a window", pConsole); 01673 UnlockConsole(pConsole); 01674 return; 01675 } 01676 01677 pConsole->InputThreadInfo = TlsGetValue(InputThreadTlsIndex); 01678 DBGPRINT(("Before CreateWindowsWindow cWindows = %d\n", 01679 pConsole->InputThreadInfo->WindowCount)); 01680 01681 Status = CreateWindowsWindow(pConsole); 01682 DBGPRINT(("After CreateWindowsWindow cWindows = %d\n", 01683 pConsole->InputThreadInfo->WindowCount)); 01684 switch (Status) { 01685 case STATUS_SUCCESS: 01686 01687 // 01688 // If we changed the screen buffer size, let the user know about it 01689 // with a message box. Make sure we don't recurse too deeply in 01690 // this code by limiting the number of message boxes on the screen 01691 // at once. If there are already a bunch up there, the user should 01692 // have the idea by now anyway. 01693 // 01694 01695 if ((pConsole->Flags & CONSOLE_DEFAULT_BUFFER_SIZE) && (DialogBoxCount < 8)) { 01696 WCHAR ItemString[120]; 01697 WCHAR Title[120]; 01698 HWND hWnd = pConsole->hWnd; 01699 ULONG TitleLength = min(sizeof(Title)-sizeof(WCHAR), pConsole->TitleLength); 01700 RtlCopyMemory(Title, pConsole->Title, TitleLength); 01701 Title[TitleLength/sizeof(WCHAR)] = 0; 01702 UnlockConsole(pConsole); 01703 LoadString(ghInstance,msgBufferTooBig,ItemString,NELEM(ItemString)); 01704 DialogBoxCount++; 01705 MessageBox(hWnd, ItemString, Title, MB_OK); 01706 DialogBoxCount--; 01707 break; 01708 } 01709 // FALL THRU 01710 case STATUS_NO_MEMORY: 01711 UnlockConsole(pConsole); 01712 break; 01713 case STATUS_INVALID_HANDLE: 01714 // Console is gone, don't do anything. 01715 break; 01716 default: 01717 KdPrint(("CONSRV: CreateWindowsWindow returned %x\n", Status)); 01718 ASSERT(FALSE); 01719 break; 01720 } 01721 } 01722 } 01723 01724 01725 LRESULT 01726 DialogHookProc( 01727 int nCode, 01728 WPARAM wParam, 01729 LPARAM lParam 01730 ) 01731 01732 // this routine gets called to filter input to console dialogs so 01733 // that we can do the special processing that StoreKeyInfo does. 01734 01735 { 01736 MSG *pmsg = (PMSG)lParam; 01737 01738 UNREFERENCED_PARAMETER(wParam); 01739 01740 if (pmsg->message == CM_CREATE_CONSOLE_WINDOW) { 01741 ProcessCreateConsoleWindow(pmsg); 01742 return TRUE; 01743 } 01744 01745 if (CONSOLE_IS_IME_ENABLED()) { 01746 if (pmsg->message == CM_CONSOLE_INPUT_THREAD_MSG) { 01747 PINPUT_THREAD_INFO pThreadInfo = TlsGetValue(InputThreadTlsIndex); 01748 MSG msg; 01749 01750 ASSERT(pThreadInfo); 01751 01752 if (UnqueueThreadMessage(pThreadInfo->ThreadId, &msg.message, &msg.wParam, &msg.lParam)) { 01753 RIPMSG3(RIP_WARNING, "DialogHookProc: %04x (%08x, %08x)", msg.message, msg.wParam, msg.lParam); 01754 switch (msg.message) { 01755 case CM_CONIME_CREATE: 01756 ProcessCreateConsoleIME(&msg, pThreadInfo->ThreadId); 01757 return TRUE; 01758 case CM_WAIT_CONIME_PROCESS: 01759 WaitConsoleIMEStuff((HDESK)msg.wParam, (HANDLE)msg.lParam); 01760 return TRUE; 01761 case CM_SET_CONSOLEIME_WINDOW: 01762 pThreadInfo->hWndConsoleIME = (HWND)msg.wParam; 01763 return TRUE; 01764 default: 01765 RIPMSG1(RIP_WARNING, "DialogHookProc: invalid thread message(%04x) !!", msg.message); 01766 break; 01767 } 01768 } 01769 else { 01770 RIPMSG0(RIP_WARNING, "DialogHookProc: bogus thread message is posted. ignored"); 01771 } 01772 } 01773 } 01774 01775 if (nCode == MSGF_DIALOGBOX) { 01776 if (pmsg->message >= WM_KEYFIRST && 01777 pmsg->message <= WM_KEYLAST) { 01778 if (pmsg->message != WM_CHAR && 01779 pmsg->message != WM_DEADCHAR && 01780 pmsg->message != WM_SYSCHAR && 01781 pmsg->message != WM_SYSDEADCHAR) { 01782 01783 // don't store key info if dialog box input 01784 if (GetWindowLongPtr(pmsg->hwnd, GWLP_HWNDPARENT) == 0) { 01785 StoreKeyInfo(pmsg); 01786 } 01787 } 01788 } 01789 } 01790 return 0; 01791 } 01792 01793 #undef DbgPrint // Need this to build on free systems 01794 01795 ULONG InputExceptionFilter( 01796 PEXCEPTION_POINTERS pexi) 01797 { 01798 NTSTATUS Status; 01799 SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInfo; 01800 01801 if (pexi->ExceptionRecord->ExceptionCode != STATUS_PORT_DISCONNECTED) { 01802 Status = NtQuerySystemInformation( SystemKernelDebuggerInformation, 01803 &KernelDebuggerInfo, 01804 sizeof(KernelDebuggerInfo), 01805 NULL 01806 ); 01807 01808 if (NT_SUCCESS(Status) && KernelDebuggerInfo.KernelDebuggerEnabled) { 01809 DbgPrint("Unhandled Exception hit in csrss.exe InputExceptionFilter\n"); 01810 DbgPrint("first, enter !exr %p for the exception record\n", pexi->ExceptionRecord); 01811 DbgPrint("next, enter !cxr %p for the context\n", pexi->ContextRecord); 01812 DbgPrint("then !kb to get the faulting stack\n"); 01813 DbgBreakPoint(); 01814 } 01815 } 01816 01817 return EXCEPTION_EXECUTE_HANDLER; 01818 } 01819 01821 // Input Thread internal Message Queue: 01822 // Mainly used for Console IME stuff 01824 01825 LIST_ENTRY gInputThreadMsg; 01826 CRITICAL_SECTION gInputThreadMsgLock; 01827 01828 VOID 01829 InitializeThreadMessages() 01830 { 01831 RtlEnterCriticalSection(&gInputThreadMsgLock); 01832 InitializeListHead(&gInputThreadMsg); 01833 RtlLeaveCriticalSection(&gInputThreadMsgLock); 01834 } 01835 01836 VOID 01837 CleanupInputThreadMessages( 01838 DWORD dwThreadId) 01839 { 01840 UINT message; 01841 WPARAM wParam; 01842 LPARAM lParam; 01843 01844 ASSERT(dwThreadId); 01845 01846 while (UnqueueThreadMessage(dwThreadId, &message, &wParam, &lParam)) { 01847 RIPMSG3(RIP_WARNING, "CleanupInputThreadMessages: %04x (%08x, %08x)", message, wParam, lParam); 01848 } 01849 } 01850 01851 // 01852 // QueueThreadMessage 01853 // 01854 // Posts a message to Input Thread, specified by dwThreadId. 01855 // CM_CONSOLE_INPUT_THEAD_MSG is used as a stub message. Actual parameters are 01856 // stored in gInputThreadMsg. Input thread should call UnqueueThreadMessage 01857 // when it gets CM_CONSOLE_INPUT_THREAD_MSG. 01858 // 01859 NTSTATUS 01860 QueueThreadMessage( 01861 DWORD dwThreadId, 01862 UINT message, 01863 WPARAM wParam, 01864 LPARAM lParam) 01865 { 01866 PCONSOLE_THREAD_MSG pConMsg; 01867 01868 // NOTE HIROYAMA: change this to RIP_VERBOSE 01869 RIPMSG4(RIP_VERBOSE, "QueueThreadMessage: TID=%08x msg:%04x (%08x, %08x)", 01870 dwThreadId, message, wParam, lParam); 01871 01872 pConMsg = ConsoleHeapAlloc(MAKE_TAG(TMP_TAG), sizeof *pConMsg); 01873 if (pConMsg == NULL) { 01874 RIPMSG0(RIP_WARNING, "QueueThreadMessage: failed to allocate pConMsg"); 01875 return STATUS_NO_MEMORY; 01876 } 01877 01878 pConMsg->dwThreadId = dwThreadId; 01879 pConMsg->Message = message; 01880 pConMsg->wParam = wParam; 01881 pConMsg->lParam = lParam; 01882 01883 RtlEnterCriticalSection(&gInputThreadMsgLock); 01884 InsertHeadList(&gInputThreadMsg, &pConMsg->ListLink); 01885 RtlLeaveCriticalSection(&gInputThreadMsgLock); 01886 01887 if (!PostThreadMessage(dwThreadId, CM_CONSOLE_INPUT_THREAD_MSG, 0, 0)) { 01888 RIPMSG1(RIP_WARNING, "QueueThreadMessage: failed to post thread msg(%04x)", message); 01889 RtlEnterCriticalSection(&gInputThreadMsgLock); 01890 RemoveEntryList(&pConMsg->ListLink); 01891 RtlLeaveCriticalSection(&gInputThreadMsgLock); 01892 ConsoleHeapFree(pConMsg); 01893 return STATUS_UNSUCCESSFUL; 01894 } 01895 01896 return STATUS_SUCCESS; 01897 } 01898 01899 // 01900 // UnqueueThreadMessage 01901 // 01902 // return value: 01903 // TRUE -- a message found. 01904 // FALSE -- no message for dwThreadId found. 01905 // 01906 BOOL UnqueueThreadMessage( 01907 DWORD dwThreadId, 01908 UINT* pMessage, 01909 WPARAM* pwParam, 01910 LPARAM* plParam) 01911 { 01912 BOOL fResult = FALSE; // if message is found, set this to TRUE 01913 PLIST_ENTRY pEntry; 01914 01915 ASSERT(dwThreadId); 01916 01917 RtlEnterCriticalSection(&gInputThreadMsgLock); 01918 01919 // 01920 // Search for dwThreadId message from the tail of the queue. 01921 // 01922 pEntry = gInputThreadMsg.Blink; 01923 01924 while (pEntry != &gInputThreadMsg) { 01925 PCONSOLE_THREAD_MSG pConMsg = CONTAINING_RECORD(pEntry, CONSOLE_THREAD_MSG, ListLink); 01926 01927 if (pConMsg->dwThreadId == dwThreadId) { 01928 *pMessage = pConMsg->Message; 01929 *pwParam = pConMsg->wParam; 01930 *plParam = pConMsg->lParam; 01931 01932 RemoveEntryList(pEntry); 01933 ConsoleHeapFree(pConMsg); 01934 fResult = TRUE; 01935 break; 01936 } 01937 pEntry = pEntry->Blink; 01938 } 01939 01940 RtlLeaveCriticalSection(&gInputThreadMsgLock); 01941 01942 return fResult; 01943 } 01944 01945 VOID 01946 ConsoleInputThread( 01947 PINPUT_THREAD_INIT_INFO pInputThreadInitInfo) 01948 { 01949 MSG msg; 01950 PTEB Teb; 01951 PCSR_THREAD pcsrt = NULL; 01952 INPUT_THREAD_INFO ThreadInfo; 01953 int i; 01954 HANDLE hThread = NULL; 01955 HHOOK hhook = NULL; 01956 BOOL fQuit = FALSE; 01957 CONSOLEDESKTOPCONSOLETHREAD ConsoleDesktopInfo; 01958 NTSTATUS Status; 01959 01960 // 01961 // Initialize GDI accelerators. 01962 // 01963 01964 Teb = NtCurrentTeb(); 01965 01966 try { 01967 01968 /* 01969 * Set this thread's desktop to the one we just created/opened. 01970 * When the very first app is loaded, the desktop hasn't been 01971 * created yet so the above call might fail. Make sure we don't 01972 * accidentally call SetThreadDesktop with a NULL pdesk. The 01973 * first app will create the desktop and open it for itself. 01974 */ 01975 ThreadInfo.Desktop = pInputThreadInitInfo->DesktopHandle; 01976 ThreadInfo.WindowCount = 0; 01977 ThreadInfo.ThreadHandle = pInputThreadInitInfo->ThreadHandle; 01978 ThreadInfo.ThreadId = HandleToUlong(Teb->ClientId.UniqueThread); 01979 #if defined(FE_IME) 01980 ThreadInfo.hWndConsoleIME = NULL; 01981 #endif 01982 TlsSetValue(InputThreadTlsIndex, &ThreadInfo); 01983 ConsoleDesktopInfo.hdesk = pInputThreadInitInfo->DesktopHandle; 01984 ConsoleDesktopInfo.dwThreadId = HandleToUlong(Teb->ClientId.UniqueThread); 01985 Status = NtUserConsoleControl(ConsoleDesktopConsoleThread, &ConsoleDesktopInfo, 01986 sizeof(ConsoleDesktopInfo)); 01987 if (NT_SUCCESS(Status)) { 01988 01989 // 01990 // This call forces the client-side desktop information 01991 // to be updated. 01992 // 01993 01994 pcsrt = CsrConnectToUser(); 01995 if (pcsrt == NULL || 01996 !SetThreadDesktop(pInputThreadInitInfo->DesktopHandle)) { 01997 Status = STATUS_UNSUCCESSFUL; 01998 } else { 01999 02000 // 02001 // Save our thread handle for cleanup purposes 02002 // 02003 02004 hThread = pcsrt->ThreadHandle; 02005 02006 if (!fOneTimeInitialized) { 02007 02008 InitializeCustomCP(); 02009 02010 // 02011 // Initialize default screen dimensions. we have to initialize 02012 // the font info here (in the input thread) so that GDI doesn't 02013 // get completely confused on process termination (since a 02014 // process that looks like it's terminating created all the 02015 // server HFONTS). 02016 // 02017 02018 EnumerateFonts(EF_DEFFACE); 02019 02020 InitializeScreenInfo(); 02021 02022 if (!InitWindowClass()) 02023 Status = STATUS_UNSUCCESSFUL; 02024 02025 for (i=0;i<CONSOLE_MAX_KEY_INFO;i++) { 02026 ConsoleKeyInfo[i].hWnd = CONSOLE_FREE_KEY_INFO; 02027 } 02028 02029 ProgmanHandleMessage = RegisterWindowMessage(TEXT(CONSOLE_PROGMAN_HANDLE_MESSAGE)); 02030 } 02031 } 02032 } 02033 02034 // 02035 // If we successfully initialized, the input thread is ready to run. 02036 // Otherwise, kill the thread. 02037 // 02038 02039 pInputThreadInitInfo->InitStatus = Status; 02040 NtSetEvent(pInputThreadInitInfo->InitCompleteEventHandle, NULL); 02041 02042 if (!NT_SUCCESS(Status)) 02043 RtlRaiseStatus(STATUS_PORT_DISCONNECTED); 02044 02045 hhook = SetWindowsHookEx(WH_MSGFILTER, DialogHookProc, NULL, 02046 HandleToUlong(Teb->ClientId.UniqueThread)); 02047 02048 while (TRUE) { 02049 02050 // 02051 // If a WM_QUIT has been received and all windows 02052 // are gone, get out. 02053 // 02054 02055 if (fQuit && ThreadInfo.WindowCount == 0) 02056 break; 02057 02058 // 02059 // Make sure we don't hold any locks while we're idle. 02060 // 02061 02062 ASSERT(NtCurrentTeb()->CountOfOwnedCriticalSections == 0); 02063 02064 GetMessage(&msg, NULL, 0, 0); 02065 02066 // 02067 // Trap messages posted to the thread. 02068 // 02069 02070 if (msg.message == CM_CREATE_CONSOLE_WINDOW) { 02071 ProcessCreateConsoleWindow(&msg); 02072 continue; 02073 } else if (msg.message == WM_QUIT) { 02074 02075 // 02076 // The message was posted from ExitWindows. This 02077 // means that it's OK to terminate the thread. 02078 // 02079 02080 fQuit = TRUE; 02081 02082 // 02083 // Only exit the loop if there are no windows, 02084 // 02085 02086 if (ThreadInfo.WindowCount == 0) { 02087 break; 02088 } 02089 KdPrint(("WM_QUIT received by console with windows\n")); 02090 continue; 02091 } 02092 else if (CONSOLE_IS_IME_ENABLED()) { 02093 if (msg.message == CM_CONSOLE_INPUT_THREAD_MSG) { 02094 MSG msg; 02095 02096 if (UnqueueThreadMessage(ThreadInfo.ThreadId, &msg.message, &msg.wParam, &msg.lParam)) { 02097 // NOTE HIROYAMA: change this to RIP_VERBOSE 02098 RIPMSG3(RIP_VERBOSE, "InputThread: Unqueue: msg=%04x (%08x, %08x)", 02099 msg.message, msg.wParam, msg.lParam); 02100 switch (msg.message) { 02101 case CM_CONIME_CREATE: 02102 ProcessCreateConsoleIME(&msg, ThreadInfo.ThreadId); 02103 continue; 02104 case CM_WAIT_CONIME_PROCESS: 02105 WaitConsoleIMEStuff((HDESK)msg.wParam, (HANDLE)msg.lParam); 02106 continue; 02107 case CM_SET_CONSOLEIME_WINDOW: 02108 ThreadInfo.hWndConsoleIME = (HWND)msg.wParam; 02109 continue; 02110 default: 02111 RIPMSG1(RIP_WARNING, "ConsoleInputThread: invalid thread message(%04x) !!", msg.message); 02112 break; 02113 } 02114 } 02115 else { 02116 RIPMSG0(RIP_WARNING, "ConsoleInputThread: bogus thread message is post. ignored"); 02117 continue; 02118 } 02119 } 02120 } 02121 02122 if (!TranslateMessageEx(&msg, TM_POSTCHARBREAKS)) { 02123 DispatchMessage(&msg); 02124 } else { 02125 // do this so that alt-tab works while journalling 02126 if (msg.message == WM_SYSKEYDOWN && 02127 msg.wParam == VK_TAB && 02128 (msg.lParam & 0x20000000) ) { // alt is really down 02129 DispatchMessage(&msg); 02130 } else { 02131 StoreKeyInfo(&msg); 02132 } 02133 } 02134 } 02135 02136 // 02137 // Cleanup the input thread messages 02138 // 02139 CleanupInputThreadMessages(ThreadInfo.ThreadId); 02140 02141 RtlRaiseStatus(STATUS_PORT_DISCONNECTED); 02142 02143 } except (InputExceptionFilter(GetExceptionInformation())) { 02144 BOOL fSuccess; 02145 02146 // 02147 // Free all resources used by this thread 02148 // 02149 02150 if (hhook != NULL) 02151 UnhookWindowsHookEx(hhook); 02152 ConsoleDesktopInfo.dwThreadId = 0; 02153 NtUserConsoleControl(ConsoleDesktopConsoleThread, 02154 &ConsoleDesktopInfo, sizeof(ConsoleDesktopInfo)); 02155 02156 // 02157 // Close the desktop handle. CSR is special cased to close 02158 // the handle even if the thread has windows. The desktop 02159 // remains assigned to the thread. 02160 // 02161 02162 fSuccess = CloseDesktop(ThreadInfo.Desktop); 02163 ASSERT(fSuccess); 02164 02165 // 02166 // Restore thread handle so that CSR won't get confused. 02167 // 02168 02169 if (hThread != NULL) 02170 pcsrt->ThreadHandle = hThread; 02171 } 02172 02173 if (pcsrt != NULL) 02174 CsrDereferenceThread(pcsrt); 02175 UserExitWorkerThread(); 02176 } 02177 02178 ULONG 02179 GetControlKeyState( 02180 LPARAM lParam 02181 ) 02182 { 02183 ULONG ControlKeyState=0; 02184 02185 if (GetKeyState(VK_LMENU) & KEY_PRESSED) { 02186 ControlKeyState |= LEFT_ALT_PRESSED; 02187 } 02188 if (GetKeyState(VK_RMENU) & KEY_PRESSED) { 02189 ControlKeyState |= RIGHT_ALT_PRESSED; 02190 } 02191 if (GetKeyState(VK_LCONTROL) & KEY_PRESSED) { 02192 ControlKeyState |= LEFT_CTRL_PRESSED; 02193 } 02194 if (GetKeyState(VK_RCONTROL) & KEY_PRESSED) { 02195 ControlKeyState |= RIGHT_CTRL_PRESSED; 02196 } 02197 if (GetKeyState(VK_SHIFT) & KEY_PRESSED) { 02198 ControlKeyState |= SHIFT_PRESSED; 02199 } 02200 if (GetKeyState(VK_NUMLOCK) & KEY_TOGGLED) { 02201 ControlKeyState |= NUMLOCK_ON; 02202 } 02203 if (GetKeyState(VK_OEM_SCROLL) & KEY_TOGGLED) { 02204 ControlKeyState |= SCROLLLOCK_ON; 02205 } 02206 if (GetKeyState(VK_CAPITAL) & KEY_TOGGLED) { 02207 ControlKeyState |= CAPSLOCK_ON; 02208 } 02209 if (lParam & KEY_ENHANCED) { 02210 ControlKeyState |= ENHANCED_KEY; 02211 } 02212 ControlKeyState |= (lParam & ALTNUMPAD_BIT); 02213 return ControlKeyState; 02214 } 02215 02216 ULONG 02217 ConvertMouseButtonState( 02218 IN ULONG Flag, 02219 IN ULONG State 02220 ) 02221 { 02222 if (State & MK_LBUTTON) { 02223 Flag |= FROM_LEFT_1ST_BUTTON_PRESSED; 02224 } 02225 if (State & MK_MBUTTON) { 02226 Flag |= FROM_LEFT_2ND_BUTTON_PRESSED; 02227 } 02228 if (State & MK_RBUTTON) { 02229 Flag |= RIGHTMOST_BUTTON_PRESSED; 02230 } 02231 return Flag; 02232 } 02233 02234 VOID 02235 TerminateRead( 02236 IN PCONSOLE_INFORMATION Console, 02237 IN PINPUT_INFORMATION InputInfo, 02238 IN DWORD Flag 02239 ) 02240 02241 /*++ 02242 02243 Routine Description: 02244 02245 This routine wakes up any readers waiting for data when a ctrl-c 02246 or ctrl-break is input. 02247 02248 Arguments: 02249 02250 InputInfo - pointer to input buffer 02251 02252 Flag - flag indicating whether ctrl-break or ctrl-c was input 02253 02254 --*/ 02255 02256 { 02257 BOOLEAN WaitSatisfied; 02258 WaitSatisfied = CsrNotifyWait(&InputInfo->ReadWaitQueue, 02259 TRUE, 02260 NULL, 02261 (PVOID)Flag 02262 ); 02263 if (WaitSatisfied) { 02264 // #334370 under stress, WaitQueue may already hold the satisfied waits 02265 ASSERT ((Console->WaitQueue == NULL) || 02266 (Console->WaitQueue == &InputInfo->ReadWaitQueue)); 02267 Console->WaitQueue = &InputInfo->ReadWaitQueue; 02268 } 02269 } 02270 02271 BOOL 02272 HandleSysKeyEvent( 02273 IN PCONSOLE_INFORMATION Console, 02274 IN HWND hWnd, 02275 IN UINT Message, 02276 IN WPARAM wParam, 02277 IN LPARAM lParam 02278 ) 02279 02280 /* 02281 02282 returns TRUE if DefWindowProc should be called. 02283 02284 */ 02285 02286 { 02287 WORD VirtualKeyCode; 02288 BOOL bCtrlDown; 02289 02290 #if defined (FE_IME) 02291 // Sep.16.1995 Support Console IME by v-HirShi(Hirotoshi Shimizu) 02292 if (Message == WM_SYSCHAR || Message == WM_SYSDEADCHAR || 02293 Message == WM_SYSCHAR+CONIME_KEYDATA || Message == WM_SYSDEADCHAR+CONIME_KEYDATA) 02294 #else 02295 if (Message == WM_SYSCHAR || Message == WM_SYSDEADCHAR) 02296 #endif 02297 { 02298 VirtualKeyCode = (WORD)MapVirtualKey(LOBYTE(HIWORD(lParam)), 1); 02299 } else { 02300 VirtualKeyCode = LOWORD(wParam); 02301 } 02302 02303 // 02304 // check for ctrl-esc 02305 // 02306 bCtrlDown = GetKeyState(VK_CONTROL) & KEY_PRESSED; 02307 02308 if (VirtualKeyCode == VK_ESCAPE && 02309 bCtrlDown && 02310 !(GetKeyState(VK_MENU) & KEY_PRESSED) && 02311 !(GetKeyState(VK_SHIFT) & KEY_PRESSED) && 02312 !(Console->ReserveKeys & CONSOLE_CTRLESC) ) { 02313 return TRUE; // call DefWindowProc 02314 } 02315 02316 if ((lParam & 0x20000000) == 0) { // we're iconic 02317 02318 02319 // 02320 // Check for ENTER while ICONic (Restore accelerator) 02321 // 02322 02323 if (VirtualKeyCode == VK_RETURN && !(Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE)) { 02324 02325 return TRUE; // call DefWindowProc 02326 } else { 02327 HandleKeyEvent(Console, 02328 hWnd, 02329 Message, 02330 wParam, 02331 lParam 02332 ); 02333 return FALSE; 02334 } 02335 } 02336 02337 if (VirtualKeyCode == VK_RETURN && !bCtrlDown && 02338 !(Console->ReserveKeys & CONSOLE_ALTENTER)) { 02339 #ifdef i386 02340 if (!(Message & KEY_UP_TRANSITION)) { 02341 if (FullScreenInitialized) { 02342 if (Console->FullScreenFlags == 0) { 02343 ConvertToFullScreen(Console); 02344 Console->FullScreenFlags = CONSOLE_FULLSCREEN; 02345 02346 ChangeDispSettings(Console, Console->hWnd,CDS_FULLSCREEN); 02347 } else { 02348 ConvertToWindowed(Console); 02349 Console->FullScreenFlags &= ~CONSOLE_FULLSCREEN; 02350 02351 ChangeDispSettings(Console, Console->hWnd,0); 02352 02353 ShowWindow(Console->hWnd, SW_RESTORE); 02354 } 02355 } else { 02356 WCHAR ItemString[70]; 02357 LoadString(ghInstance,msgNoFullScreen,ItemString,70); 02358 MessageBoxEx(Console->hWnd, 02359 ItemString, 02360 Console->Title, 02361 MB_SYSTEMMODAL | MB_OK, 02362 0L 02363 ); 02364 } 02365 } 02366 #endif 02367 return FALSE; 02368 } 02369 02370 // 02371 // make sure alt-space gets translated so that the system 02372 // menu is displayed. 02373 // 02374 02375 if (!(GetKeyState(VK_CONTROL) & KEY_PRESSED)) { 02376 if (VirtualKeyCode == VK_SPACE && !(Console->ReserveKeys & CONSOLE_ALTSPACE)) { 02377 return TRUE; // call DefWindowProc 02378 } 02379 02380 if (VirtualKeyCode == VK_ESCAPE && !(Console->ReserveKeys & CONSOLE_ALTESC)) { 02381 return TRUE; // call DefWindowProc 02382 } 02383 if (VirtualKeyCode == VK_TAB && !(Console->ReserveKeys & CONSOLE_ALTTAB)) { 02384 return TRUE; // call DefWindowProc 02385 } 02386 } 02387 HandleKeyEvent(Console, 02388 hWnd, 02389 Message, 02390 wParam, 02391 lParam 02392 ); 02393 return FALSE; 02394 } 02395 02396 VOID 02397 HandleKeyEvent( 02398 IN PCONSOLE_INFORMATION Console, 02399 IN HWND hWnd, 02400 IN UINT Message, 02401 IN WPARAM wParam, 02402 IN LPARAM lParam 02403 ) 02404 { 02405 INPUT_RECORD InputEvent; 02406 BOOLEAN ContinueProcessing; 02407 ULONG EventsWritten; 02408 WORD VirtualKeyCode; 02409 ULONG ControlKeyState; 02410 BOOL bKeyDown; 02411 BOOL bGenerateBreak=FALSE; 02412 #ifdef FE_SB 02413 BOOL KeyMessageFromConsoleIME; 02414 #endif 02415 02416 #ifdef FE_SB 02417 // v-HirShi Sep.21.1995 For Console IME 02418 if ((WM_KEYFIRST+CONIME_KEYDATA) <= Message && Message <= (WM_KEYLAST+CONIME_KEYDATA)) { 02419 Message -= CONIME_KEYDATA ; 02420 KeyMessageFromConsoleIME = TRUE ; 02421 } 02422 else { 02423 KeyMessageFromConsoleIME = FALSE ; 02424 } 02425 #endif 02426 /* 02427 * BOGUS for WM_CHAR/WM_DEADCHAR, in which LOWORD(lParam) is a character 02428 */ 02429 VirtualKeyCode = LOWORD(wParam); 02430 ControlKeyState = GetControlKeyState(lParam); 02431 bKeyDown = !(lParam & KEY_TRANSITION_UP); 02432 02433 // 02434 // Make sure we retrieve the key info first, or we could chew up 02435 // unneeded space in the key info table if we bail out early. 02436 // 02437 02438 InputEvent.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode; 02439 InputEvent.Event.KeyEvent.wVirtualScanCode = (BYTE)(HIWORD(lParam)); 02440 if (Message == WM_CHAR || Message == WM_SYSCHAR || 02441 Message == WM_DEADCHAR || Message == WM_SYSDEADCHAR) { 02442 RetrieveKeyInfo(hWnd, 02443 &InputEvent.Event.KeyEvent.wVirtualKeyCode, 02444 &InputEvent.Event.KeyEvent.wVirtualScanCode, 02445 !(Console->InputBuffer.ImeMode.Open ^ KeyMessageFromConsoleIME)); 02446 VirtualKeyCode = InputEvent.Event.KeyEvent.wVirtualKeyCode; 02447 } 02448 02449 // 02450 // If this is a key up message, should we ignore it? We do this 02451 // so that if a process reads a line from the input buffer, the 02452 // key up event won't get put in the buffer after the read 02453 // completes. 02454 // 02455 02456 if (Console->Flags & CONSOLE_IGNORE_NEXT_KEYUP) { 02457 Console->Flags &= ~CONSOLE_IGNORE_NEXT_KEYUP; 02458 if (!bKeyDown) 02459 return; 02460 } 02461 02462 #ifdef FE_SB 02463 // v-HirShi Sep.21.1995 For Console IME 02464 if (KeyMessageFromConsoleIME) { 02465 goto FromConsoleIME ; 02466 } 02467 #endif 02468 02469 if (Console->Flags & CONSOLE_SELECTING) { 02470 02471 if (!bKeyDown) { 02472 return; 02473 } 02474 02475 // 02476 // if escape or ctrl-c, cancel selection 02477 // 02478 02479 if (!(Console->SelectionFlags & CONSOLE_MOUSE_DOWN) ) { 02480 if (VirtualKeyCode == VK_ESCAPE || 02481 (VirtualKeyCode == 'C' && 02482 (GetKeyState(VK_CONTROL) & KEY_PRESSED) )) { 02483 ClearSelection(Console); 02484 return; 02485 } else if (VirtualKeyCode == VK_RETURN) { 02486 02487 // if return, copy selection 02488 02489 DoCopy(Console); 02490 return; 02491 } 02492 } 02493 if (!(Console->SelectionFlags & CONSOLE_MOUSE_SELECTION)) { 02494 if ((Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) && 02495 (VirtualKeyCode == VK_RIGHT || 02496 VirtualKeyCode == VK_LEFT || 02497 VirtualKeyCode == VK_UP || 02498 VirtualKeyCode == VK_DOWN || 02499 VirtualKeyCode == VK_NEXT || 02500 VirtualKeyCode == VK_PRIOR || 02501 VirtualKeyCode == VK_END || 02502 VirtualKeyCode == VK_HOME 02503 ) ) { 02504 PSCREEN_INFORMATION ScreenInfo; 02505 #ifdef FE_SB 02506 SHORT RowIndex; 02507 PROW Row; 02508 BYTE KAttrs; 02509 SHORT NextRightX; 02510 SHORT NextLeftX; 02511 #endif 02512 02513 ScreenInfo = Console->CurrentScreenBuffer; 02514 02515 // 02516 // see if shift is down. if so, we're extending 02517 // the selection. otherwise, we're resetting the 02518 // anchor 02519 // 02520 02521 ConsoleHideCursor(ScreenInfo); 02522 #ifdef FE_SB 02523 RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y) % ScreenInfo->ScreenBufferSize.Y; 02524 Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex]; 02525 02526 if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) 02527 { 02528 KAttrs = Row->CharRow.KAttrs[ScreenInfo->BufferInfo.TextInfo.CursorPosition.X]; 02529 if (KAttrs & ATTR_LEADING_BYTE) 02530 NextRightX = 2; 02531 else 02532 NextRightX = 1; 02533 } 02534 else 02535 { 02536 NextRightX = 1; 02537 } 02538 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X > 0) { 02539 if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) { 02540 KAttrs = Row->CharRow.KAttrs[ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-1]; 02541 if (KAttrs & ATTR_TRAILING_BYTE) 02542 NextLeftX = 2; 02543 else if (KAttrs & ATTR_LEADING_BYTE) { 02544 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-1 > 0) { 02545 KAttrs = Row->CharRow.KAttrs[ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-2]; 02546 if (KAttrs & ATTR_TRAILING_BYTE) 02547 NextLeftX = 3; 02548 else 02549 NextLeftX = 2; 02550 } 02551 else 02552 NextLeftX = 1; 02553 } 02554 else 02555 NextLeftX = 1; 02556 } 02557 else 02558 NextLeftX = 1; 02559 } 02560 02561 switch (VirtualKeyCode) { 02562 case VK_RIGHT: 02563 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X+NextRightX < ScreenInfo->ScreenBufferSize.X) { 02564 ScreenInfo->BufferInfo.TextInfo.CursorPosition.X+=NextRightX; 02565 } 02566 break; 02567 case VK_LEFT: 02568 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X > 0) { 02569 ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-=NextLeftX; 02570 } 02571 break; 02572 case VK_UP: 02573 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y > 0) { 02574 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y-=1; 02575 } 02576 break; 02577 case VK_DOWN: 02578 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1 < ScreenInfo->ScreenBufferSize.Y) { 02579 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+=1; 02580 } 02581 break; 02582 case VK_NEXT: 02583 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y += CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1; 02584 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y >= ScreenInfo->ScreenBufferSize.Y) { 02585 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = ScreenInfo->ScreenBufferSize.Y-1; 02586 } 02587 break; 02588 case VK_PRIOR: 02589 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y -= CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1; 02590 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y < 0) { 02591 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = 0; 02592 } 02593 break; 02594 case VK_END: 02595 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = ScreenInfo->ScreenBufferSize.Y-CONSOLE_WINDOW_SIZE_Y(ScreenInfo); 02596 break; 02597 case VK_HOME: 02598 ScreenInfo->BufferInfo.TextInfo.CursorPosition.X = 0; 02599 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = 0; 02600 break; 02601 default: 02602 ASSERT(FALSE); 02603 } 02604 #else // FE_SB 02605 switch (VirtualKeyCode) { 02606 case VK_RIGHT: 02607 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X+1 < ScreenInfo->ScreenBufferSize.X) { 02608 ScreenInfo->BufferInfo.TextInfo.CursorPosition.X+=1; 02609 } 02610 break; 02611 case VK_LEFT: 02612 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X > 0) { 02613 ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-=1; 02614 } 02615 break; 02616 case VK_UP: 02617 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y > 0) { 02618 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y-=1; 02619 } 02620 break; 02621 case VK_DOWN: 02622 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1 < ScreenInfo->ScreenBufferSize.Y) { 02623 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+=1; 02624 } 02625 break; 02626 case VK_NEXT: 02627 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y += CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1; 02628 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y >= ScreenInfo->ScreenBufferSize.Y) { 02629 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = ScreenInfo->ScreenBufferSize.Y-1; 02630 } 02631 break; 02632 case VK_PRIOR: 02633 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y -= CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1; 02634 if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y < 0) { 02635 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = 0; 02636 } 02637 break; 02638 case VK_END: 02639 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = ScreenInfo->ScreenBufferSize.Y-CONSOLE_WINDOW_SIZE_Y(ScreenInfo); 02640 break; 02641 case VK_HOME: 02642 ScreenInfo->BufferInfo.TextInfo.CursorPosition.X = 0; 02643 ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = 0; 02644 break; 02645 default: 02646 ASSERT(FALSE); 02647 } 02648 #endif // FE_SB 02649 ConsoleShowCursor(ScreenInfo); 02650 if (GetKeyState(VK_SHIFT) & KEY_PRESSED) { 02651 { 02652 ExtendSelection(Console,ScreenInfo->BufferInfo.TextInfo.CursorPosition); 02653 } 02654 } else { 02655 if (Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY) { 02656 MyInvert(Console,&Console->SelectionRect); 02657 Console->SelectionFlags &= ~CONSOLE_SELECTION_NOT_EMPTY; 02658 ConsoleShowCursor(ScreenInfo); 02659 } 02660 Console->SelectionAnchor = ScreenInfo->BufferInfo.TextInfo.CursorPosition; 02661 MakeCursorVisible(ScreenInfo,Console->SelectionAnchor); 02662 Console->SelectionRect.Left = Console->SelectionRect.Right = Console->SelectionAnchor.X; 02663 Console->SelectionRect.Top = Console->SelectionRect.Bottom = Console->SelectionAnchor.Y; 02664 } 02665 return; 02666 } 02667 } else if (!(Console->SelectionFlags & CONSOLE_MOUSE_DOWN)) { 02668 02669 // 02670 // if in mouse selection mode and user hits a key, cancel selection 02671 // 02672 02673 if (!IsSystemKey(VirtualKeyCode)) { 02674 ClearSelection(Console); 02675 } 02676 } 02677 } else if (Console->Flags & CONSOLE_SCROLLING) { 02678 02679 if (!bKeyDown) { 02680 return; 02681 } 02682 02683 // 02684 // if escape, enter or ctrl-c, cancel scroll 02685 // 02686 02687 if (VirtualKeyCode == VK_ESCAPE || 02688 VirtualKeyCode == VK_RETURN || 02689 (VirtualKeyCode == 'C' && 02690 (GetKeyState(VK_CONTROL) & KEY_PRESSED) )) { 02691 ClearScroll(Console); 02692 } else { 02693 WORD ScrollCommand; 02694 BOOL Horizontal=FALSE; 02695 switch (VirtualKeyCode) { 02696 case VK_UP: 02697 ScrollCommand = SB_LINEUP; 02698 break; 02699 case VK_DOWN: 02700 ScrollCommand = SB_LINEDOWN; 02701 break; 02702 case VK_LEFT: 02703 ScrollCommand = SB_LINEUP; 02704 Horizontal=TRUE; 02705 break; 02706 case VK_RIGHT: 02707 ScrollCommand = SB_LINEDOWN; 02708 Horizontal=TRUE; 02709 break; 02710 case VK_NEXT: 02711 ScrollCommand = SB_PAGEDOWN; 02712 break; 02713 case VK_PRIOR: 02714 ScrollCommand = SB_PAGEUP; 02715 break; 02716 case VK_END: 02717 ScrollCommand = SB_PAGEDOWN; 02718 Horizontal=TRUE; 02719 break; 02720 case VK_HOME: 02721 ScrollCommand = SB_PAGEUP; 02722 Horizontal=TRUE; 02723 break; 02724 case VK_SHIFT: 02725 case VK_CONTROL: 02726 case VK_MENU: 02727 return; 02728 default: 02729 Beep(800, 200); 02730 return; 02731 } 02732 if (Horizontal) 02733 HorizontalScroll(Console->CurrentScreenBuffer, ScrollCommand, 0); 02734 else 02735 VerticalScroll(Console, Console->CurrentScreenBuffer,ScrollCommand,0); 02736 } 02737 return; 02738 } 02739 02740 // 02741 // if the user is inputting chars at an inappropriate time, beep. 02742 // 02743 02744 if ((Console->Flags & (CONSOLE_SELECTING | CONSOLE_SCROLLING | CONSOLE_SCROLLBAR_TRACKING)) && 02745 bKeyDown && 02746 !IsSystemKey(VirtualKeyCode)) { 02747 Beep(800, 200); 02748 return; 02749 } 02750 02751 // 02752 // if in fullscreen mode, process PrintScreen 02753 // 02754 02755 #ifdef LATER 02756 // 02757 // Changed this code to get commas to work (build 485). 02758 // 02759 // Therese, the problem is that WM_CHAR/WM_SYSCHAR messages come through 02760 // here - in this case, LOWORD(wParam) is a character value and not a virtual 02761 // key. It happens that VK_SNAPSHOT == 0x2c, and the character value for a 02762 // comma is also == 0x2c, so execution enters this conditional when a comma 02763 // is hit. Commas aren't coming out because of the newly entered return 02764 // statement. 02765 // 02766 // HandleKeyEvent() is making many virtual key comparisons - need to make 02767 // sure that for each one, there is either no corresponding character value, 02768 // or that you check before you compare so that you are comparing two values 02769 // that have the same data type. 02770 // 02771 // I added the message comparison so that we know we're checking virtual 02772 // keys against virtual keys and not characters. 02773 // 02774 // - scottlu 02775 // 02776 02777 #endif 02778 02779 if (Message != WM_CHAR && Message != WM_SYSCHAR && 02780 VirtualKeyCode == VK_SNAPSHOT && 02781 !(Console->ReserveKeys & (CONSOLE_ALTPRTSC | CONSOLE_PRTSC )) ) { 02782 if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) { 02783 Console->SelectionFlags |= CONSOLE_SELECTION_NOT_EMPTY; 02784 Console->SelectionRect = Console->CurrentScreenBuffer->Window; 02785 StoreSelection(Console); 02786 Console->SelectionFlags &= ~CONSOLE_SELECTION_NOT_EMPTY; 02787 } 02788 return; 02789 } 02790 02791 // 02792 // IME stuff 02793 // 02794 if (!(Console->Flags & CONSOLE_VDM_REGISTERED)) { 02795 LPARAM lParamForHotKey ; 02796 DWORD HotkeyID ; 02797 lParamForHotKey = lParam ; 02798 02799 HotkeyID = NtUserCheckImeHotKey( (VirtualKeyCode & 0x00ff),lParamForHotKey) ; 02800 // 02801 // If it's direct KL switching hokey, handle it here 02802 // regardless the system is IME enabled or not. 02803 // 02804 if (HotkeyID >= IME_HOTKEY_DSWITCH_FIRST && HotkeyID <= IME_HOTKEY_DSWITCH_LAST) { 02805 UINT uModifier, uVkey; 02806 HKL hkl; 02807 02808 RIPMSG1(RIP_VERBOSE, "HandleKeyEvent: handling IME HOTKEY id=%x", HotkeyID); 02809 if (NtUserGetImeHotKey(HotkeyID, &uModifier, &uVkey, &hkl) && hkl != NULL) { 02810 BYTE bCharSetSys = CodePageToCharSet(GetACP()); 02811 WPARAM wpSysChar = 0; 02812 CHARSETINFO cs; 02813 02814 if (TranslateCharsetInfo((LPDWORD)LOWORD(hkl), &cs, TCI_SRCLOCALE)) { 02815 if (bCharSetSys == cs.ciCharset) { 02816 wpSysChar = INPUTLANGCHANGE_SYSCHARSET; 02817 } 02818 } 02819 PostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, wpSysChar, (LPARAM)hkl); 02820 } 02821 return; 02822 } 02823 02824 if (!(Console->InputBuffer.ImeMode.Disable) && CONSOLE_IS_IME_ENABLED()) { 02825 02826 if (HotkeyID != IME_INVALID_HOTKEY) { 02827 switch(HotkeyID) { 02828 case IME_JHOTKEY_CLOSE_OPEN: 02829 { 02830 BOOL fOpen = Console->InputBuffer.ImeMode.Open; 02831 if (!bKeyDown) 02832 break ; 02833 02834 Console->InputBuffer.ImeMode.Open = !fOpen ; 02835 if (!NT_SUCCESS(ConsoleImeMessagePump(Console, 02836 CONIME_HOTKEY, 02837 (WPARAM)Console->ConsoleHandle, 02838 HotkeyID))) { 02839 break; 02840 } 02841 02842 // Update in the system conversion mode buffer. 02843 GetImeKeyState(Console, NULL); 02844 02845 break ; 02846 } 02847 case IME_CHOTKEY_IME_NONIME_TOGGLE: 02848 case IME_THOTKEY_IME_NONIME_TOGGLE: 02849 case IME_CHOTKEY_SHAPE_TOGGLE: 02850 case IME_THOTKEY_SHAPE_TOGGLE: 02851 case IME_CHOTKEY_SYMBOL_TOGGLE: 02852 case IME_THOTKEY_SYMBOL_TOGGLE: 02853 case IME_KHOTKEY_SHAPE_TOGGLE: 02854 case IME_KHOTKEY_HANJACONVERT: 02855 case IME_KHOTKEY_ENGLISH: 02856 case IME_ITHOTKEY_RESEND_RESULTSTR: 02857 case IME_ITHOTKEY_PREVIOUS_COMPOSITION: 02858 case IME_ITHOTKEY_UISTYLE_TOGGLE: 02859 default: 02860 { 02861 if (!NT_SUCCESS(ConsoleImeMessagePump(Console, 02862 CONIME_HOTKEY, 02863 (WPARAM)Console->ConsoleHandle, 02864 HotkeyID))) { 02865 break; 02866 } 02867 02868 // Update in the system conversion mode buffer. 02869 GetImeKeyState(Console, NULL); 02870 02871 break ; 02872 } 02873 } 02874 return ; 02875 } 02876 02877 if ( CTRL_BUT_NOT_ALT(ControlKeyState) && 02878 (bKeyDown) ) { 02879 if (VirtualKeyCode == 'C' && 02880 Console->InputBuffer.InputMode & ENABLE_PROCESSED_INPUT) { 02881 goto FromConsoleIME ; 02882 } 02883 else if (VirtualKeyCode == VK_CANCEL) { 02884 goto FromConsoleIME ; 02885 } 02886 else if (VirtualKeyCode == 'S'){ 02887 goto FromConsoleIME ; 02888 } 02889 } 02890 else if (VirtualKeyCode == VK_PAUSE ){ 02891 goto FromConsoleIME ; 02892 } 02893 else if ( ((VirtualKeyCode == VK_SHIFT) || 02894 (VirtualKeyCode == VK_CONTROL) || 02895 (VirtualKeyCode == VK_CAPITAL) || 02896 (VirtualKeyCode == VK_KANA) || // VK_KANA == VK_HANGUL 02897 (VirtualKeyCode == VK_JUNJA) || 02898 (VirtualKeyCode == VK_HANJA) || 02899 (VirtualKeyCode == VK_NUMLOCK) || 02900 (VirtualKeyCode == VK_SCROLL) ) 02901 && 02902 !(Console->InputBuffer.ImeMode.Unavailable) && 02903 !(Console->InputBuffer.ImeMode.Open) 02904 ) 02905 { 02906 if (!NT_SUCCESS(ConsoleImeMessagePump(Console, 02907 Message+CONIME_KEYDATA, 02908 (WPARAM)LOWORD(wParam)<<16|LOWORD(VirtualKeyCode), 02909 lParam 02910 ))) { 02911 return; 02912 } 02913 goto FromConsoleIME ; 02914 } 02915 02916 if (!Console->InputBuffer.ImeMode.Unavailable && Console->InputBuffer.ImeMode.Open) { 02917 if (! (HIWORD(lParam) & KF_REPEAT)) 02918 { 02919 if (PRIMARYLANGID(LOWORD(Console->hklActive)) == LANG_JAPANESE && 02920 (BYTE)wParam == VK_KANA) { 02921 if (!NT_SUCCESS(ConsoleImeMessagePump(Console, 02922 CONIME_NOTIFY_VK_KANA, 02923 0, 02924 0 02925 ))) { 02926 return; 02927 } 02928 } 02929 } 02930 02931 ConsoleImeMessagePump(Console, 02932 Message+CONIME_KEYDATA, 02933 LOWORD(wParam)<<16|LOWORD(VirtualKeyCode), 02934 lParam 02935 ); 02936 return ; 02937 } 02938 } 02939 } 02940 FromConsoleIME: 02941 02942 // 02943 // ignore key strokes that will generate CHAR messages. this is only 02944 // necessary while a dialog box is up. 02945 // 02946 02947 if (DialogBoxCount > 0) { 02948 if (Message != WM_CHAR && Message != WM_SYSCHAR && Message != WM_DEADCHAR && Message != WM_SYSDEADCHAR) { 02949 WCHAR awch[MAX_CHARS_FROM_1_KEYSTROKE]; 02950 int cwch; 02951 BYTE KeyState[256]; 02952 02953 GetKeyboardState(KeyState); 02954 cwch = ToUnicodeEx((UINT)wParam,HIWORD(lParam),KeyState,awch, 02955 MAX_CHARS_FROM_1_KEYSTROKE, 02956 //TM_POSTCHARBREAKS | (KeyState(VK_MENU) & 1)); 02957 TM_POSTCHARBREAKS, 02958 (HKL)NULL); 02959 if (cwch != 0) { 02960 return; 02961 } 02962 } else { 02963 // remember to generate break 02964 if (Message == WM_CHAR) { 02965 bGenerateBreak=TRUE; 02966 } 02967 } 02968 } 02969 02970 #ifdef FE_IME 02971 // ignore key stroke while IME property is up. 02972 if (Console->InputBuffer.hWndConsoleIME) 02973 return; 02974 #endif 02975 02976 InputEvent.EventType = KEY_EVENT; 02977 InputEvent.Event.KeyEvent.bKeyDown = bKeyDown; 02978 InputEvent.Event.KeyEvent.wRepeatCount = LOWORD(lParam); 02979 02980 if (Message == WM_CHAR || Message == WM_SYSCHAR || Message == WM_DEADCHAR || Message == WM_SYSDEADCHAR) { 02981 // If this is a fake character, zero the scancode. 02982 if (lParam & 0x02000000) { 02983 InputEvent.Event.KeyEvent.wVirtualScanCode = 0; 02984 } 02985 InputEvent.Event.KeyEvent.dwControlKeyState = GetControlKeyState(lParam); 02986 if (Message == WM_CHAR || Message == WM_SYSCHAR) { 02987 InputEvent.Event.KeyEvent.uChar.UnicodeChar = (WCHAR)wParam; 02988 } else { 02989 InputEvent.Event.KeyEvent.uChar.UnicodeChar = (WCHAR)0; 02990 } 02991 } else { 02992 // if alt-gr, ignore 02993 if (lParam & 0x02000000) { 02994 return; 02995 } 02996 InputEvent.Event.KeyEvent.dwControlKeyState = ControlKeyState; 02997 InputEvent.Event.KeyEvent.uChar.UnicodeChar = 0; 02998 } 02999 03000 #ifdef FE_IME 03001 if (CONSOLE_IS_IME_ENABLED()) { 03002 // MSKK August.22.1993 KazuM 03003 DWORD dwConversion; 03004 03005 if (!NT_SUCCESS(GetImeKeyState(Console, &dwConversion))) { 03006 return; 03007 } 03008 03009 InputEvent.Event.KeyEvent.dwControlKeyState |= ImmConversionToConsole(dwConversion); 03010 } 03011 #endif 03012 03013 ContinueProcessing=TRUE; 03014 03015 if (CTRL_BUT_NOT_ALT(InputEvent.Event.KeyEvent.dwControlKeyState) && 03016 InputEvent.Event.KeyEvent.bKeyDown) { 03017 03018 // 03019 // check for ctrl-c, if in line input mode. 03020 // 03021 03022 if (InputEvent.Event.KeyEvent.wVirtualKeyCode == 'C' && 03023 Console->InputBuffer.InputMode & ENABLE_PROCESSED_INPUT) { 03024 HandleCtrlEvent(Console,CTRL_C_EVENT); 03025 if (!Console->PopupCount) 03026 TerminateRead(Console,&Console->InputBuffer,CONSOLE_CTRL_C_SEEN); 03027 if (!(Console->Flags & CONSOLE_SUSPENDED)) { 03028 ContinueProcessing=FALSE; 03029 } 03030 } 03031 03032 // 03033 // check for ctrl-break. 03034 // 03035 03036 else if (InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) { 03037 FlushInputBuffer(&Console->InputBuffer); 03038 HandleCtrlEvent(Console,CTRL_BREAK_EVENT); 03039 if (!Console->PopupCount) 03040 TerminateRead(Console,&Console->InputBuffer,CONSOLE_CTRL_BREAK_SEEN); 03041 if (!(Console->Flags & CONSOLE_SUSPENDED)) { 03042 ContinueProcessing=FALSE; 03043 } 03044 } 03045 03046 // 03047 // don't write ctrl-esc to the input buffer 03048 // 03049 03050 else if (InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE && 03051 !(Console->ReserveKeys & CONSOLE_CTRLESC)) { 03052 ContinueProcessing=FALSE; 03053 } 03054 } else if (InputEvent.Event.KeyEvent.dwControlKeyState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) && 03055 InputEvent.Event.KeyEvent.bKeyDown && 03056 InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE && 03057 !(Console->ReserveKeys & CONSOLE_ALTESC)) { 03058 ContinueProcessing=FALSE; 03059 } 03060 03061 if (ContinueProcessing) { 03062 EventsWritten = WriteInputBuffer( Console, 03063 &Console->InputBuffer, 03064 &InputEvent, 03065 1 03066 ); 03067 if (EventsWritten && bGenerateBreak) { 03068 InputEvent.Event.KeyEvent.bKeyDown = FALSE; 03069 WriteInputBuffer( Console, 03070 &Console->InputBuffer, 03071 &InputEvent, 03072 1 03073 ); 03074 } 03075 } 03076 return; 03077 } 03078 03079 BOOL 03080 HandleMouseEvent( 03081 IN PCONSOLE_INFORMATION Console, 03082 IN PSCREEN_INFORMATION ScreenInfo, 03083 IN UINT Message, 03084 IN WPARAM wParam, 03085 IN LPARAM lParam 03086 ) 03087 /* 03088 03089 returns TRUE if DefWindowProc should be called. 03090 03091 */ 03092 03093 { 03094 ULONG ButtonFlags,EventFlags; 03095 INPUT_RECORD InputEvent; 03096 ULONG EventsWritten; 03097 COORD MousePosition; 03098 SHORT RowIndex; 03099 PROW Row; 03100 03101 if (!(Console->Flags & CONSOLE_HAS_FOCUS) && 03102 !(Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) && 03103 !(Console->SelectionFlags & CONSOLE_MOUSE_DOWN)) { 03104 return TRUE; 03105 } 03106 03107 if (Console->Flags & CONSOLE_IGNORE_NEXT_MOUSE_INPUT) { 03108 // only reset on up transition 03109 if (Message != WM_LBUTTONDOWN && 03110 Message != WM_MBUTTONDOWN && 03111 Message != WM_RBUTTONDOWN) { 03112 Console->Flags &= ~CONSOLE_IGNORE_NEXT_MOUSE_INPUT; 03113 return FALSE; 03114 } 03115 return TRUE; 03116 } 03117 03118 // 03119 // translate mouse position into characters, if necessary. 03120 // 03121 03122 MousePosition.X = LOWORD(lParam); 03123 MousePosition.Y = HIWORD(lParam); 03124 if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { 03125 MousePosition.X /= SCR_FONTSIZE(ScreenInfo).X; 03126 MousePosition.Y /= SCR_FONTSIZE(ScreenInfo).Y; 03127 } 03128 MousePosition.X += ScreenInfo->Window.Left; 03129 MousePosition.Y += ScreenInfo->Window.Top; 03130 03131 // 03132 // make sure mouse position is clipped to screen buffer 03133 // 03134 03135 if (MousePosition.X < 0) { 03136 MousePosition.X = 0; 03137 } else if (MousePosition.X >= ScreenInfo->ScreenBufferSize.X) { 03138 MousePosition.X = ScreenInfo->ScreenBufferSize.X-1; 03139 } 03140 if (MousePosition.Y < 0) { 03141 MousePosition.Y = 0; 03142 } else if (MousePosition.Y >= ScreenInfo->ScreenBufferSize.Y) { 03143 MousePosition.Y = ScreenInfo->ScreenBufferSize.Y-1; 03144 } 03145 03146 if (Console->Flags & CONSOLE_SELECTING || 03147 ((Console->Flags & CONSOLE_QUICK_EDIT_MODE) && 03148 (Console->FullScreenFlags == 0)) ) { 03149 if (Message == WM_LBUTTONDOWN) { 03150 03151 // 03152 // make sure message matches button state 03153 // 03154 03155 if (!(GetKeyState(VK_LBUTTON) & KEY_PRESSED)) { 03156 return FALSE; 03157 } 03158 03159 if (Console->Flags & CONSOLE_QUICK_EDIT_MODE && 03160 !(Console->Flags & CONSOLE_SELECTING)) { 03161 Console->Flags |= CONSOLE_SELECTING; 03162 Console->SelectionFlags = CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN | CONSOLE_SELECTION_NOT_EMPTY; 03163 03164 // 03165 // invert selection 03166 // 03167 03168 Console->SelectionAnchor = MousePosition; 03169 Console->SelectionRect.Left =Console->SelectionRect.Right = Console->SelectionAnchor.X; 03170 Console->SelectionRect.Top = Console->SelectionRect.Bottom = Console->SelectionAnchor.Y; 03171 MyInvert(Console,&Console->SelectionRect); 03172 SetWinText(Console,msgSelectMode,TRUE); 03173 SetCapture(Console->hWnd); 03174 } else { 03175 03176 // 03177 // We now capture the mouse to our Window. We do this so that the user can 03178 // "scroll" the selection endpoint to an off screen position by moving the 03179 // mouse off the client area. 03180 // 03181 03182 if (Console->SelectionFlags & CONSOLE_MOUSE_SELECTION) { 03183 03184 // 03185 // Check for SHIFT-Mouse Down "continue previous selection" command 03186 // 03187 03188 if (GetKeyState(VK_SHIFT) & KEY_PRESSED) { 03189 Console->SelectionFlags |= CONSOLE_MOUSE_DOWN; // BUGBUG necessary flag? 03190 SetCapture(Console->hWnd); 03191 ExtendSelection(Console, 03192 MousePosition 03193 ); 03194 } else { 03195 03196 // 03197 // invert old selection, reset anchor, and invert 03198 // new selection. 03199 // 03200 03201 MyInvert(Console,&Console->SelectionRect); 03202 Console->SelectionFlags |= CONSOLE_MOUSE_DOWN; // BUGBUG necessary flag? 03203 SetCapture(Console->hWnd); 03204 Console->SelectionAnchor = MousePosition; 03205 Console->SelectionRect.Left =Console->SelectionRect.Right = Console->SelectionAnchor.X; 03206 Console->SelectionRect.Top = Console->SelectionRect.Bottom = Console->SelectionAnchor.Y; 03207 MyInvert(Console,&Console->SelectionRect); 03208 } 03209 } else { 03210 ConvertToMouseSelect(Console, 03211 MousePosition 03212 ); 03213 } 03214 } 03215 } else if (Message == WM_LBUTTONUP) { 03216 if (Console->SelectionFlags & CONSOLE_MOUSE_SELECTION) { 03217 Console->SelectionFlags &= ~CONSOLE_MOUSE_DOWN; 03218 ReleaseCapture(); 03219 } 03220 } else if (Message == WM_LBUTTONDBLCLK) { 03221 if ((MousePosition.X == Console->SelectionAnchor.X) && 03222 (MousePosition.Y == Console->SelectionAnchor.Y)) { 03223 RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+MousePosition.Y) % ScreenInfo->ScreenBufferSize.Y; 03224 Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex]; 03225 while (Console->SelectionAnchor.X > 0) { 03226 if (IS_WORD_DELIM(Row->CharRow.Chars[Console->SelectionAnchor.X - 1])) 03227 break; 03228 Console->SelectionAnchor.X--; 03229 } 03230 while (MousePosition.X < ScreenInfo->ScreenBufferSize.X) { 03231 if (IS_WORD_DELIM(Row->CharRow.Chars[MousePosition.X])) 03232 break; 03233 MousePosition.X++; 03234 } 03235 if (gfTrimLeadingZeros) { 03236 // 03237 // Trim the leading zeros: 000fe12 -> fe12 03238 // Usefull for debugging 03239 // 03240 if (MousePosition.X > Console->SelectionAnchor.X + 2 && 03241 Row->CharRow.Chars[Console->SelectionAnchor.X + 1] != L'x' && 03242 Row->CharRow.Chars[Console->SelectionAnchor.X + 1] != L'X') { 03243 // Don't touch the selection begins with 0x 03244 while (Row->CharRow.Chars[Console->SelectionAnchor.X] == L'0' && Console->SelectionAnchor.X < MousePosition.X - 1) { 03245 Console->SelectionAnchor.X++; 03246 } 03247 } 03248 } 03249 ExtendSelection(Console, MousePosition); 03250 } 03251 } else if ((Message == WM_RBUTTONDOWN) || (Message == WM_RBUTTONDBLCLK)) { 03252 if (!(Console->SelectionFlags & CONSOLE_MOUSE_DOWN)) { 03253 if (Console->Flags & CONSOLE_SELECTING) { 03254 DoCopy(Console); 03255 } else if (Console->Flags & CONSOLE_QUICK_EDIT_MODE) { 03256 DoPaste(Console); 03257 } 03258 Console->Flags |= CONSOLE_IGNORE_NEXT_MOUSE_INPUT; 03259 } 03260 } else if (Message == WM_MOUSEMOVE) { 03261 if (Console->SelectionFlags & CONSOLE_MOUSE_DOWN) { 03262 ExtendSelection(Console, 03263 MousePosition 03264 ); 03265 } 03266 } else if (Message == WM_MOUSEWHEEL) { 03267 return TRUE; 03268 } 03269 return FALSE; 03270 } 03271 03272 if (!(Console->InputBuffer.InputMode & ENABLE_MOUSE_INPUT)) { 03273 ReleaseCapture(); 03274 if (Console->FullScreenFlags == 0) { 03275 return TRUE; 03276 } 03277 return FALSE; 03278 } 03279 03280 // BUGBUG alt is not set correctly 03281 InputEvent.Event.MouseEvent.dwControlKeyState = GetControlKeyState(0); 03282 03283 if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) { 03284 if (MousePosition.X > ScreenInfo->Window.Right) { 03285 MousePosition.X = ScreenInfo->Window.Right; 03286 } 03287 if (MousePosition.Y > ScreenInfo->Window.Bottom) { 03288 MousePosition.Y = ScreenInfo->Window.Bottom; 03289 } 03290 } 03291 switch (Message) { 03292 case WM_LBUTTONDOWN: 03293 SetCapture(Console->hWnd); 03294 ButtonFlags = FROM_LEFT_1ST_BUTTON_PRESSED; 03295 EventFlags = 0; 03296 break; 03297 case WM_LBUTTONUP: 03298 ReleaseCapture(); 03299 ButtonFlags = 0; 03300 EventFlags = 0; 03301 break; 03302 case WM_RBUTTONDOWN: 03303 SetCapture(Console->hWnd); 03304 ButtonFlags = RIGHTMOST_BUTTON_PRESSED; 03305 EventFlags = 0; 03306 break; 03307 case WM_RBUTTONUP: 03308 ReleaseCapture(); 03309 ButtonFlags = 0; 03310 EventFlags = 0; 03311 break; 03312 case WM_MBUTTONDOWN: 03313 SetCapture(Console->hWnd); 03314 ButtonFlags = FROM_LEFT_2ND_BUTTON_PRESSED; 03315 EventFlags = 0; 03316 break; 03317 case WM_MBUTTONUP: 03318 ReleaseCapture(); 03319 ButtonFlags = 0; 03320 EventFlags = 0; 03321 break; 03322 case WM_MOUSEMOVE: 03323 ButtonFlags = 0; 03324 EventFlags = MOUSE_MOVED; 03325 break; 03326 case WM_LBUTTONDBLCLK: 03327 ButtonFlags = FROM_LEFT_1ST_BUTTON_PRESSED; 03328 EventFlags = DOUBLE_CLICK; 03329 break; 03330 case WM_RBUTTONDBLCLK: 03331 ButtonFlags = RIGHTMOST_BUTTON_PRESSED; 03332 EventFlags = DOUBLE_CLICK; 03333 break; 03334 case WM_MBUTTONDBLCLK: 03335 ButtonFlags = FROM_LEFT_2ND_BUTTON_PRESSED; 03336 EventFlags = DOUBLE_CLICK; 03337 break; 03338 case WM_MOUSEWHEEL: 03339 ButtonFlags = ((UINT)wParam & 0xFFFF0000); 03340 EventFlags = MOUSE_WHEELED; 03341 break; 03342 default: 03343 ASSERT(FALSE); 03344 } 03345 InputEvent.EventType = MOUSE_EVENT; 03346 InputEvent.Event.MouseEvent.dwMousePosition = MousePosition; 03347 InputEvent.Event.MouseEvent.dwEventFlags = EventFlags; 03348 InputEvent.Event.MouseEvent.dwButtonState = 03349 ConvertMouseButtonState(ButtonFlags,(UINT)wParam); 03350 EventsWritten = WriteInputBuffer( Console, 03351 &Console->InputBuffer, 03352 &InputEvent, 03353 1 03354 ); 03355 #if DBG 03356 if (EventsWritten != 1) { 03357 OutputDebugStringA("PutInputInBuffer: EventsWritten != 1, 1 expected\n"); 03358 } 03359 #endif 03360 #ifdef i386 03361 if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) { 03362 UpdateMousePosition(ScreenInfo,InputEvent.Event.MouseEvent.dwMousePosition); 03363 } 03364 #endif 03365 return FALSE; 03366 } 03367 03368 VOID 03369 HandleFocusEvent( 03370 IN PCONSOLE_INFORMATION Console, 03371 IN BOOL bSetFocus 03372 ) 03373 { 03374 INPUT_RECORD InputEvent; 03375 ULONG EventsWritten; 03376 USERTHREAD_FLAGS Flags; 03377 03378 InputEvent.EventType = FOCUS_EVENT; 03379 InputEvent.Event.FocusEvent.bSetFocus = bSetFocus; 03380 03381 Flags.dwFlags = 0; 03382 if (bSetFocus) { 03383 if (Console->Flags & CONSOLE_VDM_REGISTERED) { 03384 Flags.dwFlags |= TIF_VDMAPP; 03385 } 03386 if (Console->Flags & CONSOLE_CONNECTED_TO_EMULATOR) { 03387 Flags.dwFlags |= TIF_DOSEMULATOR; 03388 } 03389 } 03390 03391 Flags.dwMask = (TIF_VDMAPP | TIF_DOSEMULATOR); 03392 NtUserSetInformationThread(Console->InputThreadInfo->ThreadHandle, 03393 UserThreadFlags, &Flags, sizeof(Flags)); 03394 EventsWritten = WriteInputBuffer( Console, 03395 &Console->InputBuffer, 03396 &InputEvent, 03397 1 03398 ); 03399 #if DBG 03400 if (EventsWritten != 1) { 03401 OutputDebugStringA("PutInputInBuffer: EventsWritten != 1, 1 expected\n"); 03402 } 03403 #endif 03404 } 03405 03406 VOID 03407 HandleMenuEvent( 03408 IN PCONSOLE_INFORMATION Console, 03409 IN DWORD wParam 03410 ) 03411 { 03412 INPUT_RECORD InputEvent; 03413 ULONG EventsWritten; 03414 03415 InputEvent.EventType = MENU_EVENT; 03416 InputEvent.Event.MenuEvent.dwCommandId = wParam; 03417 EventsWritten = WriteInputBuffer( Console, 03418 &Console->InputBuffer, 03419 &InputEvent, 03420 1 03421 ); 03422 #if DBG 03423 if (EventsWritten != 1) { 03424 OutputDebugStringA("PutInputInBuffer: EventsWritten != 1, 1 expected\n"); 03425 } 03426 #endif 03427 } 03428 03429 VOID 03430 HandleCtrlEvent( 03431 IN PCONSOLE_INFORMATION Console, 03432 IN DWORD EventType 03433 ) 03434 { 03435 switch (EventType) { 03436 case CTRL_C_EVENT: 03437 Console->CtrlFlags |= CONSOLE_CTRL_C_FLAG; 03438 break; 03439 case CTRL_BREAK_EVENT: 03440 Console->CtrlFlags |= CONSOLE_CTRL_BREAK_FLAG; 03441 break; 03442 case CTRL_CLOSE_EVENT: 03443 Console->CtrlFlags |= CONSOLE_CTRL_CLOSE_FLAG; 03444 break; 03445 default: 03446 ASSERT (FALSE); 03447 } 03448 } 03449 03450 VOID 03451 KillProcess( 03452 PCONSOLE_PROCESS_TERMINATION_RECORD ProcessHandleRecord, 03453 ULONG_PTR ProcessId 03454 ) 03455 { 03456 NTSTATUS status; 03457 03458 // 03459 // Just terminate the process outright. 03460 // 03461 03462 status = NtTerminateProcess(ProcessHandleRecord->ProcessHandle, 03463 ProcessHandleRecord->bDebugee ? DBG_TERMINATE_PROCESS : CONTROL_C_EXIT); 03464 03465 #if DBG 03466 if (status != STATUS_SUCCESS && 03467 status != STATUS_PROCESS_IS_TERMINATING && 03468 status != STATUS_THREAD_WAS_SUSPENDED && 03469 !(status == STATUS_ACCESS_DENIED && ProcessHandleRecord->bDebugee)) { 03470 DbgPrint("NtTerminateProcess failed - status = %x\n", status); 03471 DbgBreakPoint(); 03472 } 03473 #endif 03474 03475 // 03476 // Clear any remaining hard errors for the process. 03477 // 03478 03479 if (ProcessId) 03480 BoostHardError(ProcessId, BHE_FORCE); 03481 03482 // 03483 // Give the process 5 seconds to exit. 03484 // 03485 03486 if (NT_SUCCESS(status)) { 03487 LARGE_INTEGER li; 03488 03489 li.QuadPart = (LONGLONG)-10000 * CMSHUNGAPPTIMEOUT; 03490 status = NtWaitForSingleObject(ProcessHandleRecord->ProcessHandle, 03491 FALSE, 03492 &li); 03493 if (status != STATUS_WAIT_0) { 03494 RIPMSG2(RIP_WARNING, 03495 "KillProcess: wait for process %x failed with status %x", 03496 ProcessId, status); 03497 } 03498 } 03499 } 03500 03501 int 03502 CreateCtrlThread( 03503 IN PCONSOLE_PROCESS_TERMINATION_RECORD ProcessHandleList, 03504 IN ULONG ProcessHandleListLength, 03505 IN PWCHAR Title, 03506 IN DWORD EventType, 03507 IN BOOL fForce 03508 ) 03509 03510 // this routine must be called not holding the console lock. 03511 // returns true if process is exiting 03512 03513 { 03514 HANDLE Thread; 03515 DWORD Status; 03516 NTSTATUS status; 03517 DWORD ShutdownFlags; 03518 int Success=CONSOLE_SHUTDOWN_SUCCEEDED; 03519 ULONG i; 03520 DWORD EventFlags; 03521 PROCESS_BASIC_INFORMATION BasicInfo; 03522 PCSR_PROCESS Process; 03523 BOOL fForceProcess; 03524 BOOL fExitProcess; 03525 BOOL fFirstPass=TRUE; 03526 BOOL fSecondPassNeeded=FALSE; 03527 BOOL fHasError; 03528 BOOL fFirstWait; 03529 BOOL fEventProcessed; 03530 BOOL fBreakEvent; 03531 03532 BigLoop: 03533 for (i=0;i<ProcessHandleListLength;i++) { 03534 03535 // 03536 // If the user has already cancelled shutdown, don't try to kill 03537 // any more processes. 03538 // 03539 03540 if (Success == CONSOLE_SHUTDOWN_FAILED) { 03541 break; 03542 } 03543 03544 // 03545 // Get the process shutdown parameters here. First get the process 03546 // id so we can get the csr process structure pointer. 03547 // 03548 03549 status = NtQueryInformationProcess( 03550 ProcessHandleList[i].ProcessHandle, 03551 ProcessBasicInformation, 03552 &BasicInfo, 03553 sizeof(BasicInfo), 03554 NULL); 03555 03556 // 03557 // Grab the shutdown flags from the csr process structure. If 03558 // the structure cannot be found, terminate the process. 03559 // 03560 03561 ProcessHandleList[i].bDebugee = FALSE; 03562 ShutdownFlags = 0; 03563 if (NT_SUCCESS(status)) { 03564 CsrLockProcessByClientId( 03565 (HANDLE)BasicInfo.UniqueProcessId, &Process); 03566 if (Process == NULL) { 03567 KillProcess(&ProcessHandleList[i], 03568 BasicInfo.UniqueProcessId); 03569 continue; 03570 } 03571 } else { 03572 KillProcess(&ProcessHandleList[i], 0); 03573 continue; 03574 } 03575 ShutdownFlags = Process->ShutdownFlags; 03576 ProcessHandleList[i].bDebugee = Process->DebugUserInterface.UniqueProcess!=NULL; 03577 CsrUnlockProcess(Process); 03578 03579 if (!ProcessHandleList[i].bDebugee) { 03580 HANDLE DebugPort; 03581 03582 // see if we're a OS/2 app that's being debugged 03583 DebugPort = (HANDLE)NULL; 03584 status = NtQueryInformationProcess( 03585 ProcessHandleList[i].ProcessHandle, 03586 ProcessDebugPort, 03587 (PVOID)&DebugPort, 03588 sizeof(DebugPort), 03589 NULL 03590 ); 03591 if ( NT_SUCCESS(status) && DebugPort ) { 03592 ProcessHandleList[i].bDebugee = TRUE; 03593 } 03594 } 03595 if (EventType != CTRL_C_EVENT && EventType != CTRL_BREAK_EVENT) { 03596 fBreakEvent = FALSE; 03597 if (fFirstPass) { 03598 if (ProcessHandleList[i].bDebugee) { 03599 fSecondPassNeeded = TRUE; 03600 continue; 03601 } 03602 } else { 03603 if (!ProcessHandleList[i].bDebugee) { 03604 continue; 03605 } 03606 } 03607 } else { 03608 fBreakEvent = TRUE; 03609 fFirstPass=FALSE; 03610 } 03611 03612 // 03613 // fForce is whether ExitWindowsEx was called with EWX_FORCE. 03614 // ShutdownFlags are the shutdown flags for this process. If 03615 // either are force (noretry is the same as force), then force: 03616 // which means if the app doesn't exit, don't bring up the retry 03617 // dialog - just force it to exit right away. 03618 // 03619 03620 fForceProcess = fForce || (ShutdownFlags & SHUTDOWN_NORETRY); 03621 03622 // 03623 // Only notify system security and service context processes. 03624 // Don't bring up retry dialogs for them. 03625 // 03626 03627 fExitProcess = TRUE; 03628 EventFlags = 0; 03629 if (ShutdownFlags & (SHUTDOWN_SYSTEMCONTEXT | SHUTDOWN_OTHERCONTEXT)) { 03630 03631 // 03632 // System context - make sure we don't cause it to exit, make 03633 // sure we don't bring up retry dialogs. 03634 // 03635 03636 fExitProcess = FALSE; 03637 fForceProcess = TRUE; 03638 03639 // 03640 // This EventFlag will be passed on down to the CtrlRoutine() 03641 // on the client side. That way that side knows not to exit 03642 // this process. 03643 // 03644 03645 EventFlags = 0x80000000; 03646 } 03647 03648 // 03649 // Is this the first time we're waiting for this process to die? 03650 // 03651 03652 fFirstWait = TRUE; 03653 fEventProcessed = FALSE; 03654 03655 while (!fEventProcessed) { 03656 DWORD ThreadExitCode; 03657 DWORD ProcessExitCode; 03658 DWORD cMsTimeout; 03659 03660 Thread = InternalCreateCallbackThread( 03661 ProcessHandleList[i].ProcessHandle, 03662 (ULONG_PTR)ProcessHandleList[i].CtrlRoutine, 03663 EventType | EventFlags); 03664 03665 // 03666 // If the thread cannot be created, terminate the process. 03667 // 03668 03669 if (Thread == NULL) { 03670 KdPrint(("CONSRV: CreateRemoteThread failed %x\n",GetLastError())); 03671 break; 03672 } 03673 03674 // 03675 // Mark the event as processed. 03676 // 03677 03678 fEventProcessed = TRUE; 03679 03680 /* 03681 * if it's a ctrl-c or ctrl-break event, just close our 03682 * handle to the thread. otherwise it's a close. wait 03683 * for client-side thread to terminate. 03684 */ 03685 03686 if (EventType == CTRL_CLOSE_EVENT) { 03687 cMsTimeout = gCmsHungAppTimeout; 03688 } else if (EventType == CTRL_LOGOFF_EVENT) { 03689 cMsTimeout = gCmsWaitToKillTimeout; 03690 } else if (EventType == CTRL_SHUTDOWN_EVENT) { 03691 03692 // 03693 // If we are shutting down services.exe, we need to look in the 03694 // registry to see how long to wait. 03695 // 03696 03697 if (fFirstWait && BasicInfo.UniqueProcessId == gdwServicesProcessId) { 03698 cMsTimeout = gdwServicesWaitToKillTimeout; 03699 } else { 03700 cMsTimeout = gCmsWaitToKillTimeout; 03701 } 03702 } else { 03703 CloseHandle(Thread); 03704 fExitProcess = FALSE; 03705 break; 03706 } 03707 03708 while (TRUE) { 03709 fHasError = BoostHardError(BasicInfo.UniqueProcessId, 03710 (fForceProcess ? BHE_FORCE : BHE_ACTIVATE)); 03711 03712 // 03713 // Use a 1 second wait if there was a hard error, otherwise 03714 // wait cMsTimeout ms. 03715 // 03716 03717 Status = InternalWaitCancel(Thread, 03718 (fHasError && fForceProcess) ? 1000 : cMsTimeout); 03719 if (Status == WAIT_TIMEOUT) { 03720 int Action; 03721 03722 // 03723 // If there was a hard error, see if there is another one. 03724 // 03725 03726 if (fHasError && fForceProcess) { 03727 continue; 03728 } 03729 03730 if (!fForceProcess) { 03731 03732 // 03733 // we timed out in the handler. ask the user what 03734 // to do. 03735 // 03736 03737 DialogBoxCount++; 03738 Action = ThreadShutdownNotify(WMCS_CONSOLE, (ULONG_PTR)Thread, (LPARAM)Title); 03739 DialogBoxCount--; 03740 03741 // 03742 // If the response is Cancel or EndTask, exit the loop. 03743 // Otherwise retry the wait. 03744 // 03745 03746 if (Action == TSN_USERSAYSCANCEL) { 03747 Success = CONSOLE_SHUTDOWN_FAILED; 03748 } 03749 } 03750 } else if (Status == 0) { 03751 ThreadExitCode = 0; 03752 GetExitCodeThread(Thread,&ThreadExitCode); 03753 GetExitCodeProcess(ProcessHandleList[i].ProcessHandle, 03754 &ProcessExitCode); 03755 03756 // 03757 // if the app returned TRUE (event handled) 03758 // notify the user and see if the app should 03759 // be terminated anyway. 03760 // 03761 03762 if (fHasError || (ThreadExitCode == EventType && 03763 ProcessExitCode == STILL_ACTIVE)) { 03764 int Action; 03765 03766 if (!fForceProcess) { 03767 03768 // 03769 // Wait for the process to exit. If it does exit, 03770 // don't bring up the end task dialog. 03771 // 03772 03773 Status = InternalWaitCancel(ProcessHandleList[i].ProcessHandle, 03774 (fHasError || fFirstWait) ? 1000 : cMsTimeout); 03775 if (Status == 0) { 03776 03777 // 03778 // The process exited. 03779 // 03780 03781 fExitProcess = FALSE; 03782 } else if (Status == WAIT_TIMEOUT) { 03783 DialogBoxCount++; 03784 Action = ThreadShutdownNotify(WMCS_CONSOLE, 03785 (ULONG_PTR)ProcessHandleList[i].ProcessHandle, 03786 (LPARAM)Title); 03787 DialogBoxCount--; 03788 03789 if (Action == TSN_USERSAYSCANCEL) { 03790 Success = CONSOLE_SHUTDOWN_FAILED; 03791 } 03792 } 03793 } 03794 } else { 03795 03796 // 03797 // The process exited. 03798 // 03799 03800 fExitProcess = FALSE; 03801 } 03802 } 03803 03804 // 03805 // If we get here, we know that all wait conditions have 03806 // been satisfied. Time to finish with the process. 03807 // 03808 03809 break; 03810 } 03811 03812 CloseHandle(Thread); 03813 } 03814 03815 // 03816 // If the process is shutting down, mark it as terminated. 03817 // This prevents the process from raising any hard error popups 03818 // after we're done shutting it down. 03819 // 03820 03821 if (!fBreakEvent && 03822 !(ShutdownFlags & (SHUTDOWN_SYSTEMCONTEXT | SHUTDOWN_OTHERCONTEXT)) && 03823 Success == CONSOLE_SHUTDOWN_SUCCEEDED) { 03824 CsrLockProcessByClientId( 03825 (HANDLE)BasicInfo.UniqueProcessId, &Process); 03826 if (Process) { 03827 Process->Flags |= CSR_PROCESS_TERMINATED; 03828 CsrUnlockProcess(Process); 03829 } 03830 03831 // 03832 // Force the termination of the process if needed. Otherwise, 03833 // acknowledge any remaining hard errors. 03834 // 03835 if (fExitProcess) { 03836 KillProcess(&ProcessHandleList[i], 03837 BasicInfo.UniqueProcessId); 03838 } else { 03839 BoostHardError(BasicInfo.UniqueProcessId, BHE_FORCE); 03840 } 03841 } 03842 } 03843 03844 // 03845 // If this was our first time through and we skipped one of the 03846 // processes because it was being debugged, we'll go back for a 03847 // second pass. 03848 // 03849 03850 if (fFirstPass && fSecondPassNeeded) { 03851 fFirstPass = FALSE; 03852 goto BigLoop; 03853 } 03854 03855 // if we're shutting down a system or service security context 03856 // thread, don't wait for the process to terminate 03857 03858 if (ShutdownFlags & (SHUTDOWN_SYSTEMCONTEXT | SHUTDOWN_OTHERCONTEXT)) { 03859 return CONSOLE_SHUTDOWN_SYSTEM; 03860 } 03861 return Success; 03862 } 03863 03864 int 03865 ProcessCtrlEvents( 03866 IN PCONSOLE_INFORMATION Console 03867 ) 03868 /* returns TRUE if a ctrl thread was created */ 03869 { 03870 PWCHAR Title; 03871 CONSOLE_PROCESS_TERMINATION_RECORD ProcessHandles[2]; 03872 PCONSOLE_PROCESS_TERMINATION_RECORD ProcessHandleList; 03873 ULONG ProcessHandleListLength,i; 03874 ULONG CtrlFlags; 03875 PLIST_ENTRY ListHead, ListNext; 03876 BOOL FreeTitle; 03877 int Success; 03878 PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; 03879 DWORD EventType; 03880 DWORD LimitingProcessId; 03881 NTSTATUS Status; 03882 03883 // 03884 // If the console was marked for destruction, do it now. 03885 // 03886 03887 if (Console->Flags & CONSOLE_IN_DESTRUCTION) { 03888 DestroyConsole(Console); 03889 return CONSOLE_SHUTDOWN_FAILED; 03890 } 03891 03892 // 03893 // make sure we don't try to process control events if this 03894 // console is already going away 03895 // 03896 03897 if (Console->Flags & CONSOLE_TERMINATING) { 03898 Console->CtrlFlags = 0; 03899 } 03900 03901 if (Console->CtrlFlags == 0) { 03902 RtlLeaveCriticalSection(&Console->ConsoleLock); 03903 return CONSOLE_SHUTDOWN_FAILED; 03904 } 03905 03906 // 03907 // make our own copy of the console process handle list 03908 // 03909 03910 LimitingProcessId = Console->LimitingProcessId; 03911 Console->LimitingProcessId = 0; 03912 03913 ListHead = &Console->ProcessHandleList; 03914 ListNext = ListHead->Flink; 03915 ProcessHandleListLength = 0; 03916 while (ListNext != ListHead) { 03917 ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink ); 03918 ListNext = ListNext->Flink; 03919 if ( LimitingProcessId ) { 03920 if ( ProcessHandleRecord->Process->ProcessGroupId == LimitingProcessId ) { 03921 ProcessHandleListLength += 1; 03922 } 03923 } else { 03924 ProcessHandleListLength += 1; 03925 } 03926 } 03927 03928 // 03929 // Use the stack buffer to hold the process handles if there are only a 03930 // few, otherwise allocate a buffer from the heap. 03931 // 03932 03933 if (ProcessHandleListLength <= NELEM(ProcessHandles)) { 03934 ProcessHandleList = ProcessHandles; 03935 } else { 03936 ProcessHandleList = (PCONSOLE_PROCESS_TERMINATION_RECORD)ConsoleHeapAlloc(MAKE_TAG( TMP_TAG ),ProcessHandleListLength * sizeof(CONSOLE_PROCESS_TERMINATION_RECORD)); 03937 if (ProcessHandleList == NULL) { 03938 RtlLeaveCriticalSection(&Console->ConsoleLock); 03939 return CONSOLE_SHUTDOWN_FAILED; 03940 } 03941 } 03942 03943 ListNext = ListHead->Flink; 03944 i=0; 03945 while (ListNext != ListHead) { 03946 BOOLEAN ProcessIsIn; 03947 03948 ASSERT(i<=ProcessHandleListLength); 03949 ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink ); 03950 ListNext = ListNext->Flink; 03951 03952 if ( LimitingProcessId ) { 03953 if ( ProcessHandleRecord->Process->ProcessGroupId == LimitingProcessId ) { 03954 ProcessIsIn = TRUE; 03955 } else { 03956 ProcessIsIn = FALSE; 03957 } 03958 } else { 03959 ProcessIsIn = TRUE; 03960 } 03961 03962 if ( ProcessIsIn ) { 03963 Success = (int)DuplicateHandle(NtCurrentProcess(), 03964 ProcessHandleRecord->ProcessHandle, 03965 NtCurrentProcess(), 03966 &ProcessHandleList[i].ProcessHandle, 03967 0, 03968 FALSE, 03969 DUPLICATE_SAME_ACCESS); 03970 03971 // 03972 // If the duplicate failed, the best we can do is to skip 03973 // including the process in the list and hope it goes 03974 // away. 03975 // 03976 if (!Success) { 03977 KdPrint(("CONSRV: dup handle failed for %d of %d in %lx\n", 03978 i, ProcessHandleListLength, Console)); 03979 continue; 03980 } 03981 03982 if (Console->CtrlFlags & CONSOLE_CTRL_CLOSE_FLAG) { 03983 ProcessHandleRecord->TerminateCount++; 03984 } else { 03985 ProcessHandleRecord->TerminateCount = 0; 03986 } 03987 ProcessHandleList[i].TerminateCount = ProcessHandleRecord->TerminateCount; 03988 03989 if (ProcessHandleRecord->CtrlRoutine) { 03990 ProcessHandleList[i].CtrlRoutine = ProcessHandleRecord->CtrlRoutine; 03991 } else { 03992 ProcessHandleList[i].CtrlRoutine = CtrlRoutine; 03993 } 03994 03995 // 03996 // If this is the VDM process and we're closing the 03997 // console window, move it to the front of the list 03998 // 03999 04000 if (i > 0 && Console->VDMProcessId && Console->VDMProcessId == 04001 ProcessHandleRecord->Process->ClientId.UniqueProcess && 04002 ProcessHandleRecord->TerminateCount > 0) { 04003 CONSOLE_PROCESS_TERMINATION_RECORD ProcessHandle; 04004 ProcessHandle = ProcessHandleList[0]; 04005 ProcessHandleList[0] = ProcessHandleList[i]; 04006 ProcessHandleList[i] = ProcessHandle; 04007 } 04008 04009 i++; 04010 } 04011 } 04012 ProcessHandleListLength = i; 04013 ASSERT(ProcessHandleListLength > 0); 04014 04015 // copy title. titlelength does not include terminating null. 04016 04017 Title = (PWCHAR)ConsoleHeapAlloc(MAKE_TAG( TITLE_TAG ),Console->TitleLength+sizeof(WCHAR)); 04018 if (Title) { 04019 FreeTitle = TRUE; 04020 RtlCopyMemory(Title,Console->Title,Console->TitleLength+sizeof(WCHAR)); 04021 } else { 04022 FreeTitle = FALSE; 04023 Title = L"Command Window"; 04024 } 04025 04026 // copy ctrl flags 04027 04028 CtrlFlags = Console->CtrlFlags; 04029 ASSERT( !((CtrlFlags & (CONSOLE_CTRL_CLOSE_FLAG | CONSOLE_CTRL_BREAK_FLAG | CONSOLE_CTRL_C_FLAG)) && 04030 (CtrlFlags & (CONSOLE_CTRL_LOGOFF_FLAG | CONSOLE_CTRL_SHUTDOWN_FLAG)) )); 04031 04032 Console->CtrlFlags = 0; 04033 04034 RtlLeaveCriticalSection(&Console->ConsoleLock); 04035 04036 // 04037 // the ctrl flags could be a combination of the following 04038 // values: 04039 // 04040 // CONSOLE_CTRL_C_FLAG 04041 // CONSOLE_CTRL_BREAK_FLAG 04042 // CONSOLE_CTRL_CLOSE_FLAG 04043 // CONSOLE_CTRL_LOGOFF_FLAG 04044 // CONSOLE_CTRL_SHUTDOWN_FLAG 04045 // 04046 04047 Success = CONSOLE_SHUTDOWN_FAILED; 04048 04049 EventType = (DWORD)-1; 04050 switch (CtrlFlags & (CONSOLE_CTRL_CLOSE_FLAG | CONSOLE_CTRL_BREAK_FLAG | 04051 CONSOLE_CTRL_C_FLAG | CONSOLE_CTRL_LOGOFF_FLAG | 04052 CONSOLE_CTRL_SHUTDOWN_FLAG)) { 04053 04054 case CONSOLE_CTRL_CLOSE_FLAG: 04055 EventType = CTRL_CLOSE_EVENT; 04056 break; 04057 04058 case CONSOLE_CTRL_BREAK_FLAG: 04059 EventType = CTRL_BREAK_EVENT; 04060 break; 04061 04062 case CONSOLE_CTRL_C_FLAG: 04063 EventType = CTRL_C_EVENT; 04064 break; 04065 04066 case CONSOLE_CTRL_LOGOFF_FLAG: 04067 EventType = CTRL_LOGOFF_EVENT; 04068 break; 04069 04070 case CONSOLE_CTRL_SHUTDOWN_FLAG: 04071 EventType = CTRL_SHUTDOWN_EVENT; 04072 break; 04073 } 04074 04075 if (EventType != (DWORD)-1) { 04076 04077 Success = CreateCtrlThread(ProcessHandleList, 04078 ProcessHandleListLength, 04079 Title, 04080 EventType, 04081 (CtrlFlags & CONSOLE_FORCE_SHUTDOWN_FLAG) != 0 04082 ); 04083 } 04084 04085 if (FreeTitle) { 04086 ConsoleHeapFree(Title); 04087 } 04088 04089 for (i=0;i<ProcessHandleListLength;i++) { 04090 Status = NtClose(ProcessHandleList[i].ProcessHandle); 04091 ASSERT(NT_SUCCESS(Status)); 04092 } 04093 04094 if (ProcessHandleList != ProcessHandles) { 04095 ConsoleHeapFree(ProcessHandleList); 04096 } 04097 04098 return Success; 04099 } 04100 04101 04102 VOID 04103 UnlockConsole( 04104 IN PCONSOLE_INFORMATION Console 04105 ) 04106 { 04107 LIST_ENTRY WaitQueue; 04108 04109 // 04110 // Make sure the console pointer is still valid 04111 // 04112 ASSERT(NT_SUCCESS(ValidateConsole(Console))); 04113 04114 #ifdef i386 04115 // 04116 // do nothing if we are in screen switching(handshaking with ntvdm) 04117 // we don't check anything else because we are in a safe state here. 04118 // 04119 if (ConsoleVDMOnSwitching == Console && 04120 ConsoleVDMOnSwitching->VDMProcessId == CONSOLE_CLIENTPROCESSID()) { 04121 KdPrint((" UnlockConsole - Thread %lx is leaving VDM CritSec\n", GetCurrentThreadId())); 04122 RtlLeaveCriticalSection(&ConsoleVDMCriticalSection); 04123 return; 04124 } 04125 #endif 04126 04127 // 04128 // if we're about to release the console lock, see if there 04129 // are any satisfied wait blocks that need to be dereferenced. 04130 // this code avoids a deadlock between grabbing the console 04131 // lock and then grabbing the process structure lock. 04132 // 04133 #if defined(_X86_) 04134 if (Console->ConsoleLock.RecursionCount == 1) { 04135 #endif 04136 #if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_) || defined(_IA64_) 04137 if (Console->ConsoleLock.RecursionCount == 0) { 04138 #endif 04139 InitializeListHead(&WaitQueue); 04140 if (Console->WaitQueue) { 04141 CsrMoveSatisfiedWait(&WaitQueue, Console->WaitQueue); 04142 Console->WaitQueue = NULL; 04143 } 04144 ProcessCtrlEvents(Console); 04145 04146 /* 04147 * Can't call CsrDereferenceWait with the console locked or we could deadlock. 04148 */ 04149 if (!IsListEmpty(&WaitQueue)) { 04150 CsrDereferenceWait(&WaitQueue); 04151 } 04152 } else { 04153 RtlLeaveCriticalSection(&Console->ConsoleLock); 04154 } 04155 } 04156 04157 ULONG 04158 ShutdownConsole( 04159 IN HANDLE ConsoleHandle, 04160 IN DWORD dwFlags 04161 ) 04162 /* 04163 returns TRUE if console shutdown. we recurse here so we don't 04164 return from the WM_QUERYENDSESSION until the console is gone. 04165 04166 */ 04167 04168 { 04169 DWORD EventFlag; 04170 int WaitForShutdown; 04171 PCONSOLE_INFORMATION Console; 04172 04173 EventFlag = 0; 04174 04175 // 04176 // Transmit the force bit (meaning don't bring up the retry dialog 04177 // if the app times out. 04178 // 04179 04180 if (dwFlags & EWX_FORCE) 04181 EventFlag |= CONSOLE_FORCE_SHUTDOWN_FLAG; 04182 04183 // 04184 // Remember if this is shutdown or logoff - inquiring apps want to know. 04185 // 04186 04187 if (dwFlags & EWX_SHUTDOWN) { 04188 EventFlag |= CONSOLE_CTRL_SHUTDOWN_FLAG; 04189 } else { 04190 EventFlag |= CONSOLE_CTRL_LOGOFF_FLAG; 04191 } 04192 04193 // 04194 // see if console already going away 04195 // 04196 04197 if (!NT_SUCCESS(RevalidateConsole(ConsoleHandle, &Console))) { 04198 KdPrint(("CONSRV: Shutting down terminating console\n")); 04199 return SHUTDOWN_KNOWN_PROCESS; 04200 } 04201 04202 Console->Flags |= CONSOLE_SHUTTING_DOWN; 04203 Console->CtrlFlags = EventFlag; 04204 Console->LimitingProcessId = 0; 04205 04206 WaitForShutdown = ProcessCtrlEvents(Console); 04207 if (WaitForShutdown == CONSOLE_SHUTDOWN_SUCCEEDED) { 04208 return (ULONG)STATUS_PROCESS_IS_TERMINATING; 04209 } else { 04210 if (!NT_SUCCESS(RevalidateConsole(ConsoleHandle, &Console))) { 04211 return SHUTDOWN_KNOWN_PROCESS; 04212 } 04213 Console->Flags &= ~CONSOLE_SHUTTING_DOWN; 04214 UnlockConsole(Console); 04215 if (WaitForShutdown == CONSOLE_SHUTDOWN_SYSTEM) { 04216 return SHUTDOWN_KNOWN_PROCESS; 04217 } else { 04218 return SHUTDOWN_CANCEL; 04219 } 04220 } 04221 } 04222 04223 VOID UserExitWorkerThread(VOID) 04224 04225 /*++ 04226 04227 Routine Description: 04228 04229 The current thread can exit using ExitThread. 04230 04231 ExitThread is the prefered method of exiting a thread. When this 04232 API is called (either explicitly or by returning from a thread 04233 procedure), The current thread's stack is deallocated and the thread 04234 terminates. If the thread is the last thread in the process when 04235 this API is called, the behavior of this API does not change. DLLs 04236 are not notified as a result of a call to ExitThread. 04237 04238 Arguments: 04239 04240 dwExitCode - Supplies the termination status for the thread. 04241 04242 Return Value: 04243 04244 None. 04245 04246 --*/ 04247 04248 { 04249 MEMORY_BASIC_INFORMATION MemInfo; 04250 NTSTATUS st; 04251 VOID SwitchStackThenTerminate(PVOID CurrentStack, PVOID NewStack, DWORD ExitCode); 04252 04253 st = NtQueryVirtualMemory( 04254 NtCurrentProcess(), 04255 NtCurrentTeb()->NtTib.StackLimit, 04256 MemoryBasicInformation, 04257 (PVOID)&MemInfo, 04258 sizeof(MemInfo), 04259 NULL 04260 ); 04261 if ( !NT_SUCCESS(st) ) { 04262 RtlRaiseStatus(st); 04263 } 04264 04265 SwitchStackThenTerminate( 04266 MemInfo.AllocationBase, 04267 &NtCurrentTeb()->UserReserved[0], 04268 0 04269 ); 04270 } 04271 04272 VOID FreeStackAndTerminate( 04273 IN PVOID OldStack, 04274 IN DWORD ExitCode) 04275 04276 /*++ 04277 04278 Routine Description: 04279 04280 This API is called during thread termination to delete a thread's 04281 stack and then terminate. 04282 04283 Arguments: 04284 04285 OldStack - Supplies the address of the stack to free. 04286 04287 ExitCode - Supplies the termination status that the thread 04288 is to exit with. 04289 04290 Return Value: 04291 04292 None. 04293 04294 --*/ 04295 04296 { 04297 NTSTATUS Status; 04298 SIZE_T Zero; 04299 PVOID BaseAddress; 04300 04301 Zero = 0; 04302 BaseAddress = OldStack; 04303 04304 Status = NtFreeVirtualMemory( 04305 NtCurrentProcess(), 04306 &BaseAddress, 04307 &Zero, 04308 MEM_RELEASE 04309 ); 04310 ASSERT(NT_SUCCESS(Status)); 04311 04312 // 04313 // Don't worry, no commenting precedent has been set by SteveWo. this 04314 // comment was added by an innocent bystander. 04315 // 04316 // NtTerminateThread will return if this thread is the last one in 04317 // the process. So ExitProcess will only be called if that is the 04318 // case. 04319 // 04320 04321 NtTerminateThread(NULL,(NTSTATUS)ExitCode); 04322 }

Generated on Sat May 15 19:40:23 2004 for test by doxygen 1.3.7