Home · All Namespaces · All Classes · Grouped Classes · Modules · Functions codeless banner

Tutorial: Create an Input method Plug-in that Modifies Keyboard Input

Creating a Text Input Filter

This is a very simple example of how to write a composing input method, the code described can be found in <qt-extended-root-dir>/examples/inputmethods/composing.

Qt for Embedded Linux provides the QWSInputMethod class to allow modification of keyboard or pointer input to generate text. At a minimum you will need to provide an implementation for one of the two filter functions available depending on whether you intend to filter mouse or keyboard input. You will also need to provide an implementation for the reset function.

In our example we filter keyboard so that pressing the shift key will change the case of the most recently typed letter.

    #include <Qt/qwindowsystem_qws.h>
    #include <qtopia/inputmethodinterface.h>

    class ComposeIM : public QWSInputMethod
    {
    public:
        ComposeIM();
        ~ComposeIM();

        void reset();
        bool filter(int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat);

        void setActive(bool);
        bool active() const { return isActive; }

    private:
        QString lastText;
        bool upper;
        bool isActive;
    };

In addition to the filter and reset functions, we also have an Active property used to turn the input method on and off. The string variable lastText stores the previously typed letter and upper stores the case of the letter.

    bool ComposeIM::filter(int unicode, int keycode, int modifiers,
            bool isPress, bool autoRepeat)
    {
        Q_UNUSED(autoRepeat);

        if (!isActive)
            return false;

        if ((keycode > Qt::Key_Z || keycode < Qt::Key_A) && keycode != Qt::Key_Shift) {
            reset();
            return false;
        }

        if (isPress) {
            if (keycode == Qt::Key_Shift) {
                lastText = upper ? lastText.toLower() : lastText.toUpper();
                upper = !upper;
                sendPreeditString(lastText, 0);
            } else {
                if (!lastText.isEmpty())
                    sendCommitString(lastText);

                lastText = QChar(unicode);
                upper = (modifiers & Qt::ShiftModifier) == Qt::ShiftModifier;
                sendPreeditString(lastText, 0);
            }
        }
        return true;
    }

The filter function is called for every key that is pressed and returns:

The function for this example only filters when active and the key is A-Z or Shift.

The call to sendPreeditString sends text to the current text input widget and indicates to the input widget that it has not been confirmed by the user. Generally Qt text input widget will underline pre-edit text. sendCommitString sends text to the current text input widget and indicates to the widget that the text has been confirmed by the user. For our input method pressing Shift will send the previous text again with a different text. Pressing the keys A-Z will confirm the text for the last key pressed and send a new pre-edit text. Any other key will result in the input method resetting, which will clear the pre-edit text.

See also: QWSInputMethod::sendPreeditString(), QWSInputMethod::sendCommitString() for more information.

    void ComposeIM::reset()
    {
        if (!lastText.isEmpty())
            sendCommitString(lastText);
        upper = false;
        lastText = QString::null;
    }

The reset function is called when the focus changes between widgets. Our input method example will confirm any currently tentative text and then reset to its initial state. In the previous function we saw that sending a key that was not A-Z or Shift would result in a reset, and then not filter the key. For this input method that means a space will confirm the character, and then as it is unfiltered will then send the space so that both the letter and the space arrive at the input widget in the correct order. More importantly though, a Backspace will cause the tentative character to be committed then deleted. It is important to ensure your input method handles keys like Backspace correctly.

    ComposeIM::ComposeIM()
        : QWSInputMethod(),
        upper(false), isActive(false)
    {
    }

    ComposeIM::~ComposeIM()
    {
    }

    void ComposeIM::setActive(bool b)
    {
        if (b && b != isActive) {
            lastText.clear();
            upper = false;
        }
        isActive = b;
    }

The remaining functions merely manage the state of the input method. It is possible to use this class in a stand-alone Qt for Embedded Linux application by constructing it and passing it to QWSServer::setCurrentInputMethod(). We will now show how to integrate the class into a Qt Extended Input Method plug-in.

Creating the Containing Plug-in

