Qtopia Home - Classes - Hierachy - Annotated - Functions - Qt Embedded

Input Methods

Introduction

There are two kinds of Input Methods supported in Qtopia 2.x, Popup Input Methods and Composing Input Methods.

Popup Input Methods are used when there is no Keyboard or other text input device. They popup a widget where the user can interact with via the touch screen of a device to generate key events. They can also be thought of as Pen Based Input Methods.

Composing Input Methods are used to extend or transform the text from a separate text based input device. This can be a keyboard, keypad, or a Popup Input Method. They are called Composing Input Methods because they provide a compose step between the text generated by the widget, and that accepted by the current widget with keyboard focus.

Currently in 2.x it is not possible to create an input method that is both a Popup Input Method and a Composing Input Method.

The two Interfaces to create Input Method plugins are InputMethodInterface and ExtInputMethodInterface. InputMethodInterface can only be used to create Popup Input Methods, and will only have access to the 1.5.x API. ExtInputMethodInterface can be used to create either Popup Input Methods or Composing Input Methods. However they can not be installed on devices with a Qtopia version earlier than 1.6.

Examples of Qtopia input methods can be found in the examples/inputmethods directory of the Qtopia source code.

How to create a Popup Input Method

Popup Input Methods must supply a QWidget that will be shown on the screen and emit a signal when a key is pressed. Qtopia handles showing and hiding the input widget as appropriate. It is possible to start development of a Popup Input Method in a single application that contains the Popup Input Method being developed and QMultiLineEdit to test the text output. After the widget for the Popup Input Method is tested, you will need to turn it into a plugin.

The input method in this example is a very simple virtual keyboard. It contains the keys A, B, C and D.

Designing the Widget for a Popup Input Method

The interface for our popup widget is quite simple.

#include <qwidget.h>

class PopupIM : public QWidget
{
    Q_OBJECT
public:
    PopupIM(QWidget *parent, const char *name = 0, int flags = 0);
    ~PopupIM();

signals:
    void keyPress( ushort unicode, ushort keycode,
            ushort modifiers, bool press, bool repeat );
};

Most important as the keyPress signal. Later you will need to connect this signal to Qtopia, so it is important that it is compatible with the slot that will be provided.

The parameters of the keyPress signal are:

Parameter Notes
unicode The unicode value of the character, or 0xFFFF if it is a non-printing key.
keycode The key code as specified in qnamespace.h
modifiers A combination of zero or more of the following OR'ed together: Qt::ShiftButton, Qt::ControlButton and Qt::AltButton
press TRUE for a key press, FALSE for a key release.
repeat TRUE if this is a repeating keypress. Repeating key presses are the additional events that occur when a key is held down for a period of time.

To make our Popup Input Method widget into a virtual keyboard, we will need some virtual keys and to lay them out on our PopupIM widget.

class PopupPushButton : public QPushButton
{
    Q_OBJECT
public:
    PopupPushButton ( const QChar uni, ushort key, QWidget *parent )
        : QPushButton(parent), u(uni), k(key)
    {
        connect(this, SIGNAL(pressed()), this, SLOT(sendKeyForPress()));
        connect(this, SIGNAL(released()), this, SLOT(sendKeyForRelease()));
        setText(QChar(uni));
    }
signals:
    void keyPress(ushort, ushort, ushort, bool, bool);

private slots:
    void sendKeyForPress()
    {
        emit keyPress(u.unicode(), k, 0, TRUE, FALSE);
    }
    void sendKeyForRelease()
    {
        emit keyPress(u.unicode(), k, 0, FALSE, FALSE);
    }
private:
    QChar u;
    ushort k;
};

This makes a good virtual key as it records the information needed for the key in itself. It isn't able to add modifiers, or generate repeating keys, but it is sufficent to input a character as either text or a key code.

The constructor for our PopupIM simply lays the virtual keys in a grid and connects their signals to its own.


PopupIM::PopupIM(QWidget *parent, const char *name, int flags)
    : QWidget(parent, name, flags)
{
    QGridLayout *gl = new QGridLayout(this, 2,2);
    PopupPushButton *ppb;

    ppb = new PopupPushButton(QChar('A'), Qt::Key_A, this);
    connect(ppb, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)),
            this, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)));
    gl->addWidget(ppb, 0, 0);
    ppb = new PopupPushButton(QChar('B'), Qt::Key_B, this);
    connect(ppb, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)),
            this, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)));
    gl->addWidget(ppb, 0, 1);
    ppb = new PopupPushButton(QChar('C'), Qt::Key_C, this);
    connect(ppb, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)),
            this, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)));
    gl->addWidget(ppb, 1, 0);
    ppb = new PopupPushButton(QChar('D'), Qt::Key_D, this);
    connect(ppb, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)),
            this, SIGNAL(keyPress(ushort, ushort, ushort, bool, bool)));
    gl->addWidget(ppb, 1, 1);
}

