-
Notifications
You must be signed in to change notification settings - Fork 317
Fix control symbols when changing layout #3078
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
Conversation
PSReadLine/Keys.cs
Outdated
@@ -147,7 +157,8 @@ internal static void TryGetCharFromConsoleKey(ConsoleKeyInfo key, ref char resul | |||
{ | |||
flags |= (1 << 2); /* If bit 2 is set, keyboard state is not changed (Windows 10, version 1607 and newer) */ | |||
} | |||
int charCount = ToUnicode(virtualKey, scanCode, state, chars, chars.Length, flags); | |||
uint layout = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), 0)); |
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.
This always felt like a bug in console applications. I believe the conhost process receives the keyboard layout change notifications, but the ToUnicode
call happens in a different process that never sees layout change notifications. I may have even opened a bug on ToUnicode
that might have been resolved as won't fix over concerns about breaking something.
This change may seem work well enough in practice, but there is a race condition:
- Type a character
- New popup window gets created by some background process
- Call to
GetForegroundWindow
sees this new window instead of the console/vscode/etc. window.
I'm also not excited about seeing GetWindowThreadProcessId
called on every key - it seems like it should be cached. Or maybe better - can we find the conhost/openconsole process instead? That process should see the correct layout, right?
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.
@lzybkr I create replacement for GetForegroundWindow. What do you think about it?
// aka GetForegroundWindow
static Process findParentWithWindowHandle()
{
var current = Process.GetCurrentProcess();
while (current != null)
{
if (current.MainWindowHandle != IntPtr.Zero)
{
break;
}
current = GetParentProcess(current.Handle);
}
return current;
}
static Process GetParentProcess(IntPtr handle)
{
ProcessInformation processInformation = new ProcessInformation();
int returnLength;
int status = NtQueryInformationProcess(handle, 0, ref processInformation, Marshal.SizeOf(processInformation), out returnLength);
if (status != 0)
throw new Win32Exception(status);
try
{
return Process.GetProcessById(processInformation.InheritedFromUniqueProcessId.ToInt32());
}
catch (ArgumentException)
{
// not found
return null;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation
{
internal IntPtr Reserved1;
internal IntPtr PebBaseAddress;
internal IntPtr Reserved2_0;
internal IntPtr Reserved2_1;
internal IntPtr UniqueProcessId;
internal IntPtr InheritedFromUniqueProcessId;
}
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.
That looks like it would work well in Windows Terminal, VSCode, and the ISE, but it won't work with conhost because the parent will be explorer. conhost.exe is a sibling process.
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 wonder if you can use something like GetProcessHandle(GetConsoleWindow()) to get the correct conhost process - I expect this wouldn't work in Windows Terminal.
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 research this theme deeper and find out that all approaches that find window that subsribed to locale change does not work in all situations.
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 found that replacing https://github.com/PowerShell/PSReadLine/pull/3078/files#diff-9ab1ecb1e5d0ebd879a483eada4f6fcf2b407c662752f52bea29e45fd143f1a5R242
to c == '\0' do not break test.
And so far i didn't find dead key what start with different from '\0' code. Can it help?
This is all what can i do. Better solution immposible with my skills. |
@DHowett - maybe you have some insights here? |
Adding this to my list for tomorrow. My team is starting talent reviews, so I can't promise that I'll get to it timely. |
any update? |
bump |
How can i build custom verion of PSReadLine and install to PS? |
Hello, is there a working solution now? |
|
Hello, how soon can you check it out? |
Superseded by #3786. See #3786 (comment) for the proposal to solve the two concerns raised in #3078 (comment). |
PR Summary
toUnicode sticks with first encoutered locale. During some research i use toUnicodeEx and provide current used locale to it.
Resolve #2865
PR Checklist
Microsoft Reviewers: Open in CodeFlow