Qt Extended allows for input methods to be loaded via plug-ins. This means you can extend the input capabilities of Qt Extended after it has been installed. However since Qt Extended provides for a range of different methods to provide text input, the plug-in also needs to describe the capabilities and requirements of the input method.

    #include <qtopia/inputmethodinterface.h>
    class ComposeIM;

    class ComposeImpl : public QtopiaInputMethod
    {

    public:
        ComposeImpl(QObject *parent = 0);
        ~ComposeImpl();


        QString name() const;
        QString identifier() const;

        QIcon icon() const;
        QString version() const;

        int properties() const;

        State state() const;

        void reset();

        QWSInputMethod *inputModifier();

        void setHint(const QString &, bool);
    private:
        ComposeIM *input;
        QIcon icn;
        ulong ref;
    };

The following table and the QtopiaInputMethod class documentation describe the functions used:

FunctionDescription
nameReturns a string identifying the plug-in that is translated for display to the user of the device.
identifierReturns a string identifying the plugin-in that is not translated but is suitable for identifying the plug-in.
iconReturns an Icon to display to the user while the plug-in is active.
versionReturns a version string describing the version of the plug-in.
propertiesdescribes the capabilities and requirements of the plug-in. The return value is determined by the content of the flags provided in QtopiaInputMethod::Properties
stateReturns whether the input method plug-in is:
  • QtopiaInputMethod::Ready: processing text input
  • QtopiaInputMethod::Sleeping: not processing text input.
resetcalled when the plug-in is unloaded or needs to be returned to its initial state by the server. It resets the plug-in to its state at construction.
inputModifierReturns the QWSInputMethod object if the plug-in modifes keyboard or mouse input to generate text for a text input widget.

Note: While setHint does not have to be re-implemented it is highly recommended. Qt Extended calls this function with a:

Typical types of input are:

However, applications can also define custom hints such as email so the input method should be able to handle hints it does not recognize and have some fall back mode if it is going to attempt to do more than simply activate on a non-null hint. In this example we will activate the input method only for the text and words hints.

Apart from the input and icon properties specific to this example, an unsigned long ref property is required for all Qt Extended plug-ins. It is used to keep a reference of where the input method is used and when it can be safely unloaded.

For a complete list of the composing input method plug-in implementation, see <qt-extended-root-dir>/examples/inputmethods/composing/composeimpl.cpp. This is a listing of the more critical code that needs to be included.

    ComposeImpl::ComposeImpl(QObject *parent)
        : QtopiaInputMethod(parent), input(0), ref(0)
        {
        // construct icon
        }

Note: It is important to construct the plug-in with an appropriate parent and to set the value of ref to 0 in the constructor.

    QWSInputMethod *ComposeImpl::inputModifier( )
    {
        if ( !input )
            input = new ComposeIM( );
        return input;
    }

Returns the QWSInputMethod provided by the plug-in. If it has not constructed one already it should construct it now.

    void ComposeImpl::setHint(const QString &hint, bool)
    {
        inputModifier();
        if (hint.isEmpty() || hint == "numbers" || hint == "phone") {
            if (input->active()) {
                input->setActive(false);
                emit stateChanged(Sleeping);
            }
        } else if (!input->active()) {
            input->setActive(true);
            emit stateChanged(Ready);
        }
    }

    QtopiaInputMethod::State ComposeImpl::state() const
    {
        return (input && input->active()) ? Ready : Sleeping;
    }

As the example input method deals with the capitalization of text it should be inactive when the input required is either a number or a phone number. Custom hints might still require changing capitalization so the default is to be on if the hint is not recognized. The input method status is communicated to the server by the stateChanged() signal and the state() function.

    int ComposeImpl::properties() const
    {
        return RequireKeypad | InputModifier;
    }

Our input method requires the device has keyboard or keypad input and also filters either keyboard/keypad or mouse events. This is represented by returning the combination of these flags for the properties. The properties of an input method are not expected to change.

    QTOPIA_EXPORT_PLUGIN(ComposeImpl)

This macro is required to provide the code required to implement the functions allowing the plug-in to be queried and loaded.


Copyright © 2009 Trolltech Trademarks
Qt Extended 4.4.3