Translate sequences of virtual keycodes into the resulting character message - windows

My understanding is that TranslateMessage collates a sequence of key events and adds a WM_CHAR message to the queue if it results in a character. So on my computer what happens when I press Alt+1234 (6 relevant events/messages, including releasing the Alt) is the single character "Ê" comes out (in certain places).
Let's say I have a sequence of virtual key codes and related keypress data generated from the LL keyboard hook. Is there some way of using the Windows OS logic to translate this sequence into a real character? For example, could I construct contrived MSG structures, call TranslateMessage on them and then catch the WM_CHAR ensuing events? That seems very outside of Windows' expectations; haven't tried it yet but it seems like it could cause all kinds of subtle problems.
The cleanest solution I can think of so far is just to re-implement the logic myself to figure out the characters from the virtual codes. This is unfortunate of course since Windows internals already seem to know how to do this! Is there a better way?
I am aware of the existence of MapVirtualKeyA but this does not seem to handle a sequence of virtual key codes.
I am also aware that it is possible to do a hook on all GetMessage calls which could be used just to grab the WM_CHAR messages from every process. However this seems an extremely heavy solution: I need to make a separate DLL unlike for the WH_KEYBOARD_LL hook and then use some sort of IPC to send the characters back to my host process. Also MSDN explicitly says that you should avoid doing global hooks this for anything outside debugging and I need this to work on production machines.
I am also also aware of KeysConverter in .NET (I am fine to use .NET for this) but again this does not seem to deal with sequences of virtual keys like given above.

Related

Porting an old DOS TUI to ncurses

I would like to have some advice about how to port an old C++ program written for MS-DOS in the early 90s.
This program implements a quite complex text-user interface. The interface code is well separated from the logic, and I don't think it would be too difficult to make it use ncurses.
Being a complete novice, I have a few questions:
The DOS program intercepts interrupt 0x33 to handle mouse events. The interrupt handler store events in a FIFO, which the main program pools periodically. (Every element in the FIFO is a C structure containing information about the nature of the event, the position of the mouse and the state of its buttons.) To keep the logic of the code unchanged, I was thinking of firing a thread which calls getch() asynchronously within an infinite loop and fills the FIFO in the same way the old program did. My idea is that this thread, and only this thread, should access stdin, while the main thread would only have the responsibility to access stdout (through add_wch() and similar). Is ncurses safe to use in this way, or do stdin/stdout accesses need to be always done within the same thread?
The way colors are set in this app is quite byzantine, as it uses the concept of "inherited palettes". Basically, a window usually specifies the background and foreground colors, and every widget within that window sets the foreground only (but a few widgets redefine both fg/bg). I understand that ncurses' attr() always wants to specify colors using pairs, which must be initialized using initp(), and this doesn't play nicely with the logic of this program. I am therefore thinking of using tiparm() to directly send setaf/setbf sequences when the program wants to change the fg/bg color, respectively. (I would lose the ability to run the code on terminals which do not support setaf/setbf, but this would not be a huge loss.) Is it safe to send setaf/setbf control sequences and then call functions like add_wch(), or should the latter be used only in association with attr()?
I could write a few test scripts to check that my ideas work, but I would not be sure that this approach is supposed to work always.
Thanks for any help!
There's a lot of possibilities - but the approach described sounds like terminfo (low-level) rather than curses, except for the mention of add_wch. Rather than tiparm, a curses application would use wattr_set, init_pair, start_color, etc.
ncurses I/O has to be in one thread; while ncurses can be compiled to help (by using mutexes in some places), packagers have generally ignored that (and even with that configuration, application developers still would have work to do).
Further reading:
curses color manipulation routines
curses character and window attribute control routines
curses thread support

Since TranslateMessage() returns nonzero unconditionally, how can I tell, either before or after the fact, that a translation has occurred?

