~timo-jyrinki/ubuntu/trusty/maliit-framework/fix_qt52

« back to all changes in this revision

Viewing changes to .pc/0004-fix_activationlostevent.patch/input-context/minputcontext.cpp

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo, Sergio Schvezov, Ricardo Salveti de Araujo
  • Date: 2013-07-23 19:47:04 UTC
  • mfrom: (1.1.2) (1.2.1 experimental)
  • Revision ID: package-import@ubuntu.com-20130723194704-1lsy1kmlda069cea
Tags: 0.99.0+git20130615+97e8335-0ubuntu1
[ Sergio Schvezov ]
* New build from HEAD 97e8335.
* Packaging import from lp:phablet-extras/maliit-framework.

[ Ricardo Salveti de Araujo ]
* debian/control: adding vcs and fixing dependencies
* General package cleanup

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* * This file is part of Maliit framework *
 
2
 *
 
3
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 
4
 * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 
5
 * Copyright (C) 2013 Jolla Ltd.
 
6
 *
 
7
 * All rights reserved.
 
8
 *
 
9
 * Contact: maliit-discuss@lists.maliit.org
 
10
 *
 
11
 * This library is free software; you can redistribute it and/or
 
12
 * modify it under the terms of the GNU Lesser General Public
 
13
 * License version 2.1 as published by the Free Software Foundation
 
14
 * and appearing in the file LICENSE.LGPL included in the packaging
 
15
 * of this file.
 
16
 */
 
17
 
 
18
 
 
19
#include "minputcontext.h"
 
20
 
 
21
#include <QGuiApplication>
 
22
#include <QKeyEvent>
 
23
#include <QTextFormat>
 
24
#include <QDebug>
 
25
#include <QByteArray>
 
26
#include <QRectF>
 
27
#include <QLocale>
 
28
#include <QWindow>
 
29
#include <QSharedDataPointer>
 
30
#include <QQuickItem>
 
31
 
 
32
namespace
 
33
{
 
34
    const int SoftwareInputPanelHideTimer = 100;
 
35
    const char * const InputContextName = "MInputContext";
 
36
 
 
37
    int orientationAngle(Qt::ScreenOrientation orientation)
 
38
    {
 
39
        switch (orientation) {
 
40
        case Qt::PrimaryOrientation: // Urgh.
 
41
        case Qt::PortraitOrientation:
 
42
            return MInputContext::Angle270;
 
43
        case Qt::LandscapeOrientation:
 
44
            return MInputContext::Angle0;
 
45
        case Qt::InvertedPortraitOrientation:
 
46
            return MInputContext::Angle90;
 
47
        case Qt::InvertedLandscapeOrientation:
 
48
            return MInputContext::Angle180;
 
49
        }
 
50
        return MInputContext::Angle0;
 
51
    }
 
52
}
 
53
 
 
54
bool MInputContext::debug = false;
 
55
 
 
56
 
 
57
MInputContext::MInputContext()
 
58
    : imServer(0),
 
59
      active(false),
 
60
      inputPanelState(InputPanelHidden),
 
61
      preeditCursorPos(-1),
 
62
      redirectKeys(false)
 
63
{
 
64
    QByteArray debugEnvVar = qgetenv("MALIIT_DEBUG");
 
65
    if (!debugEnvVar.isEmpty() && debugEnvVar != "0") {
 
66
        qDebug() << "Creating Maliit input context";
 
67
        debug = true;
 
68
    }
 
69
 
 
70
    QSharedPointer<Maliit::InputContext::DBus::Address> address(new Maliit::InputContext::DBus::DynamicAddress);
 
71
    imServer = new DBusServerConnection(address);
 
72
 
 
73
    sipHideTimer.setSingleShot(true);
 
74
    sipHideTimer.setInterval(SoftwareInputPanelHideTimer);
 
75
    connect(&sipHideTimer, SIGNAL(timeout()), SLOT(sendHideInputMethod()));
 
76
 
 
77
    connectInputMethodServer();
 
78
}
 
79
 
 
80
MInputContext::~MInputContext()
 
81
{
 
82
    delete imServer;
 
83
}
 
84
 
 
85
void MInputContext::connectInputMethodServer()
 
