kokoye2007 / waitzar

Automatically exported from code.google.com/p/waitzar
Other
0 stars 1 forks source link

Add "positional keys" to Key Magic #118

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
This feature might already be in Key Magic; the ability to grab input based on 
"scan codes" or "physical keys" instead of virtual keys (which change with the 
locale & keyboard). It took a while to look up, so I'm adding the following 
links, to follow up on later:

VkKeyScan:
http://msdn.microsoft.com/en-us/library/ms646329%28VS.85%29.aspx

MapVirtualKeyEx:
http://msdn.microsoft.com/en-us/library/ms646307%28VS.85%29.aspx

A complaint about functionality:
http://blogs.msdn.com/b/michkap/archive/2006/03/26/560595.aspx

Original issue reported on code.google.com by seth.h...@gmail.com on 18 Jun 2010 at 5:30

GoogleCodeExporter commented 9 years ago
Ok, should be relatively easy. The second number is produced by calling:

UINT key2 = MapVirtualKey('Q', MAPVK_VK_TO_VSC);

...etc.

I changed the layout to "French" (manually) between the two dialog boxes; both 
still output positional keys. Yay~

We _could_ add support for MSKLC. But perhaps I'll just build a profile and 
automatically update KeyMagic to a "US" layout. I don't think this is terribly 
wrong; it'll actually INCREASE compatibility for the next release. 

We should be able to update the Virtual Keyboard too, eventually. For now, at 
least we should "auto-US" the keyboard when typing in KeyMagic. 

Original comment by seth.h...@gmail.com on 18 Jun 2010 at 9:02

Attachments:

GoogleCodeExporter commented 9 years ago
We can detect when the input language has changed by processing:
WM_INPUTLANGCHANGE. We can also compare:
  LOWORD(GetKeyboardLayout(0))
..to:
  MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)

At this point, we can generate an "input map" between keys. For example, 'a' on 
the French keyboard maps to 'q' on our "assumed" US keyboard. 

Note that, for the en_US encoding, we should ALWAYS return the default key. (In 
other words, en_US should NOT try to use MapVirtualKey). This way, if there's 
some bizarre conglomerate keyboard install which crashes WaitZar, we can simply 
instruct users to switch to a US keyboard layout first.

Note that RomanInputManagers should not transform keys, since we want users to 
type with whichever layout they are most comfortable.

Original comment by seth.h...@gmail.com on 18 Jun 2010 at 9:17

GoogleCodeExporter commented 9 years ago
Here's what I propose:

  Promote VirtKey into a full class.
  Add a static method, VirtKey::SetLocale(). This is called every time the locale is switched.
  Add a function (or alternative constructor) which takes the current Locale() into account and changes the alphanum value based on this.
  If the Locale is en_US, then don't perform any changes.

That way, we can basically just sprinkle convert() functions on our existing 
vkeys.

But this will have to wait until after the help keyboard is fixed.

Original comment by seth.h...@gmail.com on 18 Jun 2010 at 9:49

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Thanks for the links. I'll make sure that different layouts won't crash 
WaitZar. 

Anyway, thanks for pointing this out; this is the first version of WaitZar that 
uses virtual key codes for letter-based input, so I can fix this bug before the 
official release. :)

Original comment by seth.h...@gmail.com on 18 Jun 2010 at 11:02

GoogleCodeExporter commented 9 years ago
Note: Our approach assumes that the keyboard layout cannot change for the life 
of a VirtKey. This is true (since changing the layout requires generating a 
message) but it also means that we can't hold on to virtual keys past a single 
processing. (This makes sense).

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 11:10

GoogleCodeExporter commented 9 years ago
Fixed. Filed a new issue for cleaning up VirtKey a little, but for now our 
solution works just fine.

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 6:33

GoogleCodeExporter commented 9 years ago
Re-opening. Apparently GetKeyboardLayout() doesn't work for console programs. 
(This is documented in a few places.) 

We have to figure out why, and how to get around it.

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 6:36

GoogleCodeExporter commented 9 years ago
Update, after some fiddling:

