What's a Keyboard?

The Text Services Framework makes a number of assumptions when you register your text service as a keyboard text service (i.e., your text service calls RegisterCategory(<clsid of your text service>, GUID_TFCAT_TIP_KEYBOARD, <clsid of your text service).

First, TSF assumes that exactly one keyboard text service can be active at a time.  If the user activates one keyboard text service, all other keyboard text services will be disabled.

Second, TSF assumes that keyboard text services must monitor two compartments:

GUID_COMPARTMENT_KEYBOARD_DISABLED, and GUID_COMPARTMENT_KEYBOARD_OPENCLOSE;

and that keyboard text services should monitor GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION and GUID_COMPARTMENT_KEYBOARD_INPUTMODE_SENTENCE.

The sample text service tells you to monitor these; unfortunately, it doesn't really describe why you need to monitor those compartments, nor does it tell you what these compartments really mean.

The input mode compartments (GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION and GUID_COMPARTMENT_KEYBOARD_INPUTMODE_SENTENCE) contain conversion flags that your text service can use to control the mappings from keystrokes to characters.  The other two compartments control when the text service should interpret the incoming keystrokes.

When GUID_COMPARTMENT_KEYBOARD_DISABLED is non-zero, it means that all keyboard processing should be disabled, and all keystrokes should be passed through without alteration.  This compartment often has a non-zero value when a text service wishes to display its own candidate UI.

When GUID_COMPARTMENT_KEYBOARD_OPENCLOSE is non-zero, it means that the keyboard is 'open' and that keystrokes should be processed normally.  If the compartment value is zero, it means that the keyboard is 'closed', and that all keystrokes should be passed through without alteration.

The main difference between these two compartments is that GUID_COMPARTMENT_KEYBOARD_DISABLED applies to a context, and GUID_COMPARTMENT_KEYBOARD_OPENCLOSE applies to an entire thread (and therefore to all the documents and contexts owned by that thread).

Since GUID_COMPARTMENT_KEYBOARD_OPENCLOSE applies to an entire thread, many text services choose to set up an compartment event sink on this compartment in order to cache the compartment value.  That way, you can avoid querying the thread compartment inside your keyboard processing routines.  You could also set up a sink on GUID_COMPARTMENT_KEYBOARD_DISABLED, but you would have to disconnect and reconnect the sink when the document or context changes (including focus changes).  The cost of manipulating the sinks may outweigh the cost of caching the value.