86
{
 
87
    connect(imServer, SIGNAL(connected()), this, SLOT(onDBusConnection()));
 
88
    connect(imServer, SIGNAL(disconnected()), this, SLOT(onDBusDisconnection()));
 
89
 
 
90
    // Hook up incoming communication from input method server
 
91
    connect(imServer, SIGNAL(activationLostEvent()), this, SLOT(activationLostEvent()));
 
92
 
 
93
    connect(imServer, SIGNAL(imInitiatedHide()), this, SLOT(imInitiatedHide()));
 
94
 
 
95
    connect(imServer, SIGNAL(commitString(QString,int,int,int)),
 
96
            this, SLOT(commitString(QString,int,int,int)));
 
97
 
 
98
    connect(imServer, SIGNAL(updatePreedit(QString,QList<Maliit::PreeditTextFormat>,int,int,int)),
 
99
            this, SLOT(updatePreedit(QString,QList<Maliit::PreeditTextFormat>,int,int,int)));
 
100
 
 
101
    connect(imServer, SIGNAL(keyEvent(int,int,int,QString,bool,int,Maliit::EventRequestType)),
 
102
            this, SLOT(keyEvent(int,int,int,QString,bool,int,Maliit::EventRequestType)));
 
103
 
 
104
    connect(imServer, SIGNAL(updateInputMethodArea(QRect)),
 
105
            this, SLOT(updateInputMethodArea(QRect)));
 
106
 
 
107
    connect(imServer, SIGNAL(setGlobalCorrectionEnabled(bool)),
 
108
            this, SLOT(setGlobalCorrectionEnabled(bool)));
 
109
 
 
110
    connect(imServer, SIGNAL(getPreeditRectangle(QRect&,bool&)),
 
111
            this, SLOT(getPreeditRectangle(QRect&,bool&)));
 
112
 
 
113
    connect(imServer, SIGNAL(invokeAction(QString,QKeySequence)), this, SLOT(onInvokeAction(QString,QKeySequence)));
 
114
 
 
115
    connect(imServer, SIGNAL(setRedirectKeys(bool)), this, SLOT(setRedirectKeys(bool)));
 
116
 
 
117
    connect(imServer, SIGNAL(setDetectableAutoRepeat(bool)),
 
118
            this, SLOT(setDetectableAutoRepeat(bool)));
 
119
 
 
120
    connect(imServer, SIGNAL(setSelection(int,int)),
 
121
            this, SLOT(setSelection(int,int)));
 
122
 
 
123
    connect(imServer, SIGNAL(getSelection(QString&,bool&)),
 
124
            this, SLOT(getSelection(QString&, bool&)));
 
125
 
 
126
    connect(imServer, SIGNAL(setLanguage(QString)),
 
127
            this, SLOT(setLanguage(QString)));
 
128
}
 
129
 
 
130
 
 
131
bool MInputContext::isValid() const
 
132
{
 
133
    return true;
 
134
}
 
135
 
 
136
void MInputContext::setLanguage(const QString &language)
 
137
{
 
138
    QLocale newLocale(language);
 
139
    Qt::LayoutDirection oldDirection = inputDirection();
 
140
 
 
141
    if (newLocale != inputLocale) {
 
142
        inputLocale = newLocale;
 
143
        emitLocaleChanged();
 
144
    }
 
145
 
 
146
    Qt::LayoutDirection newDirection = inputDirection();
 
147
    if (newDirection != oldDirection) {
 
148
        emitInputDirectionChanged(newDirection);
 
149
    }
 
150
}
 
151
 
 
152
void MInputContext::reset()
 
153
{
 
154
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
 
155
 
 
156
    const bool hadPreedit = !preedit.isEmpty();
 
157
 
 
158
    // reset input method server, preedit requires synchronization.
 
159
    // rationale: input method might be autocommitting existing preedit without
 
160
    // user interaction.
 
161
    imServer->reset(hadPreedit);
 
162
}
 
163
 
 
164
void MInputContext::commit()
 
