Pass certain keys to the console using windows messages.
If the terminal is placed in an alternate mode using DECCKM, then we need to generate different input escape sequences for WSL (and other programs using ENABLE_VIRTUAL_TERMINAL_INPUT). AFAIK, there is no way for winpty to detect whether an alternate mode is enabled, but it only seems to affect a small number of keys, so send those keys as window messages. We don't send *all* keys as window messages, because the console may try to interpret some of them. It doesn't interpret the arrow keys and Home/End, AFAICT, and those seem to be the only keys affected by DECCKM. (The console's line-input mode *does* care about these navigation keys, but in that case, WriteConsoleInput and window messages work equally well.) DECCKM only seems to affect the keys when there is no modifier key. I believe that by using SendMessage, winpty-agent will block until the keys are appended to the console input buffer. I'm not sure how to verify it. If this *weren't* the case, there could be a danger of key input being transposed. It seems unlikely to be an issue. Fixes https://github.com/rprichard/winpty/issues/90
This commit is contained in:
parent
27dfaaefb6
commit
40d5b72c43
@ -1,3 +1,12 @@
|
||||
# Next Version
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* winpty generates more correct input escape sequences for WSL programs that
|
||||
enable an alternate input mode using DECCKM. This bug affected arrow keys
|
||||
and Home/End in WSL programs such as `vim`, `mc`, and `less`.
|
||||
[#90](https://github.com/rprichard/winpty/issues/90)
|
||||
|
||||
# Version 0.4.1 (2017-01-03)
|
||||
|
||||
Bug fixes:
|
||||
|
@ -208,7 +208,8 @@ Agent::Agent(LPCWSTR controlPipeName,
|
||||
m_console.setTitle(m_currentTitle);
|
||||
|
||||
const HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
m_consoleInput.reset(new ConsoleInput(conin, m_mouseMode, *this));
|
||||
m_consoleInput.reset(
|
||||
new ConsoleInput(conin, m_mouseMode, *this, m_console));
|
||||
|
||||
// Setup Ctrl-C handling. First restore default handling of Ctrl-C. This
|
||||
// attribute is inherited by child processes. Then register a custom
|
||||
|
@ -191,7 +191,9 @@ static int matchMouseRecord(const char *input, int inputSize, MouseRecord &out)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ConsoleInput::ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender) :
|
||||
ConsoleInput::ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender,
|
||||
Win32Console &console) :
|
||||
m_console(console),
|
||||
m_conin(conin),
|
||||
m_mouseMode(mouseMode),
|
||||
m_dsrSender(dsrSender)
|
||||
@ -594,15 +596,39 @@ void ConsoleInput::appendKeyPress(std::vector<INPUT_RECORD> &records,
|
||||
const bool ctrl = (keyState & LEFT_CTRL_PRESSED) != 0;
|
||||
const bool alt = (keyState & LEFT_ALT_PRESSED) != 0;
|
||||
const bool shift = (keyState & SHIFT_PRESSED) != 0;
|
||||
bool hasDebugInput = false;
|
||||
|
||||
if (isTracingEnabled()) {
|
||||
static bool debugInput = hasDebugFlag("input");
|
||||
if (debugInput) {
|
||||
hasDebugInput = true;
|
||||
InputMap::Key key = { virtualKey, codePoint, keyState };
|
||||
trace("keypress: %s", key.toString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_escapeInputEnabled &&
|
||||
(virtualKey == VK_UP ||
|
||||
virtualKey == VK_DOWN ||
|
||||
virtualKey == VK_LEFT ||
|
||||
virtualKey == VK_RIGHT ||
|
||||
virtualKey == VK_HOME ||
|
||||
virtualKey == VK_END) &&
|
||||
!ctrl && !alt && !shift) {
|
||||
if (hasDebugInput) {
|
||||
trace("sending keypress to console HWND");
|
||||
}
|
||||
uint32_t scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
|
||||
if (scanCode > 255) {
|
||||
scanCode = 0;
|
||||
}
|
||||
SendMessage(m_console.hwnd(), WM_KEYDOWN, virtualKey,
|
||||
(scanCode << 16) | 1u);
|
||||
SendMessage(m_console.hwnd(), WM_KEYUP, virtualKey,
|
||||
(scanCode << 16) | (1u | (1u << 30) | (1u << 31)));
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t stepKeyState = 0;
|
||||
if (ctrl) {
|
||||
stepKeyState |= LEFT_CTRL_PRESSED;
|
||||
|
@ -38,7 +38,8 @@ class DsrSender;
|
||||
class ConsoleInput
|
||||
{
|
||||
public:
|
||||
ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender);
|
||||
ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender,
|
||||
Win32Console &console);
|
||||
void writeInput(const std::string &input);
|
||||
void flushIncompleteEscapeCode();
|
||||
void setMouseWindowRect(SmallRect val) { m_mouseWindowRect = val; }
|
||||
@ -79,6 +80,7 @@ private:
|
||||
DWORD inputConsoleMode();
|
||||
|
||||
private:
|
||||
Win32Console &m_console;
|
||||
HANDLE m_conin = nullptr;
|
||||
int m_mouseMode = 0;
|
||||
DsrSender &m_dsrSender;
|
||||
|
Loading…
Reference in New Issue
Block a user