Recent

Author Topic: [SOLVED] How to detect keyboard layout?  (Read 2360 times)

CM630

  • Hero Member
  • *****
  • Posts: 857
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: [SOLVED] How to detect keyboard layout?
« Reply #15 on: December 06, 2018, 12:50:30 pm »
Here is my code. It works fine as long as I do not focus another window. Then it starts acting oddly.
When I change layouts in another windows, indication in Label1 stays unchanged (for example 128). When I mouse mouse over it, it changes... sometimes.
I tried to change KetKeyboardState with GetKeyState- still not working.

I change layouts with alt+shift. I also tried changing with the mouse- so it is not an issue of Alt+Shift modifying something.

Also, there is a huge bug (possibly labelled as a „feature‟) in Windows- it does not remember key layout globally, but separately for each window.
Maybe that adds to the keyboard detection issue.

But it seems to me that GetKeyboardState does not work globally, but only for the focuses/active app.
« Last Edit: December 07, 2018, 09:54:30 am by CM630 »
Лазар 1,8,2;W7 64bit or XP 32bit;FPC3,0,4;rev 57369

GetMem

  • Hero Member
  • *****
  • Posts: 3255
Re: [SOLVED] How to detect keyboard layout?
« Reply #16 on: December 06, 2018, 05:38:17 pm »
OK, the issue was far more complex then I initially thought. To correctly get the keyboard layout, we must attach the input processing mechanism of our main thread to the thread that gets keyboard input, usually the one belonging to foreground window. Please test attached project, as far as I can tell it's working correctly now. If the input language differ from English, the "Scroll Lock" is activated(ON). I commented the code as much as possible:
Code: Pascal  [Select]
  1. procedure TForm1.tmWaitTimer(Sender: TObject);
  2. var
  3.   ActiveWindow: HWND;
  4.   ActiveThreadID: DWord;
  5.   KeyBoardLayOut: HKL;
  6.   Lang: array[0..2] of Char;
  7.   KeyState: Integer;
  8.   LangStr: String;
  9. begin
  10.   //turn on/off our "leds", similar to the keyboard leds for Num Lock, Caps Lock, Scroll Lock
  11.   im.GetBitmap(GetState(VK_NUMLOCK), imNumLock.Picture.Bitmap);
  12.   im.GetBitmap(GetState(VK_CAPITAL), imCapsLock.Picture.Bitmap);
  13.   im.GetBitmap(GetState(VK_SCROLL), imScrollLock.Picture.Bitmap);
  14.  
  15.   //get foreground window, the window attached to the calling thread that gets input
  16.   ActiveWindow := GetForegroundWindow;
  17.   //get active thread ID
  18.   ActiveThreadID := GetWindowThreadProcessId(ActiveWindow, nil);
  19.   if (ActiveThreadID <> OldActiveThreadID) and (ActiveThreadID <> GetCurrentThreadID) then
  20.   begin
  21.     //detach old
  22.     AttachThreadInput(GetCurrentThreadID, OldActiveThreadID, False);
  23.     //attach thread input, for system processes this is not possible(ActiveThreadID --> 0)
  24.     if not AttachThreadInput(GetCurrentThreadID, ActiveThreadID, True) then
  25.       ActiveThreadID := 0;
  26.     //reset old threadid
  27.     OldActiveThreadID := ActiveThreadID;
  28.   end;
  29.  
  30.   if ActiveThreadID > 0 then
  31.   begin
  32.     //get kebyoard layout and language with the
  33.     KeyBoardLayOut := GetKeyboardLayout(ActiveThreadID);
  34.     GetLocaleInfo(LoWord(KeyBoardLayOut), LOCALE_SENGLANGUAGE, Lang, 2);
  35.     if Length(Lang) > 0 then
  36.     begin
  37.       SetString(LangStr, PChar(@Lang[0]), Length(Lang));
  38.       LangStr := LeftStr(UpperCase(LangStr), 2);
  39.     end;
  40.   end;
  41.   //get keystate
  42.   KeyState := GetKeyState(VK_SCROLL);
  43.  
  44.   //togle scroll lock according to the specification
  45.   if ((OldLangStr = 'EN') and (LangStr <> 'EN') and (KeyState = 0)) or
  46.       ((OldLangStr <> 'EN') and (LangStr= 'EN') and (KeyState = 1)) or
  47.        ((OldLangStr <> 'EN') and (LangStr <> 'EN') and (KeyState = 0)) or
  48.         ((OldLangStr = 'EN') and (LangStr = 'EN') and (KeyState = 1)) then
  49.            SetState(VK_SCROLL, 45);
  50.   //reset old langugage string
  51.   if OldLangStr <> LangStr then
  52.     OldLangStr := LangStr;
  53. end;