165
{
 
166
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
 
167
 
 
168
    const bool hadPreedit = !preedit.isEmpty();
 
169
 
 
170
    if (hadPreedit) {
 
171
        QList<QInputMethodEvent::Attribute> attributes;
 
172
        if (preeditCursorPos >= 0) {
 
173
            bool valid = false;
 
174
            int start = cursorStartPosition(&valid);
 
175
            if (valid) {
 
176
                attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
 
177
                                                           start + preeditCursorPos, 0, QVariant());
 
178
            }
 
179
        }
 
180
 
 
181
        QInputMethodEvent event("", attributes);
 
182
        event.setCommitString(preedit);
 
183
        QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
 
184
 
 
185
        preedit.clear();
 
186
        preeditCursorPos = -1;
 
187
    }
 
188
 
 
189
    imServer->reset(hadPreedit);
 
190
}
 
191
 
 
192
void MInputContext::invokeAction(QInputMethod::Action action, int x)
 
193
{
 
194
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
 
195
 
 
196
    if (!inputMethodAccepted())
 
197
        return;
 
198
 
 
199
    if (action == QInputMethod::Click) {
 
200
        if (x < 0 || x >= preedit.length()) {
 
201
            reset();
 
202
            return;
 
203
        }
 
204
 
 
205
        // To preserve the wire protocol, the "x" argument gets
 
206
        // transferred in widget state instead of being an extra
 
207
        // argument to mouseClickedOnPreedit().
 
208
        QMap<QString, QVariant> stateInformation = getStateInformation();
 
209
        stateInformation["preeditClickPos"] = x;
 
210
        imServer->updateWidgetInformation(stateInformation, false);
 
211
 
 
212
        // FIXME: proper positions and preeditClickPos
 
213
        QRect preeditRect;
 
214
        QPoint globalPos;
 
215
        imServer->mouseClickedOnPreedit(globalPos, preeditRect);
 
216
 
 
217
    } else {
 
218
        QPlatformInputContext::invokeAction(action, x);
 
219
    }
 
220
}
 
221
 
 
222
void MInputContext::update(Qt::InputMethodQueries queries)
 
223
{
 
224
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
 
225
 
 
226
    Q_UNUSED(queries) // fetching everything
 
227
 
 
228
    if (queries & Qt::ImPlatformData) {
 
229
        updateInputMethodExtensions();
 
230
    }
 
231
 
 
232
    // get the state information of currently focused widget, and pass it to input method server
 
233
    QMap<QString, QVariant> stateInformation = getStateInformation();
 
234
    imServer->updateWidgetInformation(stateInformation, false);
 
235
}
 
236
 
 
237
void MInputContext::updateServerOrientation(Qt::ScreenOrientation orientation)
 
238
{
 
239
    if (active) {
 
240
        imServer->appOrientationChanged(orientationAngle(orientation));
 
241
    }
 
242
}
 
243
 
 
244
 
 
245
void MInputContext::setFocusObject(QObject *focused)
 
246
{
 
247
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__ << focused;
 
248
 
 
249
    updateInputMethodExtensions();
 
250
 
 
251
    QWindow *newFocusWindow = qGuiApp->focusWindow();
 
252
    if (newFocusWindow != window.data()) {
 
253
       if (window) {
 
254
           disconnect(window.data(), SIGNAL(contentOrientationChanged(Qt::ScreenOrientation)),
 
255
                      this, SLOT(updateServerOrientation(Qt::ScreenOrientation)));
 
256
       }
 
257
 
 
258
       window = newFocusWindow;
 
259
       if (window) {
 
260
           connect(window.data(), SIGNAL(contentOrientationChanged(Qt::ScreenOrientation)),
 
261
                   this, SLOT(updateServerOrientation(Qt::ScreenOrientation)));
 
262
       }
 
263
    }
 
264
 
 
265
    if (focused && !active) {
 
266
        imServer->activateContext();
 
267
        active = true;
 
268
        updateServerOrientation(newFocusWindow->contentOrientation());
 
269
    }
 
270
 
 
271
    const QMap<QString, QVariant> stateInformation = getStateInformation();
 
272
    imServer->updateWidgetInformation(stateInformation, true);
 
273
 
 
274
    if (inputPanelState == InputPanelShowPending && focused) {
 
275
        sipHideTimer.stop();
 
276
        imServer->showInputMethod();
 
277
        inputPanelState = InputPanelShown;
 
278
    }
 
279
}
 