This is a continuation from What is the correct, modern way to handle arbitrary text input in a custom control on Windows? WM_CHAR? IMM? TSF?.
So after experimenting with a non-IME layout (US English), a non-TSF IME (the Japanese FAKEIME from the Windows XP DDK), and a TSF text service (anything that comes with Windows 7), it appears that if the active input processor profile is not a TSF text service (that is, it is a TF_PROFILETYPE_KEYBOARDLAYOUT), I'll still have to handle keystrokes and WM_CHAR messages to do text input.
My problem is that my architecture needs a way to be told that it can ignore the current key message because it was translated into a text input message. It does not care whether this happens before or after the translation; it just needs to know that such a translation will or has happened. Or in pseudocode terms:
// if I can suppress WM_CHAR generation and synthesize it myself (including if the translation is just dead keys)
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (WillTranslateMessage())
InsertChar(GenerateEquivalentChar());
else
HandleRawKeyEvent();
break;
// if I can know if a WM_CHAR was generated (or will be generated; for instance, in the case of dead keys)
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (!DidTranslateMessage())
HandleRawKeyEvent();
break;
case WM_CHAR:
case WM_SYSCHAR:
InsertChar(wParam);
break;
The standard way of handling text input, either from a keyboard or through a non-TSF IME, is to let TranslateMessage() do the WM_KEYDOWN-to-WM_CHAR translation. However, there's a problem: MSDN says
If the message is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP, the return value is nonzero, regardless of the translation.
which means that I cannot use it to determine if a translation has occurred.
After reading some Michael Kaplan blog posts, I figured I could use ToUnicode() or ToUnicodeEx() to do the conversion myself, passing in the state array from GetKeyboardState(). The wine source code seems to agree, but it has two special cases that I'm not sure if they are wine-specific or need to be done on real Windows as well:
VK_PACKET — generates a WM_CHAR directly out of the message's LPARAM
VK_PROCESS — calls a function ImmTranslateMessage(), which seems to either be a wine-specific function or an undocumented imm32.dll function; I can't tell which is true
And wine also does nothing with WM_KEYUP and WM_SYSKEYUP; again, I don't know if this is true for wine only.
But do I even need to worry about these cases in a program that uses TSF? And if I do, what's the "official" way to do so? And even then, what would I do on WM_KEYUP/WM_SYSKEYUP; do I need to send those to ToUnicode() too? Do I even need to catch WM_KEYUPs in my windows specially if there was a WM_CHAR?
Or am I missing something that is not in any of the MSDN TSF samples that will allow me to just have TSF take care of the TF_PROFILETYPE_KEYBOARDLAYOUT processors? I thought TSF did transparent IME passthrough, but my experiment with the FAKEIME sample showed otherwise...? I see both Firefox and Chromium also check for TF_PROFILETYPE_KEYBOARDLAYOUT and even use ImmGetIMEFileName() to see if the keyboard layout is backed by an IME or not, but I don't know if they actually take care of input themselves in these cases...
My minimum version right now is Windows 7.
Thanks.
UPDATE The original version of this question included needing to know about associated WM_KEYUPs; on second look through my equivalent code on other platforms this won't be necessary after all, except for the details of TranslateMessage(); I've adjusted the question accordingly. (On OS X you don't even give key-release events to the text input system; on GTK+ you do but it seems keypresses that insert characters don't bother with releases and so they don't get handled anyway, at least for the input methods I've tried (there could be some that do...).) That being said, if I missed something, I added another sub-question.
In general, it's not a good idea to try to duplicate Windows internals. It's tedious, error-prone, and likely to change without notice.
The edit controls that I have source access to pick off arrow keys (and other specific keys) in the WM_KEYDOWN handler and pass everything else off to the default handler, which will (eventually) generate WM_CHAR or TSF input calls (if your control supports TSF, which it should).
You would still need WM_CHAR in the case where there is no TSF handler involved. However, you can always have your WM_CHAR handler call your ITextStoreACP::InsertTextAtSelection method.

How to implement accented characters on windows?

Any pointers on how accented characters are implemented in Windows would be helpful.
Goal - Ability to add accented characters(áéíóú) using keystrokes like ctrl + ' followed by a vowel and all other combinations that work on standard applications like MS Word, Text pad etc.
My Findings till date -
Everywhere I could read documentation/blogs/forums related to WM_DEADCHAR message.What I understand is :
::TranslateMessage translates WM_KEYUP messages corresponding to dead keys into WM_DEADCHAR messages, and it translates WM_SYSKEYUP messages generated by dead keys into WM_SYSDEADCHAR messages. Windows provides the logic that combines these messages with character messages to produce accented characters, so dead-key messages are usually passed on for default processing.
I added this message to my CWnd derived class's message map but OnDeadChar() never gets called. Additionally I have found out using SPY++ that even in MSWord,Textpad etc where accented characters could be added with combination of these keystrokes, WM_DEADCHAR message is never dispatched.
So, Does this mean that WM_DEADCHAR is actually not the way to address this issue?
Please provide any sample code/steps/mechanism to implement accented characters.
Thanks in advance!!!
This is all dependent on the keyboard layout you are using. Certain keyboard layouts have dead keys which basically allow for key combinations for producing more characters.
For example my ` key does nothing by itself, but pressing ` then a produces à.
In terms of allowing users to input accented characters, it's really up to them to install a keyboard layout which allows for it. Your app does not need to handle WM_DEADCHAR; you can just handle WM_CHAR.
In terms of supporting accented characters internally in your app, just make sure you're using the Unicode character set and types. For example wchar_t / WCHAR, and not char.
For what it's worth, I believe I had the same goal as you at some point. I created an app that basically simulates dead keys and would produce accented characters using keyboard hooks. The advantage is that you get the accented char functionality without installing a keyboard layout.
The disadvantages are more numerous though. There's no point re-invent this wheel. Keyboard layouts are surprisingly powerful, and all these issues with inputting characters have been solved already. You will have a very hard time translating your own messages to generate different characters. Different apps have different requirements in this regard, and in the end you will need to completely simulate keystrokes, to the point of generating keyboard state structures and handling every keyboard / char / input message. So as you are developing this, you'll notice that it works fine for Notepad, but doesn't work for Winword. Then you fix for winword, and then discover that it doesn't work for Qt apps. I would definitely suggest using keyboard layouts.
But maybe this is not what you're trying to do; in that case ignore what I said :D