Creating an InputMethodInterface plugin

Because Popup Input Methods are usually simple its better to use the InputMethodInterface to turn it into a plugin so it will be usable with Qtopia 1.5 devices. However it is also possible to use the ExtInputMethodInterface as explained in the next section.

The definition of the plugin interface is:

#include <qpe/inputmethodinterface.h>

class PopupIMImpl : public InputMethodInterface
{
public:
    PopupIMImpl();
    ~PopupIMImpl();

#ifndef QT_NO_COMPONENT
    QRESULT queryInterface( const QUuid&, QUnknownInterface** );
    Q_REFCOUNT
#endif

    QWidget *inputMethod( QWidget *parent, Qt::WFlags f );
    void resetState();
    QPixmap *icon();
    QString name();
    void onKeyPress( QObject *receiver, const char *slot );

private:
    PopupIM *input;
    QPixmap *icn;
    ulong ref;
};

The constructor and destructor are very simple:

PopupIMImpl::PopupIMImpl()
    : input(0), icn(0), ref(0)
{
}

PopupIMImpl::~PopupIMImpl()
{
    if (input)
        delete input;
    if (icn)
        delete icn;
}

The queryInterface() function can be implemented using the following boilerplate code:

QRESULT PopupIMImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
{
    *iface = 0;
    if ( uuid == IID_QUnknown )
        *iface = this;
    else if ( uuid == IID_InputMethod )
        *iface = this;
    else
        return QS_FALSE;

    (*iface)->addRef();
    return QS_OK;
}

The inputMethod() function returns the input method widget. This widget will be display on the screen when the user needs to input text. You should always return the same widget if this function is called multiple times.

QWidget *PopupIMImpl::inputMethod( QWidget *parent, Qt::WFlags f )
{
    if ( !input )
        input = new PopupIM( parent, "SimpleInput", f );
    return input;
}

The resetState() function should return the input method to its default state. However since our PopupIM keeps no state it can be implemented with the empty function.

void PopupIMImpl::resetState() { }

The name() function returns the name of the input method. This will be displayed in the popup list of available input methods.

QString PopupIMImpl::name()
{
    return qApp->translate( "InputMethods", "SimpleInput" );
}

The icon() function returns the icon for the input method. This will be displayed in the taskbar when the input method is selected.

QPixmap *PopupIMImpl::icon()
{
    if ( !icn )
        icn = new QPixmap( your pixmap );
    return icn;
}

The onKeyPress() function must connect the supplied slot to the signal that is emitted when a key press is generated.

The following code will connect the signal to the supplied slot:

void PopupIMImpl::onKeyPress( QObject *receiver, const char *slot )
{
    if ( input )
        QObject::connect( input, SIGNAL(keyPress(ushort,ushort,ushort,bool,bool)), receiver, slot );
}

You must also create an instance of the input method plugin using the following boilerplate code:

Q_EXPORT_INTERFACE()
{
    Q_CREATE_INSTANCE( PopupIMImpl )
}

Creating an ExtInputMethodInterface plugin

If your Popup Input Method uses parts of the Qtopia API from 1.6 or onwards you may want to use the ExtInputMethodInterface. While the interface does have more functions, for a Popup Input Method most of them can be set to null functions.

#include <qpe/inputmethodinterface.h>

class PopupIMExtImpl : public ExtInputMethodInterface
{

public:
    PopupIMExtImpl();
    ~PopupIMExtImpl();

#ifndef QT_NO_COMPONENT
    QRESULT queryInterface( const QUuid&, QUnknownInterface** );
    Q_REFCOUNT
#endif
    QString name();
    QPixmap *icon();

    QWidget *keyboardWidget( QWidget *parent, Qt::WFlags f);

    void resetState() {}

    QStringList compatible() { return QStringList(); }

    QWSInputMethod *inputMethod( ) { return 0; }

    QWidget *statusWidget( QWidget *parent, Qt::WFlags f) { return 0; }

    void qcopReceive( const QCString &msg, const QByteArray &data ) { }
private:
    PopupIM *input;
    ulong ref;
};

The constructor and destructor can be rather simply implemented

PopupIMExtImpl::PopupImExtImpl()
    : input(0), icn(0), ref(0)
{
}

PopupIMExtImpl::~PopupIMExtImpl()
{
    if (input)
        delete input;
    if (icn)
        delete icn;
}

The queryInterface() function can be implemented using the following boilerplate code:

QRESULT PopupIMExtImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
{
    *iface = 0;
    if ( uuid == IID_QUnknown )
        *iface = this;
    else if ( uuid == IID_InputMethod )
        *iface = this;
    else
        return QS_FALSE;

    (*iface)->addRef();
    return QS_OK;
}