280
 
 
281
bool MInputContext::filterEvent(const QEvent *event)
 
282
{
 
283
    bool eaten = false;
 
284
 
 
285
    switch (event->type()) {
 
286
 
 
287
    case QEvent::KeyPress:
 
288
    case QEvent::KeyRelease:
 
289
        if (!inputMethodAccepted()) {
 
290
            break;
 
291
        }
 
292
 
 
293
        if (redirectKeys) {
 
294
            const QKeyEvent *key = static_cast<const QKeyEvent *>(event);
 
295
            imServer->processKeyEvent(key->type(), static_cast<Qt::Key>(key->key()),
 
296
                                      key->modifiers(), key->text(), key->isAutoRepeat(),
 
297
                                      key->count(), key->nativeScanCode(),
 
298
                                      key->nativeModifiers(), 0 /* currentKeyEventTime */);
 
299
            eaten = true;
 
300
        }
 
301
        break;
 
302
 
 
303
    default:
 
304
        break;
 
305
    }
 
306
 
 
307
    return eaten;
 
308
}
 
309
 
 
310
QRectF MInputContext::keyboardRect() const
 
311
{
 
312
    return keyboardRectangle;
 
313
}
 
314
 
 
315
bool MInputContext::isAnimating() const
 
316
{
 
317
    return false; // don't know here when input method server is actually doing transitions
 
318
}
 
319
 
 
320
void MInputContext::showInputPanel()
 
321
{
 
322
    if (debug) qDebug() << __PRETTY_FUNCTION__;
 
323
 
 
324
    if (inputMethodAccepted()) {
 
325
        sipHideTimer.stop();
 
326
    }
 
327
 
 
328
    if (!active || !inputMethodAccepted()) {
 
329
        // in case SIP request comes without a properly focused widget, we
 
330
        // don't ask input method server to be shown. It's done when the next widget
 
331
        // is focused, so the widget state information can be set.
 
332
        inputPanelState = InputPanelShowPending;
 
333
 
 
334
    } else {
 
335
        // note: could do this also if panel was hidden
 
336
 
 
337
        imServer->showInputMethod();
 
338
        inputPanelState = InputPanelShown;
 
339
    }
 
340
}
 
341
 
 
342
void MInputContext::hideInputPanel()
 
343
{
 
344
    if (debug) qDebug() << __PRETTY_FUNCTION__;
 
345
    sipHideTimer.start();
 
346
}
 
347
 
 
348
bool MInputContext::isInputPanelVisible() const
 
349
{
 
350
    return !keyboardRectangle.isEmpty();
 
351
}
 
352
 
 
353
QLocale MInputContext::locale() const
 
354
{
 
355
    return inputLocale;
 
356
}
 
357
 
 
358
Qt::LayoutDirection MInputContext::inputDirection() const
 
359
{
 
360
    return inputLocale.textDirection();
 
361
}
 
362
 
 
363
void MInputContext::sendHideInputMethod()
 
364
{
 
365
    imServer->hideInputMethod();
 
366
 
 
367
    inputPanelState = InputPanelHidden;
 
368
}
 
369
 
 
370
void MInputContext::activationLostEvent()
 
371
{
 
372
    // This method is called when activation was gracefully lost.
 
373
    // There is similar cleaning up done in onDBusDisconnection.
 
374
    active = false;
 
375
    inputPanelState = InputPanelHidden;
 
376
}
 
377
 
 
378
 
 
379
void MInputContext::imInitiatedHide()
 
380
{
 
381
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
 
382
 
 
383
    inputPanelState = InputPanelHidden;
 
384
 
 
385
    // remove focus on QtQuick2
 
386
    QQuickItem *inputItem = qobject_cast<QQuickItem*>(QGuiApplication::focusObject());
 
387
    if (inputItem) {
 
388
        inputItem->setFocus(false);
 
389
    }
 
390
 
 
391
}
 
392
 
 
393
void MInputContext::commitString(const QString &string, int replacementStart,
 
394
                                 int replacementLength, int cursorPos)
 
