-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Control+Space not sent to program running in terminal #16298
Conversation
a195939
to
3b31f63
Compare
This is a test program written in go: package main
import (
"fmt"
"os"
"syscall"
"golang.org/x/sys/windows"
"golang.org/x/term"
)
func main() {
inHandle, err := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
if err != nil {
fmt.Printf("GetStdHandle: %v\r\n", err)
return
}
var inMode uint32
if err := windows.GetConsoleMode(windows.Handle(inHandle), &inMode); err != nil {
fmt.Printf("GetConsoleMode: %v\r\n", err)
return
}
defer windows.SetConsoleMode(windows.Handle(inHandle), inMode)
if err := windows.SetConsoleMode(windows.Handle(inHandle), inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
fmt.Printf("SetConsoleMode: %v\r\n", err)
return
}
state, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
fmt.Printf("MakeRaw: %v\r\n", err)
return
}
defer term.Restore(int(os.Stdin.Fd()), state)
buf := make([]byte, 100)
for {
n, err := os.Stdin.Read(buf)
if err != nil {
fmt.Printf("os.Stdin.Read(buf): %v\r\n", err)
return
}
if n > 0 {
fmt.Printf("%v\r\n", buf[:n])
} else {
fmt.Println("nil")
}
if n == 1 && buf[0] == '\x03' {
return
}
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a tiny nit.
I think we can pull this if
block out of the loop if we assume NUL
always comes as a single wchar_t
:
// If the text is just a null character, synthesize a key event that
// exactly matches the null key event.
if (const auto wch = til::at(text, 0); wch == UNICODE_NULL)
{
const auto zeroKey = OneCoreSafeVkKeyScanW(0);
const auto vkey = LOWORD(zeroKey);
uint32_t modifiers = 0;
if (WI_IsFlagSet(zeroKey, 0x100))
{
modifiers |= SHIFT_PRESSED;
}
if (WI_IsFlagSet(zeroKey, 0x200))
{
modifiers |= CTRL_PRESSED;
}
if (WI_IsFlagSet(zeroKey, 0x400))
{
modifiers |= ALT_PRESSED;
}
_storage.push_back(SynthesizeKeyEvent(true, 1, vkey, 0, wch, modifiers));
return;
}
for (const auto& wch : text)
{
_storage.push_back(SynthesizeKeyEvent(true, 1, 0, 0, wch, 0));
}
Haven't tested the code so take it with a grain of salt 😅
@tusharsnx Do we need to do it before the for loop? Is it possible that it is an input simulated by another program? |
My thought process is that we process one Since a null |
@tusharsnx Is it the same if we do it in the for loop? There are two more instructions ( test and jmp ) in each loop. But the performance impact should be negligible. Doing in the for loop also brings benefits: If some places are modified in the future, it will be compatible here. |
I'm fairly sure you could also get a string like |
I get |
FWIW I personally don't think this is the right approach, as it just works around the if condition in Lines 234 to 244 in cc2ba53
Additionally, it introduces a disparity between how Unfortunately, I can't really criticize this PR for it, because the framework for "my way" doesn't exist yet. Right now, std::deque<INPUT_RECORD> This is fairly limiting for us, because it requires us to translate raw strings into struct StringRecord {
std::wstring str;
size_t consumed = 0;
}; so that we can have a std::deque<std::variant<INPUT_RECORD, StringRecord>> That way we can store inputs like the above as their raw strings and extract them them as raw strings without any uncertainty over whether any given I'm marking this for our upcoming (internal) discussion, because I'm curious what others think about this. |
@lhecker Consider it a temporary solution until |
Oh yeah, please don't get me wrong: I do think it's acceptable in the meantime. The only thing I find somewhat concerning is the vkey thing I mentioned. But I'm not entirely sure how important that is. |
@lhecker You may want to check terminal/src/terminal/input/terminalInput.cpp Lines 610 to 646 in cc2ba53
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, and wait for the discussion to be over, I think it'll be helpful in guiding any additional changes we might require.
@lonnywong Thanks for the PR! This not only fixes the mentioned issue but also highlights a much needed change in the inputBuffer
to disambiguate a VT-translated input vs an actual KeyEvent. 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm in agreement with lhecker that it would be better if we could get rid of these translations altogether, but if that's not likely to happen soon, this PR seems like a reasonable short term fix.
@tusharsnx @j4james Thanks for your help. Is it okay to be merged? |
@lonnywong You'll need approvals from two of the core team members to get the PR merged. Approval from outside contributors doesn't usually count. And I think lhecker was saying that they were going to discuss this issue internally before making a decision. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lhecker brought this up with the team today, and while it does introduce another special case translation I think I'm okay with it. We should try to solve the problem all-up at some future point...
Thanks for all the discussion @j4james and the review notes @tusharsnx 😄
@lonnywong thanks for your contribution as well, of course! |
I am really bad at following PRs to their release ;) is this something that has landed? if not, any ideas when it will? I would like to be able to confirm the fix solved the problem as I have this problem using neovim in windows terminal. Thanks! |
I found the canary branch and I installed that and the control-space issue does not seem to be solved for my case using neovim at least. Should this fix be expected to be landed in the canary branch by now? Thanks! |
@GitMurf Which version of |
@GitMurf Are you using nvim locally, without ssh? |
@lonnywong i am not using ssh. Just straight nvim.exe locally. For example I currently am using the nightly build using the zip source from here: https://github.com/neovim/neovim/releases/tag/nightly What do you mean about switching input methods? |
Seems like this is the release that includes the fix https://github.com/microsoft/terminal/releases/tag/v1.20.10293.0 |
@GitMurf
i think what they were talking about was that |
Converts null byte to specific input event, so that it's properly delivered to the program running in the terminal.
Closes #15939