CM630

  • Hero Member
  • *****
  • Posts: 857
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: [SOLVED] How to detect keyboard layout?
« Reply #17 on: December 07, 2018, 11:23:08 am »
Thanks, as far as I tried it it seems to work fine.
But all seems to be in vain, because... pressing a Lock key when Alt+Tab dialog is open closes the dialog !?! and makes Alt+Tab unusable  >:(
Лазар 1,8,2;W7 64bit or XP 32bit;FPC3,0,4;rev 57369

GetMem

  • Hero Member
  • *****
  • Posts: 3255
Re: [SOLVED] How to detect keyboard layout?
« Reply #18 on: December 07, 2018, 12:09:24 pm »
Thanks, as far as I tried it it seems to work fine.
But all seems to be in vain, because... pressing a Lock key when Alt+Tab dialog is open closes the dialog !?! and makes Alt+Tab unusable  >:(
On my win10 nothing happens when I press Alt +Tab combined with a Lock key. Everything works as it should. What is your OS win7 or xp?

CM630

  • Hero Member
  • *****
  • Posts: 857
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: [SOLVED] How to detect keyboard layout?
« Reply #19 on: December 07, 2018, 12:44:44 pm »
It is Win7. Also- when I try to open an application with a popup menu from the taskbar (for example MS Word with more than 2 documents open in it)- the popup is gone when a lock key is toggled, so I have no way to show the desired application.
Лазар 1,8,2;W7 64bit or XP 32bit;FPC3,0,4;rev 57369

GetMem

  • Hero Member
  • *****
  • Posts: 3255
Re: [SOLVED] How to detect keyboard layout?
« Reply #20 on: December 07, 2018, 05:41:23 pm »
But all seems to be in vain, because... pressing a Lock key when Alt+Tab dialog is open closes the dialog !?! and makes Alt+Tab unusable  >:(
I can reproduce the issue with win7, but the same is true when the test application(the one I attached in my previous post) is not running. So I guess it's a standard behaviour in win7. Setting Scroll Lock in a remote application is an "abusive" move, personally I don't like it. By the way you can detect with a low level keyboard hook when Alt+Tab is pressed, then stop the timer in your application.

CM630

  • Hero Member
  • *****
  • Posts: 857
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: [SOLVED] How to detect keyboard layout?
« Reply #21 on: December 10, 2018, 12:19:54 pm »

But all seems to be in vain, because... pressing a Lock key when Alt+Tab dialog is open closes the dialog !?! and makes Alt+Tab unusable  >:(

...but the same is true when the test application(the one I attached in my previous post) is not running...

Exactly.

So I guess it's a standard behaviour in win7. Setting Scroll Lock in a remote application is an "abusive" move, personally I don't like it. By the way you can detect with a low level keyboard hook when Alt+Tab is pressed, then stop the timer in your application.

Actually, the only right decision I could think of is:
   1. Disable Window's own keyboard switched.
   2. Assign alt+shift to a (Lazarus) app.

   3. When alt+shift is pressed, keyboard layout is changed. Either:
       3,1. all active apps shall be sought and their layout should be changed to the selected one.
       3,3. when app is changed/ timer ticks selected layout shall be applied to the active window/app.
   Solution 3,1 won't probably work, because it won't be useful for newly open app.
   4. When layout is changed by step 3, ScrollLock might me toggled.


I will leave it for some future times.
« Last Edit: December 10, 2018, 12:35:23 pm by CM630 »
Лазар 1,8,2;W7 64bit or XP 32bit;FPC3,0,4;rev 57369