Language Bar change language in c# .NET

2019-01-27 11:34发布

问题:

TL;DR: Trying to solve the issue that InputLanguage changes the input layout but does not update the Language Bar display.


I am writing a custom plugin for Trados Studio. Part of this is interfacing with languages both in the app itself and in Word, as in this question: List of all available languages for Windows .NET framework

The last problem I seem to cannot solve is that in a part of the code I am using InputLanguage to set the keyboard input to en-US.

To clarify, there is a limited API, so I have to be really inventive in automating certain aspects. The best workable approach was to use the default shortcuts in the application:

  1. First I change the input language to en-US.

  2. Then I send some keys to the application.

  3. Then I change the input language back to what it was before.

  4. Then I show a form.

Here is the code:

//change input language to English
InputLanguage currentLang = InputLanguage.CurrentInputLanguage;
InputLanguage newLang = InputLanguage.FromCulture(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
if (newLang == null)
{
    MessageBox.Show("The Upload Project function requires the En-US keyboard installed.", "Missing keyboard", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
    return;
}
else
{
    InputLanguage.CurrentInputLanguage = newLang;
}

//Save the document
SendKeys.SendWait("^s");

InputLanguage.CurrentInputLanguage = currentLang;

//get url and credentials from a custom input form
string[] psw = UploadData.GetPassword(
    Settings.GetValue("Upload", "Uri", "https://www.scntranslations.org/ws/services"),
    Vars.wsUsername == null ? Settings.GetValue("Upload", "User", "") : Vars.wsUsername,
    Vars.wsPassword == null ? "" : Vars.wsPassword
    );
Application.DoEvents();

The manifestation that I have is that the Language Bar changes with a delay to EN but by the time the form shows up it should be HU yet it stays EN.

However if I test it with Debug.WriteLine(InputLanguage.CurrentInputLanguage.LayoutName) then the output is the correct language (in my case "Hungarian").

Even after the form is hidden, the language remains EN, yet the keyboard types in Hungarian and the Debug.WriteLine(InputLanguage.CurrentInputLanguage.LayoutName) returns "Hungarian".

I looked at dozens of pages on SO and the web and I tried everything I could think of including System.Threading.Thread.Sleep(1000); and Application.DoEvents() and Sendkeys.Flush(), but nothing triggers Windows to update the Language Bar, and I could not find any solution to this issue.

The earlier version of this problem as given in this question: Change keyboard layout from C# code with .NET 4.5.2
I have made this work now fully with the above implementation of the InputLanguage bar this last hick-up.


Can anybody help in:

  1. giving an explanation for this behavior?
  2. suggesting a solution that triggers the update of the Language Bar from C# code?

UPDATE: The code now fully works. I implemented the BlockInput WinAPI.

[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "BlockInput")]
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool BlockInput([System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fBlockIt);

And also turning off the Caps Lock using Win API:

[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

private void TurnOffCapsLock()
{
    if (Control.IsKeyLocked(Keys.CapsLock)) // Checks Capslock is on
    {
        const int KEYEVENTF_EXTENDEDKEY = 0x1;
        const int KEYEVENTF_KEYUP = 0x2;
        NativeMethods.keybd_event(0x14, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
        NativeMethods.keybd_event(0x14, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
        (UIntPtr)0);
    }
}

So what's left really is getting the Language Bar to correctly show the actual current input language.

I do have the option of sending Alt+Shifts, but I really don't want to do that.