395
{
 
396
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
 
397
 
 
398
    if (imServer->pendingResets()) {
 
399
        return;
 
400
    }
 
401
 
 
402
    preedit.clear();
 
403
    preeditCursorPos = -1;
 
404
 
 
405
    int start = -1;
 
406
    if (cursorPos >= 0) {
 
407
        bool valid = false;
 
408
        int currentStart = cursorStartPosition(&valid);
 
409
        if (valid) {
 
410
            start = cursorPos + currentStart + replacementStart;
 
411
        }
 
412
    }
 
413
 
 
414
    if (start >= 0) {
 
415
        QList<QInputMethodEvent::Attribute> attributes;
 
416
        attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start, 0, QVariant());
 
417
        QInputMethodEvent event("", attributes);
 
418
        event.setCommitString(string, replacementStart, replacementLength);
 
419
        QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
 
420
 
 
421
    } else {
 
422
        QInputMethodEvent event;
 
423
        event.setCommitString(string, replacementStart, replacementLength);
 
424
        QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
 
425
    }
 
426
}
 
427
 
 
428
 
 
429
void MInputContext::updatePreedit(const QString &string,
 
430
                                  const QList<Maliit::PreeditTextFormat> &preeditFormats,
 
431
                                  int replacementStart, int replacementLength, int cursorPos)
 
432
{
 
433
    if (debug) {
 
434
        qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__ << "preedit:" << string
 
435
                 << ", replacementStart:" << replacementStart
 
436
                 << ", replacementLength:" << replacementLength
 
437
                 << ", cursorPos:" << cursorPos;
 
438
    }
 
439
 
 
440
    if (imServer->pendingResets()) {
 
441
        return;
 
442
    }
 
443
 
 
444
    updatePreeditInternally(string, preeditFormats, replacementStart, replacementLength, cursorPos);
 
445
}
 
446
 
 
447
void MInputContext::updatePreeditInternally(const QString &string,
 
448
                                            const QList<Maliit::PreeditTextFormat> &preeditFormats,
 
449
                                            int replacementStart, int replacementLength, int cursorPos)
 
450
{
 
451
    preedit = string;
 
452
    preeditCursorPos = cursorPos;
 
453
 
 
454
    QList<QInputMethodEvent::Attribute> attributes;
 
455
    Q_FOREACH (const Maliit::PreeditTextFormat &preeditFormat, preeditFormats) {
 
456
 
 
457
        QTextCharFormat format;
 
458
 
 
459
        // update style mode
 
460
        switch (preeditFormat.preeditFace) {
 
461
        case Maliit::PreeditNoCandidates:
 
462
            format.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
 
463
            format.setUnderlineColor(Qt::red);
 
464
            break;
 
465
        case Maliit::PreeditUnconvertible:
 
466
            format.setForeground(QBrush(QColor(128, 128, 128)));
 
467
            break;
 
468
        case Maliit::PreeditActive:
 
469
            format.setForeground(QBrush(QColor(153, 50, 204)));
 
470
            format.setFontWeight(QFont::Bold);
 
471
            break;
 
472
        case Maliit::PreeditKeyPress:
 
473
        case Maliit::PreeditDefault:
 
474
            format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
 
475
            format.setUnderlineColor(QColor(0, 0, 0));
 
476
            break;
 
477
        }
 
478
 
 
479
        attributes << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
 
480
                                                   preeditFormat.start,
 
481
                                                   preeditFormat.length, format);
 
482
    }
 
483
 
 
484
    if (cursorPos >= 0) {
 
485
        attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, 1, QVariant());
 
486
    }
 
487
 
 
488
    QInputMethodEvent event(string, attributes);
 
489
    if (replacementStart || replacementLength) {
 
490
        event.setCommitString("", replacementStart, replacementLength);
 
491
    }
 
492
 
 
493
    QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
 
494
}
 
495
 
 
496
void MInputContext::keyEvent(int type, int key, int modifiers, const QString &text,
 
497
                             bool autoRepeat, int count,
 
498
                             Maliit::EventRequestType requestType)
 