The name() function returns the name of the input method. This will be displayed in the popup list of available input methods.

QString PopupIMExtImpl::name()
{
    return qApp->translate( "InputMethods", "SimpleInput" );
}

The icon() function returns the icon for the input method. This will be displayed in the taskbar when the input method is selected.

QPixmap *PopupIMExtImpl::icon()
{
    if ( !icn )
        icn = new QPixmap( your pixmap );
    return icn;
}

The keyboardWidget() function should return the widget for the Popup Input Method.

QWidget *keyboardWidget( QWidget *parent, Qt::WFlags f)
{
    if (!input) {
        input = new PopupIM( parent, "SimpleInput", f );
    }
    return input;
}

The resetState() function should return the input method to its default state. However since our PopupIM keeps no state it can be implemented with the empty function.

The compatible() function should return the list of compatible plugins that this plugin can work at the same time with, or the empty list for no restriction.

The inputMethod() function does not apply to a Popup Input Method and should return 0.

The statusWidget() function does not apply to a Popup Input Method and should return 0.

The qcopReceive() function is called to notify the plugin of events on the inputmethod channel. As our plugin doesn't interpret any events on the inputmethod channel this can be an empty function.

Example message the input method might want to respond to include:

You must also create an instance of the input method plugin using the following boilerplate code:

Q_EXPORT_INTERFACE()
{
    Q_CREATE_INSTANCE( PopupIMImpl )
}

Building the plugin

Building the input method plugin is the same for either InputMethodInterface or ExtInputMethodInterface.

In you .pro file to build your plugin you will need to add qtopiaplugin to the CONFIG and set the QTOPIA_PROJECT_TYPE to inputmethods.

Also set a TARGET and specify your SOURCES and HEADERS.

TARGET       = popupim

CONFIG      += qtopiaplugin
HEADERS      = popupim.h popupimpl.h
SOURCES      = popupim.cpp popupimpl.cpp

QTOPIA_PROJECT_TYPE=inputmethods

To create the Makefile, run

qmake -spec $QPEDIR/mkspecs/qws/linux-generic-g++ popup.pro

How to create a Composing Input Method

Composing Input Methods filter key events from the server rather than generating key events itself. When built as a plugin Qtopia will handle adding and removing the filter to the server as appropriate.

Designing the Filter for a Composing Input Method

The main class of a composing input method inherits from QWSInputMethod. It filters all keyboard events before they are sent to the application that has keyboard focus. A minimal input method could look like this:

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

    void reset();
    bool filter(int unicode, int keycode, int modifiers, 
                            bool isPress, bool autoRepeat);
    
    enum State { Off, On };

private:
    State state;
    QString composed;
};

The QWSInputMethod::filter() function is the central part of the input method. It implements the composition logic and maintains state. It uses QWSInputMethod::sendIMEvent() to send input method events.

The parameters of the filter function are:

Parameter Notes
unicode The unicode value of the character, or 0xFFFF if it is a non-printing key.
keycode The key code as specified in qnamespace.h
modifiers A combination of zero or more of the following OR'ed together: Qt::ShiftButton, Qt::ControlButton and Qt::AltButton
press TRUE for a key press, FALSE for a key release.
repeat TRUE if this is a repeating keypress. Repeating key presses are the additional events that occur when a key is held down for a period of time.

The function QWSInputMethod::reset() is called from the system when the input method needs to reset state. For example when the focus widget changes.

Other functions include QWSInputMethod::setMicroFocus() which is called when the cursor position changes inside the focus widget, and QWSInputMethod::mouseHandler() which is called when the user clicks inside the composed text.

The constructor and destructor can be implemented simply:

ComposeIM::ComposeIM()
{
    state = Off;
}

ComposeIM::~ComposeIM()
{
}

The reset() function needs to return the IM to an initial state. As there may be uncomposed text still, it is better to apply the composed text when ending any active compose actions.

void ComposeIM::reset()
{
    if ( state == On ) {
        state = Off;
        sendIMEvent( QWSServer::IMEnd, composed, 0 );
        composed = "";
    }
}

The filter() function filters key events from the server. The code below provides a way for the input method to be turned on or off, as well as transforming the text. The example below will turn on or off based of a combination of Shift+Space, and otherwise uses the compose function to transform the current text. The filter function returns TRUE to block the original key event, and FALSE to let the original key event pass on to the current application and focus widget. It generates additional input events with the sendIMEvent function. This is documented in the class documentation for QWSInputMethod.