We can't use AttachThreadInput() and just pump the console's messages for it (I 
think, because the Locale-changing event will have already passed, and in 
general it seems like the kind of idea that won't work.)

We can't use a system-wide hook for HSHELL_LANGUAGE events, since that will 
require a DLL (and system hooks are non-ideal anyway for other reasons).

Nonetheless, the local is detected SOMEHOW, since the console receives updated 
keystrokes. So... is there some way to detect "the current locale as seen by 
windows" ?

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 7:00

GoogleCodeExporter commented 9 years ago
We _might_ be able to use "AttachConsole" to borrow the console and add it to 
WaitZar, then retrieve its STDIN handle, then call "ReadConsoleInput", and 
finally process KEY_EVENT_RECORDs, which contain scancodes. 

This is a bit of a long shot, though, along with being a pain for debugging. 
Perhaps there's a better way?

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 8:23

GoogleCodeExporter commented 9 years ago
Interesting fact: Myanmar text won't work in a console anyway. So users 
shouldn't be using both.

Still, that's not an excuse. The icon in the lower-right clearly states that 
the Layout has changed. I'm sure it uses the equivalent of a hook, but there 
should be a way to access this exposed _somewhere_. It seems like a sensible 
thing to be able to do! I will spend some time looking for this... perhaps I 
can enumerate the current "layout" of ALL active windows; maybe the IME has its 
own specific Window that it changes over time? (I remember seeing an IME window 
waaaay back when working on WZ 0.1).... Even something experimental (with a 
config option, of course) is better than nothing.

Nonetheless, we won't be attaching to consoles; it's not worth the effort if WZ 
won't be able to input text there anyway...

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 8:31

GoogleCodeExporter commented 9 years ago
Scanning for all non-English IMEs and then following the chain backwards 
through their parents shows that an "MSCTFIME UI" window with a parent of 
"Default IME" is attached to each Console, and the language for either of these 
is correct. 

It appears that all windows have these as children. I remember that "Default 
IME" might not appear in Windows when only the default typing method is 
installed. Still, we can do a child-window search for "Default IME" OR 
"MSCTFIME UI", and just return the top-level window's locale if this fails. 
Definitely better than nothing, especially since our users will likely have at 
least one keyboard/IME installed.

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 9:34

Attachments:

GoogleCodeExporter commented 9 years ago
Technically (using GetAncestor()) the Console isn't a PARENT of the IME; it's 
an OWNER. This makes it more likely that we're on the right track (but now it's 
slightly harder to track ownership...)

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 10:27

GoogleCodeExporter commented 9 years ago
Got it! You have to use ImmGetDefaultIMEWnd() to get the WINDOW which acts as 
the IME to this process. Attached is a log of checking that value against the 
(known) value I found manually; they match if there's a "Y". Suffice to say, 
this'll work fine.

It's a one-line fix, but I'm delaying it till later. I want to write up a full 
solution so that others can find the answer if they search on Google.

Original comment by seth.h...@gmail.com on 21 Jun 2010 at 10:47

Attachments:

GoogleCodeExporter commented 9 years ago
Fixed. So, basically:

Preconditions:  Calling:
   HKL input = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow())) 
...will get the layout (locale, etc.) of the window WaitZar is considering. 
This is the same window that the lower-right icon depicts ("EN", "FR", etc.).

Problem: If the top window happens to be a Console App, then it doesn't pump 
its messages, so the Layout returned will be the one that the Console started 
in. However, it WILL react to the current input, so typing, e.g. "q" in a 
French layout will get you "a" with no obvious way to convert it back. (I.e., 
GetKeyboardLayout() will return "en_US".)

Solution: Each window clones a "Default IM" window (and sub-window, "MSCTFIME 
UI" --or just "M" in earlier versions of Windows) when it's created. These are 
"owned" windows, so enumerating child windows won't give you anything. 
Enumerating backwards from top-level windows will get you to the Console app, 
but a better way of doing this is to call:
   HKL input = GetKeyboardLayout(GetWindowThreadProcessId(ImmGetDefaultIMEWnd(GetForegroundWindow()))) 
...or, if you're cautious:
   HWND wnd = GetForegroundWindow()
   HWND wnd2 = ImmGetDefaultIMEWnd(wnd)
   HWND wnd3 = wnd2 ? wnd2 : wnd;
   HKL input = GetKeyboardLayout(GetWindowThreadProcessId(wnd3)
...since ImmGetDefaultIMEWnd() can potentially return NULL. The IME Window is 
always kept up-to-date on its owner window, so through a bit of mild irony, the 
"child" knows more than the "parent" about what is going on. 

Caveats: IM Windows aren't maintained unless East-Asian languages are 
installed. But this seems odd, since a French keyboard layout should be saved 
somewhere on a non-Asian computer anyway. I would guess that the "Default IM" 
window (or something similar) is maintained on these systems too. However, I 
wouldn't be surprised if WaitZar can't detect console layouts on 
single-keyboard systems. I need to find a way to test this. At worst, it will 
only cause consoles to malfunction on single-language systems (where the 
language is non-Asian) but that's far better than "malfunctioning on all 
systems"  --and, again, it'll work in non-Console apps by falling back to the 
owner window.

Marking fixed.

Original comment by seth.h...@gmail.com on 22 Jun 2010 at 9:45