[System.Security.SecurityCritical] // auto-generated private static bool IsModKey(Interop.InputRecord ir) { // We should also skip over Shift, Control, and Alt, as well as caps lock. // Apparently we don't need to check for 0xA0 through 0xA5, which are keys like // Left Control & Right Control. See the ConsoleKey enum for these values. short keyCode = ir.keyEvent.virtualKeyCode; return((keyCode >= 0x10 && keyCode <= 0x12) || keyCode == 0x14 || keyCode == 0x90 || keyCode == 0x91); }
public static ConsoleKeyInfo ReadKey(bool intercept) { Interop.InputRecord ir; int numEventsRead = -1; bool r; lock (s_readKeySyncObject) { if (_cachedInputRecord.eventType == Interop.KEY_EVENT) { // We had a previous keystroke with repeated characters. ir = _cachedInputRecord; if (_cachedInputRecord.keyEvent.repeatCount == 0) _cachedInputRecord.eventType = -1; else { _cachedInputRecord.keyEvent.repeatCount--; } // We will return one key from this method, so we decrement the // repeatCount here, leaving the cachedInputRecord in the "queue". } else { // We did NOT have a previous keystroke with repeated characters: while (true) { r = Interop.Kernel32.ReadConsoleInput(InputHandle, out ir, 1, out numEventsRead); if (!r || numEventsRead == 0) { // This will fail when stdin is redirected from a file or pipe. // We could theoretically call Console.Read here, but I // think we might do some things incorrectly then. throw new InvalidOperationException(SR.InvalidOperation_ConsoleReadKeyOnFile); } short keyCode = ir.keyEvent.virtualKeyCode; // First check for non-keyboard events & discard them. Generally we tap into only KeyDown events and ignore the KeyUp events // but it is possible that we are dealing with a Alt+NumPad unicode key sequence, the final unicode char is revealed only when // the Alt key is released (i.e when the sequence is complete). To avoid noise, when the Alt key is down, we should eat up // any intermediate key strokes (from NumPad) that collectively forms the Unicode character. if (!IsKeyDownEvent(ir)) { // REVIEW: Unicode IME input comes through as KeyUp event with no accompanying KeyDown. if (keyCode != AltVKCode) continue; } char ch = (char)ir.keyEvent.uChar; // In a Alt+NumPad unicode sequence, when the alt key is released uChar will represent the final unicode character, we need to // surface this. VirtualKeyCode for this event will be Alt from the Alt-Up key event. This is probably not the right code, // especially when we don't expose ConsoleKey.Alt, so this will end up being the hex value (0x12). VK_PACKET comes very // close to being useful and something that we could look into using for this purpose... if (ch == 0) { // Skip mod keys. if (IsModKey(ir)) continue; } // When Alt is down, it is possible that we are in the middle of a Alt+NumPad unicode sequence. // Escape any intermediate NumPad keys whether NumLock is on or not (notepad behavior) ConsoleKey key = (ConsoleKey)keyCode; if (IsAltKeyDown(ir) && ((key >= ConsoleKey.NumPad0 && key <= ConsoleKey.NumPad9) || (key == ConsoleKey.Clear) || (key == ConsoleKey.Insert) || (key >= ConsoleKey.PageUp && key <= ConsoleKey.DownArrow))) { continue; } if (ir.keyEvent.repeatCount > 1) { ir.keyEvent.repeatCount--; _cachedInputRecord = ir; } break; } } // we did NOT have a previous keystroke with repeated characters. } ControlKeyState state = (ControlKeyState)ir.keyEvent.controlKeyState; bool shift = (state & ControlKeyState.ShiftPressed) != 0; bool alt = (state & (ControlKeyState.LeftAltPressed | ControlKeyState.RightAltPressed)) != 0; bool control = (state & (ControlKeyState.LeftCtrlPressed | ControlKeyState.RightCtrlPressed)) != 0; ConsoleKeyInfo info = new ConsoleKeyInfo((char)ir.keyEvent.uChar, (ConsoleKey)ir.keyEvent.virtualKeyCode, shift, alt, control); if (!intercept) Console.Write(ir.keyEvent.uChar); return info; }
public static ConsoleKeyInfo ReadKey(bool intercept) { Interop.InputRecord ir; int numEventsRead = -1; bool r; lock (s_readKeySyncObject) { if (_cachedInputRecord.eventType == Interop.KEY_EVENT) { // We had a previous keystroke with repeated characters. ir = _cachedInputRecord; if (_cachedInputRecord.keyEvent.repeatCount == 0) { _cachedInputRecord.eventType = -1; } else { _cachedInputRecord.keyEvent.repeatCount--; } // We will return one key from this method, so we decrement the // repeatCount here, leaving the cachedInputRecord in the "queue". } else { // We did NOT have a previous keystroke with repeated characters: while (true) { r = Interop.mincore.ReadConsoleInput(InputHandle, out ir, 1, out numEventsRead); if (!r || numEventsRead == 0) { // This will fail when stdin is redirected from a file or pipe. // We could theoretically call Console.Read here, but I // think we might do some things incorrectly then. throw new InvalidOperationException(SR.InvalidOperation_ConsoleReadKeyOnFile); } short keyCode = ir.keyEvent.virtualKeyCode; // First check for non-keyboard events & discard them. Generally we tap into only KeyDown events and ignore the KeyUp events // but it is possible that we are dealing with a Alt+NumPad unicode key sequence, the final unicode char is revealed only when // the Alt key is released (i.e when the sequence is complete). To avoid noise, when the Alt key is down, we should eat up // any intermediate key strokes (from NumPad) that collectively forms the Unicode character. if (!IsKeyDownEvent(ir)) { // REVIEW: Unicode IME input comes through as KeyUp event with no accompanying KeyDown. if (keyCode != AltVKCode) { continue; } } char ch = (char)ir.keyEvent.uChar; // In a Alt+NumPad unicode sequence, when the alt key is released uChar will represent the final unicode character, we need to // surface this. VirtualKeyCode for this event will be Alt from the Alt-Up key event. This is probably not the right code, // especially when we don't expose ConsoleKey.Alt, so this will end up being the hex value (0x12). VK_PACKET comes very // close to being useful and something that we could look into using for this purpose... if (ch == 0) { // Skip mod keys. if (IsModKey(ir)) { continue; } } // When Alt is down, it is possible that we are in the middle of a Alt+NumPad unicode sequence. // Escape any intermediate NumPad keys whether NumLock is on or not (notepad behavior) ConsoleKey key = (ConsoleKey)keyCode; if (IsAltKeyDown(ir) && ((key >= ConsoleKey.NumPad0 && key <= ConsoleKey.NumPad9) || (key == ConsoleKey.Clear) || (key == ConsoleKey.Insert) || (key >= ConsoleKey.PageUp && key <= ConsoleKey.DownArrow))) { continue; } if (ir.keyEvent.repeatCount > 1) { ir.keyEvent.repeatCount--; _cachedInputRecord = ir; } break; } } // we did NOT have a previous keystroke with repeated characters. } ControlKeyState state = (ControlKeyState)ir.keyEvent.controlKeyState; bool shift = (state & ControlKeyState.ShiftPressed) != 0; bool alt = (state & (ControlKeyState.LeftAltPressed | ControlKeyState.RightAltPressed)) != 0; bool control = (state & (ControlKeyState.LeftCtrlPressed | ControlKeyState.RightCtrlPressed)) != 0; ConsoleKeyInfo info = new ConsoleKeyInfo((char)ir.keyEvent.uChar, (ConsoleKey)ir.keyEvent.virtualKeyCode, shift, alt, control); if (!intercept) { Console.Write(ir.keyEvent.uChar); } return(info); }
[System.Security.SecurityCritical] // auto-generated private static bool IsAltKeyDown(Interop.InputRecord ir) { return((((ControlKeyState)ir.keyEvent.controlKeyState) & (ControlKeyState.LeftAltPressed | ControlKeyState.RightAltPressed)) != 0); }
[System.Security.SecurityCritical] // auto-generated private static bool IsKeyDownEvent(Interop.InputRecord ir) { return(ir.eventType == Interop.KEY_EVENT && ir.keyEvent.keyDown); }