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:
InputMethodListener
interface to
handle incoming InputMethodEvents
generated by the
current input method, and register the listener.InputMethodRequests
interface and
override getInputMethodRequests
to return the request
handler.InputMethodHighlight
attributes along with
composed text and pass them on to the drawing routines.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.
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).
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
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.
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:
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.
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:
LANGUAGE
- the language of the text, specified as
a Locale
object.READING
- a phonetic representation (yomi
in Japanese), specified as a String
object.INPUT_METHOD_SEGMENT
- segmentation information
used by input methods.Input methods written in the Java programming language may define additional attributes.
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.
Text components can use the input context's
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.
Text components can use the input context's
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.
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.
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.
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.