Merge lp:~dandrader/ubuntu/trusty/maliit-framework/orientationAngleMapping into lp:ubuntu/trusty/maliit-framework

Proposed by Daniel d'Andrada
Status: Merged
Merge reported by: Iain Lane
Merged at revision: not available
Proposed branch: lp:~dandrader/ubuntu/trusty/maliit-framework/orientationAngleMapping
Merge into: lp:ubuntu/trusty/maliit-framework
Diff against target: 908 lines (+843/-12)
6 files modified
.pc/0006-fix_orientation_to_angle_mapping.patch/input-context/minputcontext.cpp (+794/-0)
.pc/applied-patches (+1/-0)
debian/changelog (+6/-0)
debian/patches/0006-fix_orientation_to_angle_mapping.patch (+38/-0)
debian/patches/series (+1/-0)
input-context/minputcontext.cpp (+3/-12)
To merge this branch: bzr merge lp:~dandrader/ubuntu/trusty/maliit-framework/orientationAngleMapping
Reviewer Review Type Date Requested Status
Bill Filler (community) Approve
Ubuntu branches Pending
Review via email: mp+204304@code.launchpad.net

Commit message

Fix mapping between screen orientations and rotation angles.

Simply use the function that Qt provides for that.

To post a comment you must log in.
Revision history for this message
Bill Filler (bfiller) wrote :

tested with https://code.launchpad.net/~dandrader/ubuntu-keyboard/fixAngleToOrientationMap/+merge/204293 and worked as expected on tablet and N4

Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator?
YES

