Input Scopes

Another useful, but underutilized, group of functions in TSF are those relating to Input Scopes.   Input Scopes allow an application to define the sorts of things that are expected in this document (edit control, etc.).  For example, the Internet Explorer 7 address bar has an input scope of IS_URL | IS_DEFAULT | IS_ENUMSTRING - meaning that the address bar expects the input to be either a URL, one of the entries in its enumeration, or just plain anything (IE will default to searching for the string you typed). 

Input scopes were originally created for the Tablet PC, and a lot of the MSDN documentation is specifically related to the Tablet PC.  However, other input handlers (for example, speech) use input scopes as well to improve recognition.   For example, Windows Speech Recognition has a custom URL language model that is used when a control specifies the IS_URL input scope.  This significantly improves recognitions on URLs that are part of the language model.

The functions are very easy to use, if you have an hwnd for your control.  If you only want to set a single input scope (for example, IS_DIGITS for a numeric control), then SetInputScope is the function for you.  If you want to set multiple input scopes, or you want to use one of the more exotic input scopes like IS_PHRASELIST or IS_REGULAREXPRESSION (which return application-defined strings), then you will want to use SetInputScopes, which allows you to pass an array of input scopes, along with other data.  Finally, Windows Vista adds SetInputScopes2, which is a variant of the SetInputScopes function, but which takes a string enumerator object instead of an array of strings.

One thing to take note is that if you call SetInputScope (or one of its siblings), you need to call SetInputScope(hwnd, IS_DEFAULT) before the window is destroyed.  MSDN mentions this in the remarks; I want to emphasize it.

If your control doesn't have an hwnd, or if you want to have multiple input scopes per document, the situation is a bit more complicated.   MSDN isn't very clear about how to make input scopes work in TSF-aware applications.  In the description of the ITfInputScope interface, MSDN says

A TSF-aware application does not call SetInputScope directly, but rather implements either ITextStoreACP or ITfContextOwner to get a pointer to ITfInputScope .

What this bit means is that TSF-aware applications need to implement input scopes via an application property.  In particular, you need to implement ITextStoreACP::RequestSupportedAttrs, and ITextStoreACP::RetrieveRequestedAttrs.  If you want to have multiple input scopes per document, then you also need to implement ITextStoreACP::RequestAttrsAtPosition.  Note that the documentation refers to TS_ATTRIDs; these are typedefs for GUIDs!  The TS_ATTRID that you need to support for input scopes is GUID_PROP_INPUTSCOPE  (you may, of course, add support for other TS_ATTRIDs). 

Retrieving input scopes is fairly straightforward.  MSDN has a nice code snippet describing how to retrieve the ITfInputScope interface here; once you have it, use ITfInputScope::GetInputScopes to retrieve the list of input scopes, and the other methods return auxiliary data for exotic input scopes.

If you need the string enumerator (i.e., you want to support IS_ENUMSTRING), then you need to get the ITfInputScope2 interface, instead of ITfInputScope; all you need to do is QI the application property for IID_ITfInputScope2 instead of IID_ITfInputScope.   The MSDN documentation for ITfInputScope2 is incorrect; ITfInputScope2 extends ITfInputScope, not IUnknown (and it's only available on Windows Vista).   

The Input Scope enumerations are defined here.