bool ComposeIM::filter(int unicode, int keycode, int modifiers, 
  bool isPress, bool autoRepeat)
{
    if ( isPress && keycode == Qt::Key_Space && 
         modifiers & Qt::ShiftButton ) {
        //switch to opposite state
        if ( state == On ) {
            sendIMEvent( QWSServer::IMEnd, QString::null, 0 );
            composed = "";
            state = Off; //reset and remove text
        } else {
            state = On;
        }
        return TRUE; //block event
    } else if ( state == On ) {
        if ( isPress ) {
            if ( keycode == Qt::Key_Return ) {
                //accept text and remain active
                sendIMEvent( QWSServer::IMEnd, composed, composed.length() );
                composed = "";
            } else if ( keycode == Qt::Key_Backspace ) {
                if ( composed.length() > 0 )
                    composed = composed.left( composed.length() - 1 );
                sendIMEvent( QWSServer::IMCompose, composed, composed.length(), 0 );
            } else if ( unicode > 0 && unicode < 0xffff) {
                composed += QChar( unicode );
                // transform the given text before sending to the input widget
                composed = compose( composed );
                sendIMEvent( QWSServer::IMCompose, composed, composed.length(), 0 );
            }
        }
        return TRUE; //block event
    }  
    return FALSE; //pass keystroke normally.
}

Creating an ExtInputMethodInterface plugin

Composing Input Methods must use the ExtInputMethodInterface when being made into a plugin for Qtopia.

For our example the interface can be:

class ComposeImpl : public ExtInputMethodInterface
{

public:
    ComposeImpl();
    virtual ~ComposeImpl();

#ifndef QT_NO_COMPONENT
    QRESULT queryInterface( const QUuid&, QUnknownInterface** );
    Q_REFCOUNT
#endif
    virtual QString name();
    virtual QPixmap *icon();

    virtual void resetState();

    virtual QStringList compatible();

    virtual QWSInputMethod *inputMethod( );

    virtual QWidget *statusWidget( QWidget *parent, Qt::WFlags f);
    virtual QWidget *keyboardWidget( QWidget *parent, Qt::WFlags f) { return 0; }

    virtual void qcopReceive( const QCString &msg, const QByteArray &data ) { }

private:
    ComposeIM *input;
    QPixmap *icn;
    QWidget *statWid;
    ulong ref;
};

The queryInterface() function can be implemented using the following boilerplate code:

QRESULT ComposeImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
{
    *iface = 0;
    if ( uuid == IID_QUnknown )
        *iface = this;
    else if ( uuid == IID_ExtInputMethod )
        *iface = this;
    else
        return QS_FALSE;

    (*iface)->addRef();
    return QS_OK;
}

The name() function returns the name of the input method. This will be displayed in the popup list of available input methods.

QString ComposeImpl::name()
{
    return qApp->translate( "InputMethods", "SimpleInput" );
}

The icon() function returns the icon for the input method. This is less relavent to composing input methods as they can provide a statusWidget instead.

QPixmap *ComposeImpl::icon()
{
    if ( !icn )
        icn = new QPixmap( your pixmap );
    return icn;
}

The resetState() function should return the input method to its orignal state.

void ComposeImpl::resetState()
{
    if ( input )
        input->reset();
}

The compatible() function can be used to say that this input method is only compatible with certain other input methods. In this case the empty list is returned to indicate there are no restrictions.

QStringList ComposeImpl::compatible( )
{
    return QStringList();
}

The inputMethod() function returns the QWSInputMethod described int the previous section. It should return the same pointer if this function is called multiple times only creating the input method once.

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

The statusWidget() function returns the widget that will be placed in the header or taskbar when the input method is selected. This widget is typically used to display status, and can also be used to let the user interact with the input method.

QWidget *ComposeImpl::statusWidget( QWidget *parent, Qt::WFlags )
{
    if (!statWid) {
        (void) inputMethod(); //create input before we use it
        statWid  = new IMStatus( input, parent);
    }
    return statWid;
}

The keyboardWidget() function does not apply to a Composing Input Method and should return 0.

The qcopReceive() function is called to notify the plugin of events on the inputmethod channel. As our plugin doesn't interpret any events on the inputmethod channel this can be an empty function.

Example message the input method might want to respond to include:

You must also create an instance of the input method plugin using the following boilerplate code:

Q_EXPORT_INTERFACE()
{
    Q_CREATE_INSTANCE( PopupIMImpl )
}

Building the plugin

In you .pro file to build your plugin you will need to add qtopiaplugin to the CONFIG and set the QTOPIA_PROJECT_TYPE to inputmethods.

Also set a TARGET and specify your SOURCES and HEADERS.

TARGET       = composeim

CONFIG      += qtopiaplugin
HEADERS      = composeim.h composeimpl.h
SOURCES      = composeim.cpp composeimpl.cpp

QTOPIA_PROJECT_TYPE=inputmethods

To create the Makefile, run

qmake -spec $QPEDIR/mkspecs/qws/linux-generic-g++ composing.pro


Copyright © 2001-2005 Trolltech Trademarks
Qtopia version 2.1.1