Commit b26b9d89 authored by Martin Robinson's avatar Martin Robinson Committed by Commit Bot

Add X11 support for ATK key event listeners

ATK requires us to allow it to filter all key events. Add an AtkUtil
mechanism to filter key events.

Bug: 866334
Change-Id: I42383479ab78242325bda0714afb60b7dcf2fe65
Reviewed-on: https://chromium-review.googlesource.com/c/1319709
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607989}
parent c0293693
...@@ -147,6 +147,16 @@ jumbo_component("accessibility") { ...@@ -147,6 +147,16 @@ jumbo_component("accessibility") {
if (use_glib) { if (use_glib) {
configs += [ "//build/config/linux:glib" ] configs += [ "//build/config/linux:glib" ]
} }
if (use_x11) {
sources += [ "platform/atk_util_auralinux_x11.cc" ]
configs += [ "//build/config/linux:x11" ]
public_deps += [
"//ui/events/x",
"//ui/gfx/x",
]
}
} }
if (use_aura) { if (use_aura) {
...@@ -242,7 +252,10 @@ test("accessibility_unittests") { ...@@ -242,7 +252,10 @@ test("accessibility_unittests") {
libs = [ "oleacc.lib" ] libs = [ "oleacc.lib" ]
} }
if (use_atk) { if (use_atk) {
sources += [ "platform/ax_platform_node_auralinux_unittest.cc" ] sources += [
"platform/atk_util_auralinux_unittest.cc",
"platform/ax_platform_node_auralinux_unittest.cc",
]
configs += [ "//build/config/linux/atk" ] configs += [ "//build/config/linux/atk" ]
} }
} }
......
specific_include_rules = {
"atk_util_auralinux_x11.cc": [
"+ui/events/x",
]
}
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
#include <atk/atk.h> #include <atk/atk.h>
#include <map>
#include <utility>
#include "base/environment.h" #include "base/environment.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
...@@ -75,6 +77,25 @@ static G_CONST_RETURN gchar* atk_util_auralinux_get_toolkit_version(void) { ...@@ -75,6 +77,25 @@ static G_CONST_RETURN gchar* atk_util_auralinux_get_toolkit_version(void) {
return "1.0"; return "1.0";
} }
static std::map<guint, std::pair<AtkKeySnoopFunc, gpointer>>
g_key_snoop_function_map;
static guint atk_util_add_key_event_listener(AtkKeySnoopFunc key_snoop_function,
gpointer data) {
static guint current_key_event_listener_id = 0;
current_key_event_listener_id++;
g_key_snoop_function_map[current_key_event_listener_id] =
std::make_pair(key_snoop_function, data);
return current_key_event_listener_id;
}
static void atk_util_remove_key_event_listener(guint listener_id) {
auto it = g_key_snoop_function_map.find(listener_id);
if (it != g_key_snoop_function_map.end())
g_key_snoop_function_map.erase(it);
}
static void atk_util_auralinux_class_init(AtkUtilAuraLinuxClass *klass) { static void atk_util_auralinux_class_init(AtkUtilAuraLinuxClass *klass) {
AtkUtilClass *atk_class; AtkUtilClass *atk_class;
gpointer data; gpointer data;
...@@ -85,6 +106,8 @@ static void atk_util_auralinux_class_init(AtkUtilAuraLinuxClass *klass) { ...@@ -85,6 +106,8 @@ static void atk_util_auralinux_class_init(AtkUtilAuraLinuxClass *klass) {
atk_class->get_root = atk_util_auralinux_get_root; atk_class->get_root = atk_util_auralinux_get_root;
atk_class->get_toolkit_name = atk_util_auralinux_get_toolkit_name; atk_class->get_toolkit_name = atk_util_auralinux_get_toolkit_name;
atk_class->get_toolkit_version = atk_util_auralinux_get_toolkit_version; atk_class->get_toolkit_version = atk_util_auralinux_get_toolkit_version;
atk_class->add_key_event_listener = atk_util_add_key_event_listener;
atk_class->remove_key_event_listener = atk_util_remove_key_event_listener;
} }
G_END_DECLS G_END_DECLS
...@@ -130,4 +153,32 @@ void AtkUtilAuraLinux::InitializeForTesting() { ...@@ -130,4 +153,32 @@ void AtkUtilAuraLinux::InitializeForTesting() {
InitializeAsync(); InitializeAsync();
} }
// static
DiscardAtkKeyEvent AtkUtilAuraLinux::HandleAtkKeyEvent(
AtkKeyEventStruct* key_event) {
DCHECK(key_event);
if (!GetInstance()->ShouldEnableAccessibility())
return DiscardAtkKeyEvent::Retain;
GetInstance()->InitializeAsync();
bool discard = false;
for (auto it = g_key_snoop_function_map.begin();
it != g_key_snoop_function_map.end(); it++) {
AtkKeySnoopFunc key_snoop_function = it->second.first;
gpointer data = it->second.second;
if (key_snoop_function(key_event, data) != 0)
discard = true;
}
return discard ? DiscardAtkKeyEvent::Discard : DiscardAtkKeyEvent::Retain;
}
#if !defined(USE_X11)
DiscardAtkKeyEvent AtkUtilAuraLinux::HandleKeyEvent(
const ui::KeyEvent& ui_key_event) {
NOTREACHED();
}
#endif
} // namespace ui } // namespace ui
...@@ -5,12 +5,34 @@ ...@@ -5,12 +5,34 @@
#ifndef UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_ #ifndef UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_
#define UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_ #define UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_
#include <atk/atk.h>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_export.h"
#if defined(USE_X11)
#include "ui/gfx/x/x11.h"
#endif
namespace ui { namespace ui {
// These values are duplicates of the GDK values that can be found in
// <gdk/gdktypes.h>. ATK expects the GDK values, but we don't want to depend on
// GDK here.
typedef enum {
kAtkShiftMask = 1 << 0,
kAtkLockMask = 1 << 1,
kAtkControlMask = 1 << 2,
kAtkMod1Mask = 1 << 3,
kAtkMod2Mask = 1 << 4,
kAtkMod3Mask = 1 << 5,
kAtkMod4Mask = 1 << 6,
KAtkMod5Mask = 1 << 7,
} AtkKeyModifierMask;
enum DiscardAtkKeyEvent { Discard, Retain };
// This singleton class initializes ATK (accessibility toolkit) and // This singleton class initializes ATK (accessibility toolkit) and
// registers an implementation of the AtkUtil class, a global class that // registers an implementation of the AtkUtil class, a global class that
// every accessible application needs to register once. // every accessible application needs to register once.
...@@ -24,6 +46,12 @@ class AX_EXPORT AtkUtilAuraLinux { ...@@ -24,6 +46,12 @@ class AX_EXPORT AtkUtilAuraLinux {
void InitializeAsync(); void InitializeAsync();
void InitializeForTesting(); void InitializeForTesting();
static DiscardAtkKeyEvent HandleAtkKeyEvent(AtkKeyEventStruct* key_event);
#if defined(USE_X11)
static DiscardAtkKeyEvent HandleKeyEvent(XEvent* xevent);
#endif
private: private:
friend struct base::DefaultSingletonTraits<AtkUtilAuraLinux>; friend struct base::DefaultSingletonTraits<AtkUtilAuraLinux>;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Chromium cannot upgrade to ATK 2.12 API as it still needs to run
// valid builds for Ubuntu Trusty.
#define ATK_DISABLE_DEPRECATION_WARNINGS
#include <atk/atk.h>
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/platform/atk_util_auralinux.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
#include "ui/accessibility/platform/ax_platform_node_unittest.h"
#include "ui/accessibility/platform/test_ax_node_wrapper.h"
namespace ui {
class AtkUtilAuraLinuxTest : public AXPlatformNodeTest {
public:
AtkUtilAuraLinuxTest() {
// We need to create a platform node in order to install it as the root
// ATK node. The ATK bridge will complain if we try to use it without a
// root node installed.
AXNodeData root;
root.id = 1;
Init(root);
TestAXNodeWrapper* wrapper =
TestAXNodeWrapper::GetOrCreate(tree_.get(), GetRootNode());
if (!wrapper)
NOTREACHED();
AXPlatformNodeAuraLinux::SetApplication(wrapper->ax_platform_node());
AtkUtilAuraLinux::GetInstance()->InitializeForTesting();
}
~AtkUtilAuraLinuxTest() override {
TestAXNodeWrapper* wrapper =
TestAXNodeWrapper::GetOrCreate(tree_.get(), GetRootNode());
if (!wrapper)
NOTREACHED();
g_object_unref(wrapper->ax_platform_node()->GetNativeViewAccessible());
}
};
TEST_F(AtkUtilAuraLinuxTest, KeySnooping) {
AtkKeySnoopFunc key_snoop_func = reinterpret_cast<AtkKeySnoopFunc>(
+[](AtkKeyEventStruct* key_event, int* keyval_seen) {
*keyval_seen = key_event->keyval;
});
int keyval_seen = 0;
guint listener_id = atk_add_key_event_listener(key_snoop_func, &keyval_seen);
AtkKeyEventStruct atk_key_event;
atk_key_event.type = ATK_KEY_EVENT_PRESS;
atk_key_event.state = 0;
atk_key_event.keyval = 55;
atk_key_event.keycode = 10;
atk_key_event.timestamp = 10;
atk_key_event.string = nullptr;
atk_key_event.length = 0;
AtkUtilAuraLinux* atk_util = AtkUtilAuraLinux::GetInstance();
atk_util->HandleAtkKeyEvent(&atk_key_event);
EXPECT_EQ(keyval_seen, 55);
atk_remove_key_event_listener(listener_id);
keyval_seen = 0;
atk_util->HandleAtkKeyEvent(&atk_key_event);
EXPECT_EQ(keyval_seen, 0);
}
} // namespace ui
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <atk/atk.h>
#include "ui/accessibility/platform/atk_util_auralinux.h"
#include "ui/events/x/events_x_utils.h"
namespace ui {
// static
DiscardAtkKeyEvent AtkUtilAuraLinux::HandleKeyEvent(XEvent* xevent) {
if (!GetInstance()->ShouldEnableAccessibility())
return DiscardAtkKeyEvent::Retain;
AtkKeyEventStruct atk_key_event;
if (xevent->type == KeyPress)
atk_key_event.type = ATK_KEY_EVENT_PRESS;
else if (xevent->type == KeyRelease)
atk_key_event.type = ATK_KEY_EVENT_RELEASE;
else
NOTREACHED() << xevent->type;
XKeyEvent& xkey = xevent->xkey;
KeySym keysym = NoSymbol;
XLookupString(&xkey, nullptr, 0, &keysym, nullptr);
atk_key_event.state = xkey.state;
atk_key_event.keyval = keysym;
atk_key_event.keycode = xkey.keycode;
atk_key_event.timestamp = xkey.time;
// This string property matches the one that was removed from GdkEventKey. In
// the future, ATK clients should no longer rely on it, so we set it to null.
atk_key_event.string = nullptr;
atk_key_event.length = 0;
int flags = ui::EventFlagsFromXEvent(*xevent);
if (flags & ui::EF_SHIFT_DOWN)
atk_key_event.state |= AtkKeyModifierMask::kAtkShiftMask;
if (flags & ui::EF_CAPS_LOCK_ON)
atk_key_event.state |= AtkKeyModifierMask::kAtkLockMask;
if (flags & ui::EF_CONTROL_DOWN)
atk_key_event.state |= AtkKeyModifierMask::kAtkControlMask;
if (flags & ui::EF_ALT_DOWN)
atk_key_event.state |= AtkKeyModifierMask::kAtkMod1Mask;
if (flags & ui::EF_NUM_LOCK_ON)
atk_key_event.state |= AtkKeyModifierMask::kAtkMod2Mask;
if (flags & ui::EF_MOD3_DOWN)
atk_key_event.state |= AtkKeyModifierMask::kAtkMod3Mask;
if (flags & ui::EF_COMMAND_DOWN)
atk_key_event.state |= AtkKeyModifierMask::kAtkMod4Mask;
if (flags & ui::EF_ALTGR_DOWN)
atk_key_event.state |= AtkKeyModifierMask::KAtkMod5Mask;
return HandleAtkKeyEvent(&atk_key_event);
}
} // namespace ui
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPath.h"
#include "ui/accessibility/platform/atk_util_auralinux.h"
#include "ui/aura/client/aura_constants.h" #include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h" #include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h" #include "ui/aura/client/focus_client.h"
...@@ -2045,8 +2046,11 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( ...@@ -2045,8 +2046,11 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
break; break;
} }
case KeyPress: { case KeyPress: {
ui::KeyEvent keydown_event(xev); if (ui::AtkUtilAuraLinux::HandleKeyEvent(xev) !=
DispatchKeyEvent(&keydown_event); ui::DiscardAtkKeyEvent::Discard) {
ui::KeyEvent keydown_event(xev);
DispatchKeyEvent(&keydown_event);
}
break; break;
} }
case KeyRelease: { case KeyRelease: {
...@@ -2055,8 +2059,11 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( ...@@ -2055,8 +2059,11 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
if (!IsActive() && !HasCapture()) if (!IsActive() && !HasCapture())
break; break;
ui::KeyEvent key_event(xev); if (ui::AtkUtilAuraLinux::HandleKeyEvent(xev) !=
DispatchKeyEvent(&key_event); ui::DiscardAtkKeyEvent::Discard) {
ui::KeyEvent key_event(xev);
DispatchKeyEvent(&key_event);
}
break; break;
} }
case ButtonPress: case ButtonPress:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment