Input Method Client API Tutorial

Contents

  1. Implementing an Active Client Component
  2. Enhancing an Active Client Component
  3. Implementing a Non-Client
  4. Sample Code

1. Implementing an Active Client Component

The input method client API makes it possible for client components to implement integrated text input user interfaces such as on-the-spot input. The API defines events and methods that facilitate the communication between a client component and an input method. It also lets the client component request an input method for a particular language.

Since the API doesn't make any assumptions about how and where the text is drawn, it can also be used to implement other input styles such as over-the-spot editing. In this style, the composed text is drawn over surrounding text and covers it instead of being integrated and formatted with it.

Any client component class can become an active client of the input method client API and thus support an integrated text input user interface by performing the following steps:

Optionally, the client component can also use the following functionality:

Client components don't need to deal with setting up input contexts, activating or deactivating contexts, or dispatching events to input methods, since all this is handled automatically by AWT.

Handling Input Method Events

The input method framework provides an event class, InputMethodEvent, to support the communication between input methods and text components. The class has two separate event kinds: text changed and caret changed. An event listener interface, InputMethodListener, supports these two events. An active client component must implement the InputMethodListener interface, register the listener, and handle both kinds of events.

InputMethodEvent instances are sent to the client component when there is a change to the user's input text, its highlighting, or to the caret location within the composed text. The event sent for caret-only changes is a simplified version of the one for text changes (it just doesn't have text information), so the following discussion assumes the text-changed event.

An event reporting a text change has a reference to an instance of AttributedCharacterIterator that represents either composed text or committed text or both together. The event's committed character count value specifies how many characters in the iterator's range are committed text; all remaining characters are composed text. Committed text always precedes composed text. If the component has no previous composed text, the committed and composed text replace any selected text or are inserted at the current insertion position of the component's text. If there is previous composed text, the entire previous composed text is replaced with the new committed and composed text. The insertion point moves to the end of the committed text. The client component is responsible for redrawing the updated text.

The event also contains information about the current caret location within the composed text (null if no caret is to be displayed), and about the part of the composed text that is most important to keep in view (null if the input method doesn't have a recommendation).

Handling Input Method Highlight Attributes

The text component generally draws the composed text as part of the text being edited, using its regular text layout and drawing functionality. However, it needs to add certain highlight style attributes to the composed text to indicate the current state of the composition. The framework defines these style attributes as abstract styles (for example, "unconverted unselected text" or "converted selected text"), and maps them internally to platform-dependent concrete styles (for example, 2-pixel gray underline).

Highlight attributes are represented by the InputMethodHighlight class. Instances of this class are used as attribute values of the AttributedCharacterIterator instances representing composed text. Text components must store these attributes with the composed text and pass them on to the drawing routines when drawing composed text. They can use either the java.text.AttributedCharacterIterator, int, int)">drawString methods that accept AttributedCharacterIterator, or create a TextLayout from the iterator and use its draw method. These drawing methods interact with the input method framework to map abstract to concrete highlight styles. Text components using these methods therefore generally do not need to be concerned with the internal details of the input method highlights. If a text component uses some other mechanism to render the text, it should check the input method highlight for concrete style information, and, if none is provided, use Toolkit.mapInputMethodHighlight to map to a concrete style.

Some input methods may treat highlights as "annotations". Annotations are attributes that apply to a specified range of text, but not to subranges or the concatenation of ranges. They are represented by wrapping the InputMethodHighlight instance into an Annotation instance. Input methods may use annotation highlights to separate text segments that will be converted as separate units. On some platforms, these highlights are rendered so as to make the segments visible, for example, by using underlines with short breaks between the segments. Text components have to be able to handle input method highlights whether they are wrapped in Annotation instances or not. If a text component implements line wrapping, special care needs to be taken when the range to which a highlight annotation applies crosses a line boundary: The normal behavior (implemented, for example, in AttributedString) would be to discard the attribute because it doesn't apply to subranges. But, since in this case there's only a visual break and not a logical break, the highlight needs to be preserved - it has to be treated as if it applied to the subranges that are rendered on separate lines. One way to do this is by implementing the AttributedCharacterIterator in a way that returns highlight annotations even for subranges of the intended range.

Handling Input Method Requests

An input method needs to access component information to perform input operations. For example, an input method needs to know the location where a list of possible choices can be shown.

An active client component therefore must implement the InputMethodRequests interface, and override getInputMethodRequests to return the request handler. The interface includes methods to:

Ending Input Operations

Input methods typically recognize some user actions that end input operations, for example, an operation that commits all uncommitted text. However, there are also user actions that start operations for which input operations should be ended, but that an input method cannot recognize. Saving the document containing the text is one such example. In these cases, the component has to explicitly call the input context's endComposition method.

2. Enhancing an Active Client Component

Handling Additional Text Attributes

In addition to the input method highlight information, input methods may also attach other attributes to the text they send to a text component. These attributes may be useful information for the component. They may also improve the input method's performance if returned by the InputMethodRequest methods. For the latter reason, it is recommended that text components keep this attribute information around while the text is being edited, and return it with any text requested.

The AttributedCharacterIterator.Attribute class defines the following common attributes:

Input methods written in the Java programming language may define additional attributes.

Creating Private Input Contexts

By default, one InputContext instance is created per Window instance, and this input context is shared by all components within the window's containment hierarchy. This reduces the number of instances created overall, and lets input methods combine information about all the text entered in this window (input methods often use information about previously entered text to improve their conversion accuracy). It means, however, that only one input operation is possible at any one time within a window, and that the text needs to be committed when moving the focus from one text component to another. If this is not desired, text components can create their own input context instances and override getInputContext to return them. A component that doesn't have its own input context uses the one used by its parent.

Selecting Input Methods

Text components can use the input context's java.util.Locale)">selectInputMethod operation to select an input method for a given language or locale. This may be helpful, for example, if the user clicks in text that is written in that language, since it's likely that she wants to continue in the same language. Or, the text component may know that the application only allows text in a certain language to be entered.

Setting an Expected Character Subset

Text components can use the input context's java.lang.Character.Subset[])">setCharacterSubsets operation to tell input methods which characters can be meaningfully entered. For example, a database application may know that certain fields should only receive input in hiragana (one of the syllabic subscripts used in Japanese), another one only Latin characters, a third one any kind of characters. Passing on this information to input methods may allow the input methods to limit the range of characters that can be entered, or to switch to a different input mode that particularly supports the specified character subsets.

Using Engine-Specific Functionality

Some input methods may provide functionality to client components that can not be made available through the input method framework API. This is possible through input method control objects. The input method developer must publish an interface for these objects. Client components that want to take advantage of the additional functionality can then call InputContext.getInputMethodControlObject, check whether the returned object is an instance of a known control object class, and if it is, call its methods.

3. Implementing a Non-Client

By default, all components that process key events are clients of the input method framework, that is, input method support is enabled for them. In some cases, components may not want to have their input processed by input methods. For example, games may want to interpret keyboard events directly. These components should call enableInputMethods(false), so that events do not get forwarded to input methods.

4. Sample Code

This sample code shows how to implement the different kinds of input method clients that are possible with the input method framework: an active client, a passive client, a non-client, and a peered text component.