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

Subscribers

People subscribed via source and target branches