499
{
 
500
    if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
 
501
 
 
502
    if (qGuiApp->focusWindow() != 0 && requestType != Maliit::EventRequestSignalOnly) {
 
503
        QEvent::Type eventType = static_cast<QEvent::Type>(type);
 
504
        QKeyEvent event(eventType, key, static_cast<Qt::KeyboardModifiers>(modifiers), text, autoRepeat, count);
 
505
        // need window instead of focus item so e.g. QQuickItem::keyPressEvent() gets properly called
 
506
        QGuiApplication::sendEvent(qGuiApp->focusWindow(), &event);
 
507
    }
 
508
}
 
509
 
 
510
 
 
511
void MInputContext::updateInputMethodArea(const QRect &rect)
 
512
{
 
513
    bool wasVisible = isInputPanelVisible();
 
514
 
 
515
    if (rect != keyboardRectangle) {
 
516
        keyboardRectangle = rect;
 
517
        emitKeyboardRectChanged();
 
518
 
 
519
        if (wasVisible != isInputPanelVisible()) {
 
520
            emitInputPanelVisibleChanged();
 
521
        }
 
522
    }
 
523
}
 
524
 
 
525
 
 
526
void MInputContext::setGlobalCorrectionEnabled(bool enabled)
 
527
{
 
528
    Q_UNUSED(enabled)
 
529
    // not handling preedit injections, ignored
 
530
}
 
531
 
 
532
 
 
533
void MInputContext::getPreeditRectangle(QRect &rectangle, bool &valid) const
 
534
{
 
535
    // not supported
 
536
    rectangle = QRect();
 
537
    valid = false;
 
538
 
 
539
    return;
 
540
}
 
541
 
 
542
void MInputContext::onInvokeAction(const QString &action, const QKeySequence &sequence)
 
543
{
 
544
    if (debug) qDebug() << InputContextName << __PRETTY_FUNCTION__ << "action" << action;
 
545
 
 
546
    // NOTE: currently not trying to trigger action directly
 
547
    static const Qt::KeyboardModifiers AllModifiers = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier
 
548
            | Qt::MetaModifier | Qt::KeypadModifier;
 
549
 
 
550
    for (int i = 0; i < sequence.count(); i++) {
 
551
        const int key = sequence[i] & ~AllModifiers;
 
552
        const int modifiers = sequence[i] & AllModifiers;
 
553
        QString text("");
 
554
        if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
 
555
            text = QString(key);
 
556
        }
 
557
        keyEvent(QEvent::KeyPress, key, modifiers, text, false, 1);
 
558
        keyEvent(QEvent::KeyRelease, key, modifiers, text, false, 1);
 
559
    }
 
560
}
 
561
 
 
562
void MInputContext::onDBusDisconnection()
 
563
{
 
564
    if (debug) qDebug() << __PRETTY_FUNCTION__;
 
565
 
 
566
    active = false;
 
567
    redirectKeys = false;
 
568
 
 
569
    updateInputMethodArea(QRect());
 
570
}
 
571
 
 
572
void MInputContext::onDBusConnection()
 
573
{
 
574
    if (debug) qDebug() << __PRETTY_FUNCTION__;
 
575
 
 
576
    // using one attribute extension for everything
 
577
    imServer->registerAttributeExtension(0, QString());
 
578
 
 
579
    // Force activation, since setFocusWidget may have been called after
 
580
    // onDBusDisconnection set active to false or before the dbus connection.
 
581
    active = false;
 
582
 
 
583
    if (inputMethodAccepted()) {
 
584
        setFocusObject(QGuiApplication::focusObject());
 
585
        if (inputPanelState != InputPanelHidden) {
 
586
            imServer->showInputMethod();
 
587
            inputPanelState = InputPanelShown;
 
588
        }
 
589
    }
 
590
}
 
591
 
 
592
void MInputContext::notifyOrientationAboutToChange(MInputContext::OrientationAngle angle)
 
593
{
 
594
    // can get called from signal so cannot be sure we are really currently active
 
595
    if (active) {
 
596
        imServer->appOrientationAboutToChange(static_cast<int>(angle));
 
597
    }
 
598
}
 
599
 
 
600
void MInputContext::notifyOrientationChanged(MInputContext::OrientationAngle angle)
 
