aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports/inputcontext/inputcontextmodule.cpp
blob: 7dc124d083e4bc715530f1eeaf5877c1c1383670 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "inputcontextmodule.h"

#include "declarativeinputcontext.h"

#include <QtCore/qdebug.h>
#include <QtGui/qapplication.h>
#include <QtGui/qevent.h>
#include <QtGui/qtextformat.h>

QT_BEGIN_NAMESPACE

/*!
    \qmlmodule Qt.labs.inputcontext InputContextModule

    \brief The Qt.labs.inputcontext module provides an API for implementing input methods is QML.
*/

InputContextModule::InputContextModule(QObject *parent)
    : QObject(parent)
    , m_inputContext(qobject_cast<DeclarativeInputContext *>(qApp->inputContext()))
    , m_focusWidget(m_inputContext ? m_inputContext->focusWidget() : 0)
    , m_visible(false)
{
    if (m_inputContext)
        m_inputContext->setModule(this);
}

InputContextModule::~InputContextModule()
{
    if (m_inputContext)
        m_inputContext->setModule(0);
}

/*!
    \qmlproperty bool focus

    \inqmlmodule Qt.labs.inputcontext

    This property identifies whether an item that takes text input has active focus.
*/

bool InputContextModule::hasFocus() const
{
    return m_focusWidget != 0;
}

void InputContextModule::setFocusWidget(QWidget *widget)
{
    m_focusWidget = widget;

    if (!m_focusWidget)
        setVisible(false);

    emit focusChanged();
}

/*!
    \qmlproperty bool softwareInputPanelVisible

    \inqmlmodule Qt.labs.inputcontext

    This property identifies whether the item with focus has requested a
    software input panel.
*/

bool InputContextModule::isVisible() const
{
    return m_visible;
}

void InputContextModule::setVisible(bool visible)
{
    if (m_visible != visible) {
        m_visible = visible;

        emit visibleChanged();
    }
}

/*!
    \qmlproperty string preeditText

    \inqmlmodule Qt.labs.inputcontext

    This property holds the uncommited text that is displayed in the item that
    has focus.
*/

QString InputContextModule::preeditText() const
{
    return m_preeditText;
}

void InputContextModule::setPreeditText(const QString &text)
{
    if (text != m_preeditText)
        sendPreedit(text);
}

/*!
    \qmlproperty rectangle microFocus

    \inqmlmodule Qt.labs.inputcontext

    This property holds a rectangle in scene coordinates around the position
    of the cursor.
*/

QRect InputContextModule::microFocus() const
{
    return m_focusWidget
            ? m_focusWidget->inputMethodQuery(Qt::ImMicroFocus).toRect()
            : QRect();
}

/*!
    \qmlproperty font font

    \inqmlmodule Qt.labs.inputcontext

    This property holds the font of the text that currently has focus.
*/

QFont InputContextModule::font() const
{
    return m_focusWidget
            ? m_focusWidget->inputMethodQuery(Qt::ImFont).value<QFont>()
            : QFont();
}

/*!
    \qmlproperty int cursorPosition

    \inqmlmodule Qt.labs.inputcontext

    This property holds the position of the text cursor in the
    \l surroundingText.
*/

int InputContextModule::cursorPosition() const
{
    return m_focusWidget
            ? m_focusWidget->inputMethodQuery(Qt::ImCursorPosition).toInt()
            : 0;
}

/*!
    \qmlproperty int anchorPosition

    \inqmlmodule Qt.labs.inputcontext

    This property holds the position of the selection anchor in the
    \l surroundingText.  If no text is selected this is the same as the
    \l cursorPosition.
*/

int InputContextModule::anchorPosition() const
{
    return m_focusWidget
            ? m_focusWidget->inputMethodQuery(Qt::ImAnchorPosition).toInt()
            : 0;
}

/*!
    \qmlproperty int maximumTextLength

    \inqmlmodule Qt.labs.inputcontext

    This property holds the maximum number of characters that the item with
    focus can hold.  If there is no limit -1 is returned.
*/

int InputContextModule::maximumTextLength() const
{
    QVariant length;
    if (m_focusWidget)
        length = m_focusWidget->inputMethodQuery(Qt::ImMaximumTextLength);
    return length.isValid() ? length.toInt() : -1;
}

/*!
    \qmlproperty string surroundingText

    \inqmlmodule Qt.labs.inputcontext

    This property holds the plain text around the input area.  For example the
    current paragraph.
*/

QString InputContextModule::surroundingText() const
{
    return m_focusWidget
            ? m_focusWidget->inputMethodQuery(Qt::ImSurroundingText).toString()
            : QString();
}

/*!
    \qmlproperty string selectedText

    \inqmlmodule Qt.labs.inputcontext

    This property holds the currently selected text.
*/

QString InputContextModule::selectedText() const
{
    return m_focusWidget
            ? m_focusWidget->inputMethodQuery(Qt::ImCurrentSelection).toString()
            : QString();
}