Did you successfully run all tests found in your component's Test Plan
(https://wiki.ubuntu.com/Process/Merges/TestPlan/<package-name>) on device or emulator?
YES

Did CI run pass? If not, please explain why.
YES

Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?
YES

review: Approve
Revision history for this message
Bill Filler (bfiller) wrote :

Are there any related MPs required for this MP to build/function as expected?
YES, https://code.launchpad.net/~dandrader/ubuntu-keyboard/fixAngleToOrientationMap/+merge/204293

Revision history for this message
Iain Lane (laney) wrote :

I merged this manually because I didn't see this MP—thanks for the work.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory '.pc/0006-fix_orientation_to_angle_mapping.patch'
=== added file '.pc/0006-fix_orientation_to_angle_mapping.patch/.timestamp'
=== added directory '.pc/0006-fix_orientation_to_angle_mapping.patch/input-context'
=== added file '.pc/0006-fix_orientation_to_angle_mapping.patch/input-context/minputcontext.cpp'
--- .pc/0006-fix_orientation_to_angle_mapping.patch/input-context/minputcontext.cpp 1970-01-01 00:00:00 +0000
+++ .pc/0006-fix_orientation_to_angle_mapping.patch/input-context/minputcontext.cpp 2014-01-31 18:02:44 +0000
@@ -0,0 +1,794 @@
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
32namespace
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
54bool MInputContext::debug = false;
55
56
57MInputContext::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
80MInputContext::~MInputContext()
81{
82 delete imServer;
83}
84
85void 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
131bool MInputContext::isValid() const
132{
133 return true;
134}
135
136void 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
152void 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
164void 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
192void 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
222void 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
237void MInputContext::updateServerOrientation(Qt::ScreenOrientation orientation)
238{
239 if (active) {
240 imServer->appOrientationChanged(orientationAngle(orientation));
241 }
242}
243
244
245void 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
281bool 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
310QRectF MInputContext::keyboardRect() const
311{
312 return keyboardRectangle;
313}
314
315bool MInputContext::isAnimating() const
316{
317 return false; // don't know here when input method server is actually doing transitions
318}
319
320void 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
342void MInputContext::hideInputPanel()
343{
344 if (debug) qDebug() << __PRETTY_FUNCTION__;
345 sipHideTimer.start();
346}
347
348bool MInputContext::isInputPanelVisible() const
349{
350 return !keyboardRectangle.isEmpty();
351}
352
353QLocale MInputContext::locale() const
354{
355 return inputLocale;
356}
357
358Qt::LayoutDirection MInputContext::inputDirection() const
359{
360 return inputLocale.textDirection();
361}
362
363void MInputContext::sendHideInputMethod()
364{
365 imServer->hideInputMethod();
366
367 inputPanelState = InputPanelHidden;
368}
369
370void MInputContext::activationLostEvent()
371{
372 if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
373
374 // This method is called when activation was gracefully lost.
375 // There is similar cleaning up done in onDBusDisconnection.
376 active = false;
377 inputPanelState = InputPanelHidden;
378
379 updateInputMethodArea(QRect());
380}
381
382
383void MInputContext::imInitiatedHide()
384{
385 if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
386
387 inputPanelState = InputPanelHidden;
388
389 // remove focus on QtQuick2
390 QQuickItem *inputItem = qobject_cast<QQuickItem*>(QGuiApplication::focusObject());
391 if (inputItem) {
392 inputItem->setFocus(false);
393 }
394
395}
396
397void MInputContext::commitString(const QString &string, int replacementStart,
398 int replacementLength, int cursorPos)
399{
400 if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
401
402 if (imServer->pendingResets()) {
403 return;
404 }
405
406 preedit.clear();
407 preeditCursorPos = -1;
408
409 int start = -1;
410 if (cursorPos >= 0) {
411 bool valid = false;
412 int currentStart = cursorStartPosition(&valid);
413 if (valid) {
414 start = cursorPos + currentStart + replacementStart;
415 }
416 }
417
418 if (start >= 0) {
419 QList<QInputMethodEvent::Attribute> attributes;
420 attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start, 0, QVariant());
421 QInputMethodEvent event("", attributes);
422 event.setCommitString(string, replacementStart, replacementLength);
423 QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
424
425 } else {
426 QInputMethodEvent event;
427 event.setCommitString(string, replacementStart, replacementLength);
428 QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
429 }
430}
431
432
433void MInputContext::updatePreedit(const QString &string,
434 const QList<Maliit::PreeditTextFormat> &preeditFormats,
435 int replacementStart, int replacementLength, int cursorPos)
436{
437 if (debug) {
438 qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__ << "preedit:" << string
439 << ", replacementStart:" << replacementStart
440 << ", replacementLength:" << replacementLength
441 << ", cursorPos:" << cursorPos;
442 }
443
444 if (imServer->pendingResets()) {
445 return;
446 }
447
448 updatePreeditInternally(string, preeditFormats, replacementStart, replacementLength, cursorPos);
449}
450
451void MInputContext::updatePreeditInternally(const QString &string,
452 const QList<Maliit::PreeditTextFormat> &preeditFormats,
453 int replacementStart, int replacementLength, int cursorPos)
454{
455 preedit = string;
456 preeditCursorPos = cursorPos;
457
458 QList<QInputMethodEvent::Attribute> attributes;
459 Q_FOREACH (const Maliit::PreeditTextFormat &preeditFormat, preeditFormats) {
460
461 QTextCharFormat format;
462
463 // update style mode
464 switch (preeditFormat.preeditFace) {
465 case Maliit::PreeditNoCandidates:
466 format.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
467 format.setUnderlineColor(Qt::red);
468 break;
469 case Maliit::PreeditUnconvertible:
470 format.setForeground(QBrush(QColor(128, 128, 128)));
471 break;
472 case Maliit::PreeditActive:
473 format.setForeground(QBrush(QColor(153, 50, 204)));
474 format.setFontWeight(QFont::Bold);
475 break;
476 case Maliit::PreeditKeyPress:
477 case Maliit::PreeditDefault:
478 format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
479 format.setUnderlineColor(QColor(0, 0, 0));
480 break;
481 }
482
483 attributes << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
484 preeditFormat.start,
485 preeditFormat.length, format);
486 }
487
488 if (cursorPos >= 0) {
489 attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, 1, QVariant());
490 }
491
492 QInputMethodEvent event(string, attributes);
493 if (replacementStart || replacementLength) {
494 event.setCommitString("", replacementStart, replacementLength);
495 }
496
497 QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
498}
499
500void MInputContext::keyEvent(int type, int key, int modifiers, const QString &text,
501 bool autoRepeat, int count,
502 Maliit::EventRequestType requestType)
503{
504 if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__;
505
506 if (qGuiApp->focusWindow() != 0 && requestType != Maliit::EventRequestSignalOnly) {
507 QEvent::Type eventType = static_cast<QEvent::Type>(type);
508 QKeyEvent event(eventType, key, static_cast<Qt::KeyboardModifiers>(modifiers), text, autoRepeat, count);
509 // need window instead of focus item so e.g. QQuickItem::keyPressEvent() gets properly called
510 QGuiApplication::sendEvent(qGuiApp->focusWindow(), &event);
511 }
512}
513
514
515void MInputContext::updateInputMethodArea(const QRect &rect)
516{
517 bool wasVisible = isInputPanelVisible();
518
519 if (rect != keyboardRectangle) {
520 keyboardRectangle = rect;
521 emitKeyboardRectChanged();
522
523 if (wasVisible != isInputPanelVisible()) {
524 emitInputPanelVisibleChanged();
525 }
526 }
527}
528
529
530void MInputContext::setGlobalCorrectionEnabled(bool enabled)
531{
532 Q_UNUSED(enabled)
533 // not handling preedit injections, ignored
534}
535
536
537void MInputContext::getPreeditRectangle(QRect &rectangle, bool &valid) const
538{
539 // not supported
540 rectangle = QRect();
541 valid = false;
542
543 return;
544}
545
546void MInputContext::onInvokeAction(const QString &action, const QKeySequence &sequence)
547{
548 if (debug) qDebug() << InputContextName << __PRETTY_FUNCTION__ << "action" << action;
549
550 // NOTE: currently not trying to trigger action directly
551 static const Qt::KeyboardModifiers AllModifiers = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier
552 | Qt::MetaModifier | Qt::KeypadModifier;
553
554 for (int i = 0; i < sequence.count(); i++) {
555 const int key = sequence[i] & ~AllModifiers;
556 const int modifiers = sequence[i] & AllModifiers;
557 QString text("");
558 if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) {
559 text = QString(key);
560 }
561 keyEvent(QEvent::KeyPress, key, modifiers, text, false, 1);
562 keyEvent(QEvent::KeyRelease, key, modifiers, text, false, 1);
563 }
564}
565
566void MInputContext::onDBusDisconnection()
567{
568 if (debug) qDebug() << __PRETTY_FUNCTION__;
569
570 active = false;
571 redirectKeys = false;
572
573 updateInputMethodArea(QRect());
574}
575
576void MInputContext::onDBusConnection()
577{
578 if (debug) qDebug() << __PRETTY_FUNCTION__;
579
580 // using one attribute extension for everything
581 imServer->registerAttributeExtension(0, QString());
582
583 // Force activation, since setFocusWidget may have been called after
584 // onDBusDisconnection set active to false or before the dbus connection.
585 active = false;
586
587 if (inputMethodAccepted()) {
588 setFocusObject(QGuiApplication::focusObject());
589 if (inputPanelState != InputPanelHidden) {
590 imServer->showInputMethod();
591 inputPanelState = InputPanelShown;
592 }
593 }
594}
595
596void MInputContext::notifyOrientationAboutToChange(MInputContext::OrientationAngle angle)
597{
598 // can get called from signal so cannot be sure we are really currently active
599 if (active) {
600 imServer->appOrientationAboutToChange(static_cast<int>(angle));
601 }
602}
603
604void MInputContext::notifyOrientationChanged(MInputContext::OrientationAngle angle)
605{
606 // can get called from signal so cannot be sure we are really currently active
607 if (active) {
608 imServer->appOrientationChanged(static_cast<int>(angle));
609 }
610}
611
612Maliit::TextContentType MInputContext::contentType(Qt::InputMethodHints hints) const
613{
614 Maliit::TextContentType type = Maliit::FreeTextContentType;
615 hints &= Qt::ImhExclusiveInputMask;
616
617 if (hints == Qt::ImhFormattedNumbersOnly || hints == Qt::ImhDigitsOnly) {
618 type = Maliit::NumberContentType;
619 } else if (hints == Qt::ImhDialableCharactersOnly) {
620 type = Maliit::PhoneNumberContentType;
621 } else if (hints == Qt::ImhEmailCharactersOnly) {
622 type = Maliit::EmailContentType;
623 } else if (hints == Qt::ImhUrlCharactersOnly) {
624 type = Maliit::UrlContentType;
625 }
626
627 return type;
628}
629
630void MInputContext::setRedirectKeys(bool enabled)
631{
632 redirectKeys = enabled;
633}
634
635void MInputContext::setDetectableAutoRepeat(bool enabled)
636{
637 Q_UNUSED(enabled);
638 qWarning() << "Detectable autorepeat not supported.";
639}
640
641QMap<QString, QVariant> MInputContext::getStateInformation() const
642{
643 QMap<QString, QVariant> stateInformation;
644
645 stateInformation["focusState"] = inputMethodAccepted();
646
647 if (!inputMethodAccepted()) {
648 return stateInformation;
649 }
650
651 QInputMethodQueryEvent query(Qt::ImQueryAll);
652 QGuiApplication::sendEvent(qGuiApp->focusObject(), &query);
653
654 QVariant queryResult;
655
656 queryResult = query.value(Qt::ImSurroundingText);
657 if (queryResult.isValid()) {
658 stateInformation["surroundingText"] = queryResult.toString();
659 }
660
661 queryResult = query.value(Qt::ImCursorPosition);
662 if (queryResult.isValid()) {
663 stateInformation["cursorPosition"] = queryResult.toInt();
664 }
665
666 queryResult = query.value(Qt::ImAnchorPosition);
667 if (queryResult.isValid()) {
668 stateInformation["anchorPosition"] = queryResult.toInt();
669 }
670
671 queryResult = query.value(Qt::ImHints);
672 Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryResult.toUInt());
673
674 // content type value
675 // Deprecated, replaced by just transmitting all hints (see below):
676 // FIXME: Remove once MAbstractInputMethod API for this got deprecated/removed.
677 stateInformation["contentType"] = contentType(hints);
678
679 stateInformation["autocapitalizationEnabled"] = !(hints & Qt::ImhNoAutoUppercase);
680 stateInformation["hiddenText"] = static_cast<bool>(hints & Qt::ImhHiddenText);
681 stateInformation["predictionEnabled"] = ! static_cast<bool>(hints & Qt::ImhNoPredictiveText);
682
683 stateInformation["maliit-inputmethod-hints"] = QVariant(static_cast<qint64>(hints));
684
685 // is text selected
686 queryResult = query.value(Qt::ImCurrentSelection);
687 if (queryResult.isValid()) {
688 stateInformation["hasSelection"] = !(queryResult.toString().isEmpty());
689 }
690
691 QWindow *window = qGuiApp->focusWindow();
692 if (window) {
693 stateInformation["winId"] = static_cast<qulonglong>(window->winId());
694 }
695
696 queryResult = query.value(Qt::ImCursorRectangle);
697 if (queryResult.isValid()) {
698 QRect rect = queryResult.toRect();
699 rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(rect);
700 if (window) {
701 stateInformation["cursorRectangle"] = QRect(window->mapToGlobal(rect.topLeft()), rect.size());
702 }
703 }
704
705 stateInformation["toolbarId"] = 0; // Global extension id. And bad state parameter name for it.
706
707 return stateInformation;
708}
709
710void MInputContext::setSelection(int start, int length)
711{
712 if (!inputMethodAccepted())
713 return;
714
715 QList<QInputMethodEvent::Attribute> attributes;
716 attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start,
717 length, QVariant());
718 QInputMethodEvent event("", attributes);
719 QGuiApplication::sendEvent(qGuiApp->focusObject(), &event);
720}
721
722void MInputContext::getSelection(QString &selection, bool &valid) const
723{
724 selection.clear();
725
726 QString selectionText;
727 valid = false;
728
729 if (!inputMethodAccepted()) {
730 return;
731 }
732
733 QInputMethodQueryEvent query(Qt::ImCurrentSelection);
734 QGuiApplication::sendEvent(qGuiApp->focusObject(), &query);
735
736 QVariant queryResult = query.value(Qt::ImCurrentSelection);
737 valid = queryResult.isValid();
738 selectionText = queryResult.toString();
739
740 selection = selectionText;
741}
742
743int MInputContext::cursorStartPosition(bool *valid)
744{
745 int start = -1;
746 if (valid) {
747 *valid = false;
748 }
749
750 if (!inputMethodAccepted()) {
751 return start;
752 }
753
754 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition);
755 QGuiApplication::sendEvent(qGuiApp->focusObject(), &query);
756
757 // obtain the cursor absolute position
758 QVariant queryResult = query.value(Qt::ImCursorPosition);
759 if (queryResult.isValid()) {
760 int absCursorPos = queryResult.toInt();
761
762 // Fetch anchor position too but don't require it.
763 queryResult = query.value(Qt::ImAnchorPosition);
764 int absAnchorPos = queryResult.isValid() ? queryResult.toInt() : absCursorPos;
765
766 // In case of selection, base cursorPos on start of it.
767 start = qMin<int>(absCursorPos, absAnchorPos);
768 *valid = true;
769 }
770
771 return start;
772}
773
774void MInputContext::updateInputMethodExtensions()
775{
776 if (!inputMethodAccepted()) {
777 return;
778 }
779 if (debug) qDebug() << InputContextName << __PRETTY_FUNCTION__;
780
781 QVariantMap extensions = qGuiApp->focusObject()->property("__inputMethodExtensions").toMap();
782 QVariant value;
783 value = extensions.value("enterKeyIconSource");
784 imServer->setExtendedAttribute(0, "/keys", "actionKey", "icon", QVariant(value.toUrl().toString()));
785
786 value = extensions.value("enterKeyText");
787 imServer->setExtendedAttribute(0, "/keys", "actionKey", "label", QVariant(value.toString()));
788
789 value = extensions.value("enterKeyEnabled");
790 imServer->setExtendedAttribute(0, "/keys", "actionKey", "enabled", value.isValid() ? value.toBool() : true);
791
792 value = extensions.value("enterKeyHighlighted");
793 imServer->setExtendedAttribute(0, "/keys", "actionKey", "highlighted", value.isValid() ? value.toBool() : false);
794}
0795
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2013-07-23 19:47:04 +0000
+++ .pc/applied-patches 2014-01-31 18:02:44 +0000
@@ -3,3 +3,4 @@
30003-prediction.patch30003-prediction.patch
40004-fix_activationlostevent.patch40004-fix_activationlostevent.patch
50005-testability.patch50005-testability.patch
60006-fix_orientation_to_angle_mapping.patch
67
=== modified file 'debian/changelog'
--- debian/changelog 2014-01-24 13:49:59 +0000
+++ debian/changelog 2014-01-31 18:02:44 +0000
@@ -1,3 +1,9 @@
1maliit-framework (0.99.0+git20130615+97e8335-0ubuntu6) trusty; urgency=medium
2
3 * Fix mapping between screen orientations and rotation angles. (LP: #1251330)
4
5 -- Daniel d'Andrada <daniel.dandrada@canonical.com> Fri, 31 Jan 2014 15:59:27 -0200
6
1maliit-framework (0.99.0+git20130615+97e8335-0ubuntu5) trusty; urgency=medium7maliit-framework (0.99.0+git20130615+97e8335-0ubuntu5) trusty; urgency=medium
28
3 * Modify xvfb command to successfully pass tests (LP: #1272249)9 * Modify xvfb command to successfully pass tests (LP: #1272249)
410
=== added file 'debian/patches/0006-fix_orientation_to_angle_mapping.patch'
--- debian/patches/0006-fix_orientation_to_angle_mapping.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/0006-fix_orientation_to_angle_mapping.patch 2014-01-31 18:02:44 +0000
@@ -0,0 +1,38 @@
1Author: Daniel d'Andrada <daniel.dandrada@canonical.com>
2Bug: https://bugs.launchpad.net/ubuntu-keyboard/+bug/1251330
3Forwarded: no
4Description: Fix mapping between screen orientations and rotation angles.
5 Simply use the function that Qt provides for that.
6Index: orientationAngleMapping/input-context/minputcontext.cpp
7===================================================================
8--- orientationAngleMapping.orig/input-context/minputcontext.cpp 2014-01-31 15:40:11.336846000 -0200
9+++ orientationAngleMapping/input-context/minputcontext.cpp 2014-01-31 15:41:15.171087065 -0200
10@@ -24,6 +24,7 @@
11 #include <QDebug>
12 #include <QByteArray>
13 #include <QRectF>
14+#include <QScreen>
15 #include <QLocale>
16 #include <QWindow>
17 #include <QSharedDataPointer>
18@@ -36,18 +37,8 @@
19
20 int orientationAngle(Qt::ScreenOrientation orientation)
21 {
22- switch (orientation) {
23- case Qt::PrimaryOrientation: // Urgh.
24- case Qt::PortraitOrientation:
25- return MInputContext::Angle270;
26- case Qt::LandscapeOrientation:
27- return MInputContext::Angle0;
28- case Qt::InvertedPortraitOrientation:
29- return MInputContext::Angle90;
30- case Qt::InvertedLandscapeOrientation:
31- return MInputContext::Angle180;
32- }
33- return MInputContext::Angle0;
34+ QScreen *screen = qGuiApp->primaryScreen();
35+ return screen->angleBetween(screen->primaryOrientation(), orientation);
36 }
37 }
38
039
=== modified file 'debian/patches/series'
--- debian/patches/series 2013-07-23 19:47:04 +0000
+++ debian/patches/series 2014-01-31 18:02:44 +0000
@@ -3,3 +3,4 @@
30003-prediction.patch30003-prediction.patch
40004-fix_activationlostevent.patch40004-fix_activationlostevent.patch
50005-testability.patch50005-testability.patch
60006-fix_orientation_to_angle_mapping.patch
67
=== modified file 'input-context/minputcontext.cpp'
--- input-context/minputcontext.cpp 2013-07-23 19:47:04 +0000
+++ input-context/minputcontext.cpp 2014-01-31 18:02:44 +0000
@@ -24,6 +24,7 @@
24#include <QDebug>24#include <QDebug>
25#include <QByteArray>25#include <QByteArray>
26#include <QRectF>26#include <QRectF>
27#include <QScreen>
27#include <QLocale>28#include <QLocale>
28#include <QWindow>29#include <QWindow>
29#include <QSharedDataPointer>30#include <QSharedDataPointer>
@@ -36,18 +37,8 @@
3637
37 int orientationAngle(Qt::ScreenOrientation orientation)38 int orientationAngle(Qt::ScreenOrientation orientation)
38 {39 {
39 switch (orientation) {40 QScreen *screen = qGuiApp->primaryScreen();
40 case Qt::PrimaryOrientation: // Urgh.41 return screen->angleBetween(screen->primaryOrientation(), orientation);
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 }42 }
52}43}
5344

Subscribers

People subscribed via source and target branches