601
{
 
602
    // can get called from signal so cannot be sure we are really currently active
 
603
    if (active) {
 
604
        imServer->appOrientationChanged(static_cast<int>(angle));
 
605
    }
 
606
}
 
607
 
 
608
Maliit::TextContentType MInputContext::contentType(Qt::InputMethodHints hints) const
 
609
{
 
610
    Maliit::TextContentType type = Maliit::FreeTextContentType;
 
611
    hints &= Qt::ImhExclusiveInputMask;
 
612
 
 
613
    if (hints == Qt::ImhFormattedNumbersOnly || hints == Qt::ImhDigitsOnly) {
 
614
        type = Maliit::NumberContentType;
 
615
    } else if (hints == Qt::ImhDialableCharactersOnly) {
 
616
        type = Maliit::PhoneNumberContentType;
 
617
    } else if (hints == Qt::ImhEmailCharactersOnly) {
 
618
        type = Maliit::EmailContentType;
 
619
    } else if (hints == Qt::ImhUrlCharactersOnly) {
 
620
        type = Maliit::UrlContentType;
 
621
    }
 
622
 
 
623
    return type;
 
624
}
 
625
 
 
626
void MInputContext::setRedirectKeys(bool enabled)
 
627
{
 
628
    redirectKeys = enabled;
 
629
}
 
630
 
 
631
void MInputContext::setDetectableAutoRepeat(bool enabled)
 
632
{
 
633
    Q_UNUSED(enabled);
 
634
    qWarning() << "Detectable autorepeat not supported.";
 
635
}
 
636
 
 
637
QMap<QString, QVariant> MInputContext::getStateInformation() const
 
638
{
 
639
    QMap<QString, QVariant> stateInformation;
 
640
 
 
641
    stateInformation["focusState"] = inputMethodAccepted();
 
642
 
 
643
    if (!inputMethodAccepted()) {
 
644
        return stateInformation;
 
645
    }
 
646
 
 
647
    QInputMethodQueryEvent query(Qt::ImQueryAll);
 
648
    QGuiApplication::sendEvent(qGuiApp->focusObject(), &query);
 
649
 
 
650
    QVariant queryResult;
 
651
 
 
652
    queryResult = query.value(Qt::ImSurroundingText);
 
653
    if (queryResult.isValid()) {
 
654
        stateInformation["surroundingText"] = queryResult.toString();
 
655
    }
 
656
 
 
657
    queryResult = query.value(Qt::ImCursorPosition);
 
658
    if (queryResult.isValid()) {
 
659
        stateInformation["cursorPosition"] = queryResult.toInt();
 
660
    }
 
661
 
 
662
    queryResult = query.value(Qt::ImAnchorPosition);
 
663
    if (queryResult.isValid()) {
 
664
        stateInformation["anchorPosition"] = queryResult.toInt();
 
665
    }
 
666
 
 
667
    queryResult = query.value(Qt::ImHints);
 
668
    Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryResult.toUInt());
 
669
 
 
670
    // content type value
 
671
    // Deprecated, replaced by just transmitting all hints (see below):
 
672
    // FIXME: Remove once MAbstractInputMethod API for this got deprecated/removed.
 
673
    stateInformation["contentType"] = contentType(hints);
 
674
 
 
675
    stateInformation["autocapitalizationEnabled"] = !(hints & Qt::ImhNoAutoUppercase);
 
676
    stateInformation["hiddenText"] = static_cast<bool>(hints & Qt::ImhHiddenText);
 
677
    stateInformation["predictionEnabled"] = ! static_cast<bool>(hints & Qt::ImhNoPredictiveText);
 
678
 
 
679
    stateInformation["maliit-inputmethod-hints"] = QVariant(static_cast<qint64>(hints));
 
680
 
 
681
    // is text selected
 
682
    queryResult = query.value(Qt::ImCurrentSelection);
 
683
    if (queryResult.isValid()) {
 
684
        stateInformation["hasSelection"] = !(queryResult.toString().isEmpty());
 
685
    }
 
686
 
 
687
    QWindow *window = qGuiApp->focusWindow();
 
688
    if (window) {
 
689
        stateInformation["winId"] = static_cast<qulonglong>(window->winId());
 
690
    }
 
