Input Method Engine SPI Tutorial
Contents
- Introduction
- Describing the Input Method
- Communicating with the Client Component
- Using Input Method Windows
- Implementing Composition
- Providing Engine-Specific Functionality
- Packaging the Input Method
- Sample Code
1. Introduction
The input method engine SPI enables the development of input methods in the Java programming language that can be used with any Java 2 runtime environment. As far as the input method framework is concerned, an input method consists of two classes implementing the InputMethodDescriptor and InputMethod interfaces, packaged with some additional information as an extension and installed into a Java runtime. The specifications for the package, and the InputMethodDescriptor and InputMethod interfaces provide the core information that's needed to implement an input method. This tutorial provides additional information that makes this task a little easier and helps avoid compatibility problems between different implementations of the Java 2 platform.
2. Describing the Input Method
Before the input method framework can start using an input method, it needs to know about its capabilities. The necessary information is provided by the input method's implementation of the InputMethodDescriptor class. This information is used in selecting input methods.
The list of available locales returned by getAvailableLocales should only return languages that the input method is really designed for. For example, a Chinese Pinyin input method that produces simplified Chinese characters should only return SIMPLIFIED_CHINESE, even if it has a mode that simply lets key events pass through and thus also makes it possible to write English or Malay. The java.util.Locale)">InputMethod.setLocale method on the other hand may return true for a larger set of languages. The reason is that getAvailableLocales is used to decide whether to load and switch to an input method, which is only worthwhile if the input method handles the language well, while setLocale is used to decide whether to switch away from an input method, which is only worthwhile if the input method doesn't handle the language at all.
3. Communicating with the Client Component
When an input method instance is created, it receives an InputMethodContext instance through setInputMethodContext. This instance provides it with all the functionality that it needs to communicate with the input method framework, the client component, or the composition window. It lets the input method send information about composed and committed text using the java.text.AttributedCharacterIterator, int, java.awt.font.TextHitInfo, java.awt.font.TextHitInfo)">dispatchInputMethodEvent method. And it lets the input method request information from the client component using the methods it inherits from the InputMethodRequests interface.
The input method framework provides the input method with an environment that makes it seem like it is always communicating with an active client component using the on-the-spot input style. If the actual client component is not an active client, or if a different input style is used, then the framework redirects events and requests as needed.
The input method should never try to access the client component directly, as doing so would conflict with the framework's switching and redirection functionality. Instead, the input method should always use the methods provided by its input method context.
4. Using Input Method Windows
Input methods may use a number of different windows to communicate with the user. Windows commonly used by input methods include:
- a look-up window, which shows several possible interpretations of the user's input and lets the user choose the correct one.
- a status window, which provides the user with information about the current state of the input method, such as the selected language or target character set.
- a control panel (often combined with the status window), which lets the user change the input method's state, such as selecting a different language or target character set.
- a preferences window, which lets the user tailor the input method to his or her needs.
- a dictionary editor window, which lets the user add or correct conversions.
Note: On some other platforms, input methods may also provide a composition window, which shows the composed text. In the Java input method framework, composed text is always displayed by the client component or the input method framework, never by the input method.
It is useful to consider three groups of windows:
- transient windows: these windows pop up for short times during a composition operation. Their functionality is tied to a specific composition. Opening, closing, positioning, and sizing are usually automatic since any user interaction with the windows themselves would distract from the composition. In particular, transient windows are always closed when the composition operation ends or is interrupted. Examples: look-up window.
- persistent windows: these windows tend to stay around for extended periods of time, possibly for as long as the user is using the input method. Their functionality may be tied to the currently active instance of the input method, or to the input method class. Usually the user can actively open, close, position, and possibly resize these windows, although they are always automatically closed when switching to a different input method, and in some cases they're automatically positioned relative to the window containing the current client component. Examples: status window, control panel.
- document windows: these are just regular windows. Their functionality is not tied to composition. The user fully controls opening, closing, positioning, and possibly sizing of these windows. Examples: dictionary editor window.
Here's how these window groups can be handled by input methods written for the Java 2 platform:
- transient windows are created using InputMethodContext.createInputMethodWindow, typically with attachToInputContext set to true. They are opened either in the input method's implementation of activate, or later when needed to respond to user input. They are closed in the input method's implementations of deactivate or hideWindows, or earlier if they are no longer needed.
- persistent windows are created using InputMethodContext.createInputMethodWindow, with attachToInputContext set to false. They are typically opened in the input method's implementation of activate and closed in the input method's implementation of hideWindows.
- document windows are created as regular AWT windows, and opening and closing them is usually under user control.
Note that the focus behavior of a window created by createInputMethodWindow is implementation dependent. It may never get the focus, it may get the focus when initially made visible, or it may get the focus when the user clicks into it. An input method must be able to handle either case.
To position windows (such as the look-up window) automatically relative to the composed text, the input method can use the input method context's getTextLocation method. To position windows (such as a status window) automatically relative to the window containing the current client component, the input method can register for notifications about that window's location and state using the input method context's enableClientWindowNotification method; it then has to implement the notifyClientWindowChange method to receive notifications.
5. Implementing Composition
The main task of an input method is interpreting user actions in composing text input. The user actions may be typing on the keyboard, using the mouse, handwriting, or speaking.
The activate and deactivate methods indicate to the input method whether a client component has the focus and therefore is the target of text input. Typically input methods only process events to compose text while they're active.
When an input method is active, certain types of events are dispatched to the input method using the java.awt.AWTEvent)">dispatchEvent method before they are processed by the client component. The input method decides for each event whether it wants to handle it. If it does, it marks the event as consumed so that it is not processed by the client component.
Note: For key events, input methods should use only KEY_TYPED events to obtain information about characters being entered, and use KEY_PRESSED or KEY_RELEASED events only to obtain information about function keys that don't result in KEY_TYPED events. The mapping from key-presses to characters depends on platforms, hardware, locales, and possibly other factors, and is best left to the underlying operating system.
As text is being composed and committed, the input method needs to inform the client component about all changes so that the client component can redraw the text. The input method does this by using java.text.AttributedCharacterIterator, int, java.awt.font.TextHitInfo, java.awt.font.TextHitInfo)">InputMethodContext.dispatchInputMethodEvent to construct and dispatch input method events to the client component. Depending on the current event flow model, the input method framework may redirect the events to its composition window. Dispatching input method events is the only way for Java input methods to have composed text displayed.
Composed text is usually marked up with highlight styles that indicate the current state of the conversion. This is accomplished by adding attributes to the text using the TextAttribute.INPUT_METHOD_HIGHLIGHT key and instances of InputMethodHighlight as values. Normally input methods only define abstract highlights (using the state and selected properties of the input method highlight) and leave the mapping to concrete styles to the rendering system. However, if desired, input methods can add concrete style information to the highlight using the style property. It is a good idea to design the concrete styles as variations of the styles provided returned by Toolkit.mapInputMethodHighlight.
Both the client component and the input method framework may recognize situations where the current composition needs to be ended and all composed text either committed or cancelled. They inform the input method about this need using the endComposition method. Note that endComposition may be called while the input method is not active.
Client components can influence composition using several methods. The java.lang.Character.Subset[])">InputContext.setCharacterSubsets method lets them restrict the subset of the Unicode character set that the input method is allowed to input. Input methods should generally not create characters outside of the specified subsets, and may switch to a different input mode that particularly supports the specified character subsets. The InputContext.setCompositionEnabled and isCompositionEnabled methods let them control and examine whether the current input method is enabled for composition. The InputContext.reconvert method lets them initiate reconversion.
6. Providing Engine-Specific Functionality
Some input methods may want to 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, and return instances through InputMethod.getControlObject. 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.
7. Packaging the Input Method
Input methods are packaged as installed extensions with specific content as described in the Input Methods" section of the SPI specification. One important aspect to consider is that all extensions installed in a Java application environment share the same name space. To avoid name collisions, input methods should follow the package naming conventions as described in the Java Language Specification. Similar conventions should be applied to naming non-class files that are packaged in the input method JAR file, such as dictionaries.
8. Sample Code
City Input Method is a simple input method that shows how to use the interfaces provided by the input method engine SPI.
- City Input Method documentation - tells you how to install and use this input method.
- City Input Method - a jar file containing the input method. Some browsers will automatically offer to download this file; others will show its contents in a window (not a pretty sight), and you then have to use the Save command to write it into a file. See the documentation for installation instructions.
- CityInputMethodDescriptor.java - the InputMethodDescriptor implementation for this input method.
- CityInputMethod.java - the InputMethod implementation for this input method.