-
Notifications
You must be signed in to change notification settings - Fork 287
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
Windows keyboard layout handling: get the current layout from the parent terminal process #3786
Windows keyboard layout handling: get the current layout from the parent terminal process #3786
Conversation
Friendly ping. Folks, could you please help with the review here? |
5bfd94f
to
e8c26ae
Compare
e8c26ae
to
05836c5
Compare
@jazzdelightsme, if you have time, can you please help review this PR? Thanks! |
It's been a very long time since I last looked at this problem, but the code and approach seem sound to me. It'd be nice to see it fixed for conhost since folks still use it, but knowing the problem is fixed in Windows Terminal might get some folks to switch. |
I am open to ideas on how to fix it for conhost. I've tried googling that but haven't found any working solutions on how to properly extract the active keyboard layout from conhost. All we need is a way to get the active layout for a Just for the record, I use this version of PSReadline daily for the last several releases in VSCode, IntelliJ and Windows Terminal, and the functionality works reliably for me: it never crashed and never misdetected the terminal host. |
I know some experts in this area; I will look into it... |
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.
Have you tried using GetForegroundWindow?
I changed the GetConsoleKeyboardLayout
method to the following and it seems working fine for me to retrieve the current active keyboard layout, even when pwsh is opened in Conhost from cmd.exe.
public static IntPtr? GetConsoleKeyboardLayout()
{
IntPtr handle = GetForegroundWindow();
if (handle != IntPtr.Zero)
{
uint tid = GetWindowThreadProcessId(handle, out _);
if (tid > 0)
{
IntPtr layout = GetKeyboardLayout(tid);
return layout;
}
}
return null;
}
Thanks for your useful feedback! Will take a look tonight. |
…process and get the layout from it
05836c5
to
d54cf58
Compare
d54cf58
to
5e12c53
Compare
@daxian-dbw, thanks for your fantastic feedback. I've applied all the suggestions (the most significant change being the migration to Notably, I no longer can reproduce the issue with |
Thanks for your useful feedback again! I believe I've addressed the suggestions. Please take another look! |
@ForNeVeR I spent 2 days playing with code and decided that we should move back to your
So, I changed the code back and did some polishing. Now, about the
It's not perfect, but I'm afraid there is no perfect solution that can work in all scenarios. |
@daxian-dbw, thank you so much for your help. I can confirm the following observations:
It does not work for:
Generally, for all of my use cases, it works. There's of course some room for improvement, but I believe it is significantly better than without the patch, at least. So, I still vote for merging it, even in the current non-ideal state. Perhaps we could introduce a better fix by introducing keyboard layout options? For me it would be even better if it just forced the English layout, not looking at the current one I use when processing the shortcuts. But that's a different topic, IMO, and even if we introduce such an option, having a heuristic that makes it work by default in more cases is good anyway. |
As far as I remember this problem is only with PSRL, yes? I may have missed something, but is it only for Ctrl-C? If so, is it a consequence of setting the ENABLE_PROCESSED_INPUT flag? What if we remove this flag and set the handler to handle Ctrl+C? |
Yep, correct.
No, it is not. Other shortcuts such as
I've removed the |
It seems I misread ENABLE_PROCESSED_INPUT flag description. I see PSRL clear the flag and system send Ctrl+C to input buffer. So if we set the flag the system will process Ctrl+C and call out callback if we set it. Perhaps this could fix Ctrl+C at least. |
@ForNeVeR Thanks for double verifying all the scenarios. I agree this is the desired improvement even though not perfect. For scenarios where it doesn't work, the old behavior is kept unchanged. I will merge this PR. @iSazonov It's by design for PSReadLine to clear that flag. When editing, PSReadLine wants to capture ctrl+c and handles it in its own way. The issue here is that |
PR Summary
This is my another attempt on #1393, with a different approach this time.
Fixes #1393 in my environment somewhat: we'll use the proper current keyboard layout from the terminal process, which means the
Ctrl+C
will work in English layout and won't work in Cyrillic. But that's a step forward, since before it was not working at all if you started the process in non-English layout.The terminal process lookup is a heuristic (since there's no official way to determine which process provides a terminal for you) and won't work in 100% of cases (because in some convoluted cases, the process/terminal/console ownership structure may be different). But it should be a good and stable improvement for most of the PowerShell use cases.
After we've got the parent terminal process (which I currently define as a parent process in the process tree that has its main window visible), we ask the OS of its current keyboard layout, and then pass it to
ToUnicodeEx
(sinceToUnicode
is hard-coded to always cache the wrong keyboard layout — the one we've called it the first time with).Open issues: this only works well in Windows Terminal, IntelliJ and VSCode, but doesn't work in conhost. Perhaps let's leave it as it is for now?
PR Checklist
Make sure you've added one or more new testsMicrosoft Reviewers: Open in CodeFlow