5

I want to be able to support text input in a custom Windows control, just like the EDIT and rich edit controls already do, but not subclassing either of those. The control currently uses Direct2D and DirectWrite to draw text, and runs on Windows Vista SP1 with Platform Update or newer (I might change it to Windows 7 SP1 with Platform Update or newer if I decide I need newer Direct2D and DirectWrite features, assuming those are available there or on Windows 8 only, but that's a different question...)

For what it's worth, on OS X I would use NSTextInputClient and on GTK+ I would use GtkIMContext. It's things like these that I'm talking about.

The obvious choice is to use WM_CHAR, which if I gather correctly, is natively UTF-16 if the window class is registered with RegisterClassW(), and therefore should "just work" regardless of location. However, WM_CHAR is generated by TranslateMessage(), and its documentation says there is no way to determine whether a WM_CHAR has been generated or not, since TranslateMessage() always returns nonzero. I need to be able to determine whether the current keyboard message will be handled by the text system (and thus should be ignored); this is especially true since all non-text keys need to be handled in a layout-independent way (which I already have).

I've also seen in the Windows 7 samples code for both the IMM API and the Text Services Framework. I'm not sure whether one is better than the other, and they both seem to do the same thing. Do they?

In the case of IMM, there are a number of WM_IMM_xxx messages that I'm not sure if I should be ignoring or not, and every reference I've found seems to disagree as to whether I should handle them in a Unicode window or not... Also, the above problem of knowing if a given key event will be handled by IMM or not is still open; is there a way?

TSF has a concept called ACP, which seems to allow me to use whatever text storage format I want for storing the text I'm actually going to use (that is, not an in-progress composition). Is this true? I'd like to be able to store my text as UTF-8 with attributes, converting to UTF-16 when drawing (for DirectWrite). Do the other API choices also let me do this?

Or am I completely on the wrong path?

And how would I opt into the on-screen keyboard once I do all of that?

Other references I used:

Thanks.

UPDATE 7 Nov 2016
After looking at the TsfPad sample again, I notice it also seems to just use WM_CHAR; now I'm not sure how it even uses TSF, other than that it does...

Community
  • 1
  • 1
andlabs
  • 11,290
  • 1
  • 31
  • 52
  • Have a look at [Uniscribe](https://msdn.microsoft.com/en-us/library/dd374091(v=vs.85).aspx), [Uniscribe functions](https://msdn.microsoft.com/en-us/library/dd374093(v=vs.85).aspx), and [International Text Display](https://msdn.microsoft.com/en-us/library/dd317783(v=vs.85).aspx), it sounds like a lot of work however. – Barmak Shemirani Nov 06 '16 at 21:27
  • That's about display, not input; or at least it seems to only be about display. I've already got that covered =P And I'm already using Uniscribe for splitting text into grapheme clusters; it works well enough. Thanks in the meantime! – andlabs Nov 06 '16 at 23:02
  • Maybe you can handle WM_KEYDOWN messages to process the non-text keys and handle WM_CHAR to process the text keys. – Stuart Nov 07 '16 at 01:00
  • @Stuart yes; the question is how to distinguish between the two. – andlabs Nov 07 '16 at 01:20
  • @andlabs What non-text keys do you need to handle? Can you give a couple of examples of key presses that you're not sure how to process? – Stuart Nov 08 '16 at 00:59
  • @andlabs With TSF, you don't really need to process keys (as such) at all. TSF uses your implementation of [ITextStoreACP](https://msdn.microsoft.com/en-us/library/windows/desktop/ms538384(v=vs.85).aspx) to insert characters into your document. – Eric Brown Nov 08 '16 at 17:57
  • @EricBrown right; my point isn't to process keys, but rather to know when *not* to because TSF did it already. Thanks for the answer in the meantime; I'll respond to it when I get a chance to read the article. (I've been skimming the TSF Blog in the meantime as well.) – andlabs Nov 08 '16 at 21:17

1 Answers1

2

The TSF API is a superset of the IMM API. It's also newer than IMM, and is the current, modern way to handle international text input (as well as other input mechanisms like handwriting and speech).

If you use the TSF API, text appears via the API instead of windows messages (so the issue of which message is irrelevant).

The On-Screen keyboard is handled automatically, and you shouldn't have to worry about it. (The entire purpose of TSF is to make your app independent of input source.)

TSF can support UTF-8, but it's a bit of a pain; you need to mark the extension characters as hidden. You would be much better off with UTF-16, which is TSF's default API.

The best example I know of on how to add TSF support to an existing edit control is still the article I wrote back in July 2007.

Input can still arrive via WM_CHAR (if the current input profile is a keyboard layout, for example), so you need to implement this as well; typically, though, you can handle WM_CHAR messages by calling into your ITextStoreACP::InsertTextAtSelection implementation.

Eric Brown
  • 13,774
  • 7
  • 30
  • 71
  • All right, thanks. In this case, what stops me from just using ACPs as UTF-8 byte offsets? Does TSF do things like `wcslen()` on the result of `GetText()`? Also do I need to use ITfMessagePump [like here](https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/winui/tsf/tsfapp/tsfapp.cpp#L61) to actually activate text services? And if so, why do the tsfpad samples not need it? – andlabs Nov 21 '16 at 03:33
  • Okay, so upon further study I figured it out: the tsfpad samples still use `WM_CHAR` for keys that aren't handled by the input manager. I imagine I would have to use ITfMessagePump and ITfKeystrokeMgr if I want TSF to handle keyboard events itself too, right? Why should I use ITfMessagePump as opposed to just plain old `GetMessage()` anyway? Or am I completely on the wrong track now? Also, the link to your fixed ScintillaWin.cxx and the other TSF samples are down; where can I find them now? – andlabs Nov 22 '16 at 14:20
  • Er, by other TSF samples I mean the ones that used to be on archive.msdn.microsoft.com. – andlabs Nov 22 '16 at 15:03
  • Okay, I'm seriously misunderstanding TSF. I added calls to the ITfKeystrokeMgr methods in my window class, but they are all returning "not handled" unless I have a second language enabled... – andlabs Nov 22 '16 at 20:28
  • Coming back to this: is it true that input methods that are solely based on the old keyboard layout system (`HKL`) — that do not use either an IMM module or a TSF service, such as the default US English — are not exposed by TSF? Because after a lot more experimentation that seems to be the only conclusion I can come up with, and if I am right, it will lead me to a more direct, but separate, question (how to tell if `TranslateMessage()` will do something, since its return value is documented as meaningless). – andlabs Dec 23 '16 at 04:34
  • Actually I decided to ask this as a different question: http://stackoverflow.com/questions/41334851/since-translatemessage-returns-nonzero-unconditionally-how-can-i-tell-either. Thanks anyway! – andlabs Dec 26 '16 at 18:16