diff --git a/qt/core/browser/oxide_qt_contents_view.cc b/qt/core/browser/oxide_qt_contents_view.cc index 2698877..af47e66 100644 --- a/qt/core/browser/oxide_qt_contents_view.cc +++ b/qt/core/browser/oxide_qt_contents_view.cc @@ -296,6 +296,10 @@ void ContentsView::visibilityChanged() { view()->VisibilityChanged(); } +void ContentsView::activeFocusChanged() { + view()->FocusChanged(); +} + QVariant ContentsView::inputMethodQuery(Qt::InputMethodQuery query) const { return input_method_context_->Query(query); } @@ -319,7 +323,6 @@ void ContentsView::handleInputMethodEvent(QInputMethodEvent* event) { void ContentsView::handleFocusEvent(QFocusEvent* event) { input_method_context_->FocusChanged(event); - view()->FocusChanged(); event->accept(); } diff --git a/qt/core/browser/oxide_qt_contents_view.h b/qt/core/browser/oxide_qt_contents_view.h index 10f9772..ab5a74a 100644 --- a/qt/core/browser/oxide_qt_contents_view.h +++ b/qt/core/browser/oxide_qt_contents_view.h @@ -79,6 +79,7 @@ class ContentsView : public QObject, void windowChanged() override; void wasResized() override; void visibilityChanged() override; + void activeFocusChanged() override; QVariant inputMethodQuery(Qt::InputMethodQuery query) const override; void handleKeyEvent(QKeyEvent* event) override; void handleInputMethodEvent(QInputMethodEvent* event) override; diff --git a/qt/core/glue/oxide_qt_contents_view_proxy.h b/qt/core/glue/oxide_qt_contents_view_proxy.h index fd7137c..252381f 100644 --- a/qt/core/glue/oxide_qt_contents_view_proxy.h +++ b/qt/core/glue/oxide_qt_contents_view_proxy.h @@ -80,6 +80,7 @@ class ContentsViewProxy { virtual void windowChanged() = 0; virtual void wasResized() = 0; virtual void visibilityChanged() = 0; + virtual void activeFocusChanged() = 0; virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const = 0; diff --git a/qt/quick/oxide_qquick_contents_view.cc b/qt/quick/oxide_qquick_contents_view.cc index e2d92ad..4884e7d 100644 --- a/qt/quick/oxide_qquick_contents_view.cc +++ b/qt/quick/oxide_qquick_contents_view.cc @@ -221,6 +221,8 @@ void ContentsView::handleItemChange(QQuickItem::ItemChange change) { if (change == QQuickItem::ItemVisibleHasChanged) { proxy()->visibilityChanged(); + } else if (change == QQuickItem::ItemActiveFocusHasChanged) { + proxy()->activeFocusChanged(); } } diff --git a/qt/tests/qmltests/core/tst_focus.html b/qt/tests/qmltests/core/tst_focus.html new file mode 100644 index 0000000..245c3e5 --- /dev/null +++ b/qt/tests/qmltests/core/tst_focus.html @@ -0,0 +1,13 @@ + + + + + + + diff --git a/qt/tests/qmltests/core/tst_focus.qml b/qt/tests/qmltests/core/tst_focus.qml new file mode 100644 index 0000000..472ed6e --- /dev/null +++ b/qt/tests/qmltests/core/tst_focus.qml @@ -0,0 +1,82 @@ +import QtQuick 2.0 +import QtTest 1.0 +import com.canonical.Oxide 1.0 +import Oxide.testsupport 1.0 + +TestWebView { + id: webView + + property bool htmlInputElementFocus: true + + focus: true + + messageHandlers: [ + ScriptMessageHandler { + msgId: "FOCUS-STATE" + contexts: [ "oxide://testutils/" ] + callback: function(msg) { + webView.htmlInputElementFocus = msg.payload; + } + } + ] + + SignalSpy { + id: spy + target: webView + signalName: "activeFocusChanged" + } + + TestCase { + id: testcase; + name: "webview_focus" + when: windowShown + + function initTestCase() { + verify(webView.activeFocus); + } + + function init() { + spy.clear(); + + webView.url = "https://testsuite/tst_focus.html"; + verify(webView.waitForLoadSucceeded(), + "Timed out waiting for successful load"); + + webView.getTestApi().evaluateCode( + "document.addEventListener(\"oxidefocusstate\", function(event) { + oxide.sendMessage(\"FOCUS-STATE\", event.detail.status); + });", true); + + verify(webView.activeFocus); + verify(webView.htmlInputElementFocus); + } + + function test_toggle_focus_onclicked() { + var rect = webView.getTestApi().getBoundingClientRectForSelector("#input"); + + // clicking outside input field should unfocus the input element. + var x1 = webView.width / 2; + var y1 = (rect.y + rect.height + webView.height) / 2; + mouseClick(webView, x1, y1, Qt.LeftButton); + verify(webView.activeFocus); + compare(spy.count, 0); + tryCompare(webView, "htmlInputElementFocus", false); + + // clicking inside input field restore the focus on input element. + mouseClick(webView, rect.x + rect.width / 2, rect.y + rect.height / 2, Qt.LeftButton); + verify(webView.activeFocus); + compare(spy.count, 0); + tryCompare(webView, "htmlInputElementFocus", true); + } + + function test_toggle_focus() { + webView.focus = false; + tryCompare(webView, "activeFocus", false); + tryCompare(webView, "htmlInputElementFocus", false); + + webView.focus = true; + tryCompare(webView, "activeFocus", true); + tryCompare(webView, "htmlInputElementFocus", true); + } + } +}