Are Window Messages "Reliable"?

This is somewhat of a general question regarding Windows programming:
Are Window messages "reliable"?
For example (these are just examples):
Can you be certain that a WM_MOUSEMOVE will happen before a cursor enters your screen?
Can you be certain that you will get a WM_DEVICECHANGE message if a device is inserted?
Can you be certain that you will receive a WM_KILLFOCUS message if your window loses focus?
Or, in other words: Can you be certain that you'll get the appropriate message at the appropriate times, or do you always have to code defensively in case that, somehow, you might miss a message for no apparently documented reason?
Example:
It is guaranteed (AFAIK) that a file system filter driver will not "miss" a file operation or change notification.
By contrast, it is not guaranteed that ReadDirectoryChangesW will not miss a notification. In fact, it can miss quite a few if its buffer overflows.
Note:
I am not talking about a situation against an adversary (e.g. someone hijacking your window procedure or installing a hook/filter); that would pretty much invalidate any guarantee. I'm only asking about obscure situations that could really happen even if no one meant anything bad intentionally, like if some random buffer overflows, if someone uses SendInput, etc., assuming you have control of your own code.
No you cannot be certain that a given message will be delivered in a specific order. Here are a couple of reasons why not
Messages can be sent progamatically and this can be used to simulate "impossible" scenarios like a WM_KEYUP followed by a WM_KEYDOWN.
Another routine could sub-class your window and selectively intercept messages and not send them on to your WNDPROC
It's best to code defensively around any scenarios where ordering is important

Can abusing RegisterWindowMessage lead to resource exhaustion?

MSDN advises that RegisterWindowMessage() function is only used for registering messages to be sent between the processes. If a message is needed for sending within one process it can be safely selected from the range WM_APP through 0xBFFF.
However in our codebase I often see that RegisterWindowMessage() is used for messages only sent within one process. I suppose that this was done because of perceived simplicity of using RegisterWindowMessage() since it doesn't require manually distributing the message identifiers in the WM_APP..0xBFFF range.
Do I understand correctly that if many applications are run on one machine and they all call RegisterWindowMessage() with different strings they could exhaust the range of message identifiers allowed to return by RegisterWindowMessage() and for some of them it will just return a value indicating a failure? What could be a valid reason for using RegisterWindowMessage() messages in cases where WM_APP..0xBFFF range messages would suffice?
IMHO there is no valid reason to use RegisterWindowMessage if you are only sending messages to yourself
There is no (documented) way to un-register a message, so after your app quits, that registered message will stay in the atom table until reboot/logoff (I can't remember exactly where this atom table is stored, the window station or terminal server session instance probably)
The reason you need to use RegisterWindowMessage even when messaging to yourself is that it protects you from the idiot who broadcasts messages in the WM_APP + N range.
Yes, this does happen.
Abusing RegisterWindowMessage can potentially make a windows box unusuable. This is especially true if the window message names are dynamically generated and a bug causes out of control windows message allocation. In this case the global atom table in your windows station/ desktop will fill up and any process using User32.dll (basically, any app) will fail to start, create windows, etc.
There is a bug out there in Delphi / Borland products that registers messages that start with ControlOfsXXXXXX where XXXX is a memory address (or other dynamic modifier). Apps that are started and stopped frequently will register multiple ControlOfsXXXX atoms and eventually exhaust atom space. For more details see:
http://blogs.msdn.com/b/ntdebugging/archive/2012/01/31/identifying-global-atom-table-leaks.aspx
And
https://forums.embarcadero.com/thread.jspa?threadID=47678
A possible advantage is that Spy++ can display more informative text, therefore debugging is a bit easier. Compare
<00058> 00330CA2 S message:0x0419 [User-defined:WM_USER+25] wParam:00000000 lParam:00000000
with
<00129> 004F0DA0 S message:0xC2B0 [Registered:"AFX_WM_ONCHANGE_ACTIVE_TAB"] wParam:00000001 lParam:02B596E8
Of course, in principle there is a chance to run out of message IDs. On the other hand, in the source code of the MFC Feature Pack there are 52 calls to RegisterWindowMessage. So there are still 16300 IDs left for other applications.

Resources