/*!
    \qmlmethod sendKeyPress(int key, string text, int modifiers, bool autoRepeat)

    \inqmlmodule Qt.labs.inputcontext

    This method sends a key press event to the item that currently has focus.

    Int key is the code for the Qt::Key that the event loop should listen for.
    If key is 0, the event is not a result of a known key; for example, it may
    be the result of a compose sequence or keyboard macro. The modifiers holds
    the keyboard modifiers, and the given text is the Unicode text that the key
    generated. If autorep is true, isAutoRepeat() will be true. count is the
    number of keys involved in the event.
*/
void InputContextModule::sendKeyPress(
        int key, const QString &text, int modifiers, bool autoRepeat, int count)
{
    if (m_focusWidget) {
        QKeyEvent event(
                QEvent::KeyPress, key, Qt::KeyboardModifiers(modifiers), text, autoRepeat, count);
        if (!m_inputContext || !m_inputContext->filterKeyEvent(&event))
            QApplication::sendEvent(m_focusWidget, &event);
    }
}

/*!
    \qmlmethod sendKeyRelease(int key, string text, int modifiers)

    \inqmlmodule Qt.labs.inputcontext

    This method sends a key release event to the item that currently has focus.

    Int key is the code for the Qt::Key that the event loop should listen for.
    If key is 0, the event is not a result of a known key; for example, it may
    be the result of a compose sequence or keyboard macro. The modifiers holds
    the keyboard modifiers, and the given text is the Unicode text that the key
    generated. count is the number of keys involved in the event.
*/
void InputContextModule::sendKeyRelease(int key, const QString &text, int modifiers, int count)
{
    if (m_focusWidget) {
        QKeyEvent event(
                QEvent::KeyRelease, key, Qt::KeyboardModifiers(modifiers), text, false, count);
        if (!m_inputContext || !m_inputContext->filterKeyEvent(&event))
            QApplication::sendEvent(m_focusWidget, &event);
    }
}

/*!
    \qmlmethod sendPreedit(string text, int cursor = -1)

    \inqmlmodule Qt.labs.inputcontext

    Sends a pre-edit event to the item with active focus.

    This will set \l preeditText to \a text, and position the text \a cursor
    within the pre-edit text.  If the value of cursor is -1 the cursor will be
    positioned at the end of the pre-edit text.
*/
void InputContextModule::sendPreedit(const QString &text, int cursor)
{
    const QString preedit = m_preeditText;
    m_preeditText = text;

    if (m_inputContext) {
        QList<QInputMethodEvent::Attribute> attributes;

        if (cursor >= 0 && cursor <= text.length()) {
            attributes.append(QInputMethodEvent::Attribute(
                    QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
        } else {
            cursor = text.length();
        }

        if (cursor > 0) {
            attributes.append(QInputMethodEvent::Attribute(
                    QInputMethodEvent::TextFormat,
                    0,
                    cursor,
                    m_inputContext->standardFormat(QInputContext::PreeditFormat)));
        }
        if (cursor < text.length()) {
            attributes.append(QInputMethodEvent::Attribute(
                    QInputMethodEvent::TextFormat,
                    cursor,
                    text.length(),
                    m_inputContext->standardFormat(QInputContext::SelectionFormat)));
        }

        m_inputContext->sendEvent(QInputMethodEvent(text, attributes));
    }

    if (m_preeditText != preedit)
        emit preeditTextChanged();
}


/*!
    \qmlmethod commit()

    \inqmlmodule Qt.labs.inputcontext

    Commits \l preeditText to the item with active focus.
*/
void InputContextModule::commit()
{
    // Create an explicit copy of m_preeditText as the reference value is cleared before sending
    // the event.
    commit(QString(m_preeditText));
}

/*!
    \qmlmethod commit(string)

    \inqmlmodule Qt.labs.inputcontext

    Commits \a text to the item with active focus and clears the current
    \l preeditText.  The text will be inserted into the \l surroundingText at a
    position \a replacementStart relative to the \l cursorPosition and will
    replace \a replacementLength characters.
*/
void InputContextModule::commit(const QString &text, int replacementStart, int replacementLength)
{
    const QString preedit = m_preeditText;
    m_preeditText.clear();

    if (m_inputContext) {
        QInputMethodEvent inputEvent;
        inputEvent.setCommitString(text, replacementStart, replacementLength);
        m_inputContext->sendEvent(inputEvent);
    }

    if (m_preeditText != preedit)
        emit preeditTextChanged();
}

/*!
    \qmlmethod clear()

    \inqmlmodule Qt.labs.inputcontext

    Clears the current \l preeditText.
*/
void InputContextModule::clear()
{
    const QString preedit = m_preeditText;
    m_preeditText.clear();

    if (m_inputContext)
        m_inputContext->sendEvent(QInputMethodEvent());

    if (m_preeditText != preedit)
        emit preeditTextChanged();
}

void InputContextModule::update()
{
    emit contextUpdated();
}

QT_END_NAMESPACE