delphikeyboard-layouttthread

How to use LoadKeyboardLayout in a background thread?


I'm using the LoadKeyboardLayout function to load and activate the keyboard layout this way:

procedure TfrmMain.eSearchEnter(Sender: TObject);
begin
  LoadKeyboardLayout('00000429', KLF_ACTIVATE);
end;

It works perfectly, but it freezes the active form for 1-2 seconds, since this change takes some time. For preventing this, I've moved this code to a background thread like this:

type
  FLangChangeThread = class(TThread)
  private
    FLang: string;
  protected
    procedure Execute; override;
  public
    property Lang: string read FLang write FLang;
  end;

implementation

procedure FLangChangeThread.Execute;
begin
  if FLang = 'EN' then
    LoadKeyboardLayout('00000409', KLF_ACTIVATE)
  else
  if FLang = 'FA' then
    LoadKeyboardLayout('00000429', KLF_ACTIVATE);
end;

This background thread I'm then running this way:

procedure TfrmMain.ChangeWritingLanguage(ALang: string);
begin
  with FLangChangeThread.Create(True) do
  begin
    FreeOnTerminate := True;
    Lang := ALang;
    Resume;
  end;
end;

procedure TfrmMain.eSearchEnter(Sender: TObject);
begin
  ChangeWritingLanguage('FA');
end;

The problem is, that it doesn't change the keyboard layout as expected. I've debugged the code and all lines were execeuted; just the LoadKeyboardLayout function hasn't made its job.

How can I make the LoadKeyboardLayout function work from a background thread ?


Solution

  • First of all, you should check the result of the LoadKeyboardLayout function and if it fails, you should check the error returned by the GetLastError function to determine what is wrong.

    But even if this function call succeed, it will activate the input locale identifier, but for your worker thread. As the LoadKeyboardLayout reference states for the KLF_ACTIVATE flag (emphasized by me):

    KLF_ACTIVATE

    If the specified input locale identifier is not already loaded, the function loads and activates the input locale identifier for the current thread.


    Although, if you want to load and activate keyboard layout for the whole process, you may try to combine the KLF_ACTIVATE flag with the KLF_SETFORPROCESS one:

    const
      KLF_SETFORPROCESS = $00000100;
    begin
      if LoadKeyboardLayout('00000429', KLF_ACTIVATE or KLF_SETFORPROCESS) = 0 then
        RaiseLastOSError;
    end;