691
 
 
692
    queryResult = query.value(Qt::ImCursorRectangle);
 
693
    if (queryResult.isValid()) {
 
694
        QRect rect = queryResult.toRect();
 
695
        rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(rect);
 
696
        if (window) {
 
697
            stateInformation["cursorRectangle"] = QRect(window->mapToGlobal(rect.topLeft()), rect.size());
 
698
        }
 
699
    }
 
700
 
 
701
    stateInformation["toolbarId"] = 0; // Global extension id. And bad state parameter name for it.
 
702
 
 
703
    return stateInformation;
 
704
}
 
705
 
 
706
void MInputContext::setSelection(int start, int length)
 
707
{
 
708
    if (!inputMethodAccepted())
 
709
        return;
 
710
 
 
711
    QList<QInputMethodEvent::Attribute> attributes;
 
712
    attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start,
 
713
                                                length, QVariant());
 
714
    QInputMethodEvent event("", attributes);
 
715
    QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
 
716
}
 
717
 
 
718
void MInputContext::getSelection(QString &selection, bool &valid) const
 
719
{
 
720
    selection.clear();
 
721
 
 
722
    QString selectionText;
 
723
    valid = false;
 
724
 
 
725
    if (!inputMethodAccepted()) {
 
726
        return;
 
727
    }
 
728
 
 
729
    QInputMethodQueryEvent query(Qt::ImCurrentSelection);
 
730
    QGuiApplication::sendEvent(qGuiApp->focusObject(), &query);
 
731
 
 
732
    QVariant queryResult = query.value(Qt::ImCurrentSelection);
 
733
    valid = queryResult.isValid();
 
734
    selectionText = queryResult.toString();
 
735
 
 
736
    selection = selectionText;
 
737
}
 
738
 
 
739
int MInputContext::cursorStartPosition(bool *valid)
 
740
{
 
741
    int start = -1;
 
742
    if (valid) {
 
743
        *valid = false;
 
744
    }
 
745
 
 
746
    if (!inputMethodAccepted()) {
 
747
        return start;
 
748
    }
 
749
 
 
750
    QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition);
 
751
    QGuiApplication::sendEvent(qGuiApp->focusObject(), &query);
 
752
 
 
753
    // obtain the cursor absolute position
 
754
    QVariant queryResult = query.value(Qt::ImCursorPosition);
 
755
    if (queryResult.isValid()) {
 
756
        int absCursorPos = queryResult.toInt();
 
757
 
 
758
        // Fetch anchor position too but don't require it.
 
759
        queryResult = query.value(Qt::ImAnchorPosition);
 
760
        int absAnchorPos = queryResult.isValid() ? queryResult.toInt() : absCursorPos;
 
761
 
 
762
        // In case of selection, base cursorPos on start of it.
 
763
        start = qMin<int>(absCursorPos, absAnchorPos);
 
764
        *valid = true;
 
765
    }
 
766
 
 
767
    return start;
 
768
}
 
769
 
 
770
void MInputContext::updateInputMethodExtensions()
 
771
{
 
772
    if (!inputMethodAccepted()) {
 
773
        return;
 
774
    }
 
775
    if (debug) qDebug() << InputContextName << __PRETTY_FUNCTION__;
 
776
 
 
777
    QVariantMap extensions = qGuiApp->focusObject()->property("__inputMethodExtensions").toMap();
 
778
    QVariant value;
 
779
    value = extensions.value("enterKeyIconSource");
 
780
    imServer->setExtendedAttribute(0, "/keys", "actionKey", "icon", QVariant(value.toUrl().toString()));
 
781
 
 
782
    value = extensions.value("enterKeyText");
 
783
    imServer->setExtendedAttribute(0, "/keys", "actionKey", "label", QVariant(value.toString()));
 
784
 
 
785
    value = extensions.value("enterKeyEnabled");
 
786
    imServer->setExtendedAttribute(0, "/keys", "actionKey", "enabled", value.isValid() ? value.toBool() : true);
 
787
 
 
788
    value = extensions.value("enterKeyHighlighted");
 
789
    imServer->setExtendedAttribute(0, "/keys", "actionKey", "highlighted", value.isValid() ? value.toBool() : false);
 
790
}