Add two api for synchronize, waitForEvents, sendKeyAndWaitForEvents.
sample:
mDevice->sendKeyAndWaitForEvents("Left", A11yEvent::EVENT_STATE_CHANGED_FOCUSED, 5000)
mDevice->waitForEvents(A11yEvent::EVENT_WINDOW_DEACTIVATE, 5000)
Change-Id: If3886af4b2331f5e50f35e1dfcd27780c9618b93
--- /dev/null
+#pragma once
+#include "bitmask.h"
+
+#include <string>
+
+enum class A11yEvent {
+ EVENT_NONE = 0x00000,
+ EVENT_WINDOW_CREATE = 0x00001,
+ EVENT_WINDOW_CLOSE = 0x00002,
+ EVENT_WINDOW_MINIMIZE = 0x00004,
+ EVENT_WINDOW_MAXIMIZE = 0x00008,
+ EVENT_WINDOW_RESTORE = 0x00010,
+ EVENT_WINDOW_ACTIVATE = 0x00020,
+ EVENT_WINDOW_DEACTIVATE = 0x00040,
+ EVENT_WINDOW_RAISE = 0x00080,
+ EVENT_WINDOW_LOWER = 0x00100,
+ EVENT_WINDOW_MOVE = 0x00200,
+ EVENT_WINDOW_RESIZE = 0x00400,
+
+ EVENT_TEXT_CHANGED_INSERT = 0x00800,
+ EVENT_TEXT_CHANGED_DELETE = 0x01000,
+
+ EVENT_STATE_CHANGED_VISIBLE = 0x02000,
+ EVENT_STATE_CHANGED_FOCUSED = 0x04000,
+ EVENT_STATE_CHANGED_CHECKED = 0x08000,
+ EVENT_STATE_CHANGED_PRESSED = 0x10000,
+ EVENT_STATE_CHANGED_SELECTED = 0x20000,
+};
+
+enableEnumClassBitfield(A11yEvent);
+
+class A11yEventInfo {
+public:
+ A11yEventInfo();
+ A11yEventInfo(A11yEvent event, std::string name = "", std::string pkg = "");
+ A11yEventInfo(std::string event, std::string name = "", std::string pkg = "");
+ ~A11yEventInfo();
+public:
+ A11yEvent getEvent();
+ A11yEvent getEvent(std::string event);
+ std::string getName();
+ std::string getPkg();
+
+protected:
+ const A11yEvent mEvent;
+ const std::string mName;
+ const std::string mPkg;
+};
+
#include "AccessibleNode.h"
#include "AccessibleUtils.h"
#include "IEventSource.h"
+#include "Runnable.h"
+#include "A11yEvent.h"
#include <memory>
#include <vector>
*/
virtual std::vector<std::shared_ptr<AccessibleApplication>> getApplications(void) const = 0;
+ /**s
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) = 0;
+
public:
/**
* @brief TBD
* @brief TBD
*/
std::mutex mLock;
-};
\ No newline at end of file
+};
*/
virtual std::vector<std::shared_ptr<AccessibleApplication>> getApplications(void) const override;
+ /**
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) override;
+
public:
/**
* @brief TBD
*/
void onObjectDefunct(AtspiAccessible* node) override;
+ /**
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ static void onEventListener(AtspiEvent *event, void *user_data);
private:
/**
* @brief TBD
void print_debug();
-private:
+ /**
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ void addEventListener(AtspiEventListener *listener, A11yEvent type);
+
+ /**
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ void removeEventListener(AtspiEventListener *listener, A11yEvent type);
+
+public:
/**
* @brief TBD
*/
- static AtspiEventListener * listener;
+ static guint timeoutId;
+private:
/**
* @brief TBD
*/
*/
std::map<AtspiAccessible *, AtspiAccessible *> mWindowAppMap;
-};
\ No newline at end of file
+ /**
+ * @brief TBD
+ */
+ static GThread * mEventThread;
+
+ /**
+ * @brief TBD
+ */
+ static std::vector<std::shared_ptr<A11yEventInfo>> mEventQueue;
+};
*/
virtual std::vector<std::shared_ptr<AccessibleApplication>> getApplications(void) const override;
+ /**
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) override;
+
public:
/**
* @brief TBD
* @brief TBD
*/
std::vector<std::shared_ptr<AccessibleApplication>> mApplicationList;
-};
\ No newline at end of file
+};
--- /dev/null
+#pragma once
+
+class Runnable
+{
+public:
+ virtual ~Runnable() { }
+ virtual void run() const = 0;
+};
+
--- /dev/null
+#pragma once
+
+#include "SendKeyRunnable.h"
--- /dev/null
+#pragma once
+
+#include <string>
+
+#include "Runnable.h"
+
+class SendKeyRunnable : public Runnable {
+protected:
+ std::string mKeycode;
+
+public:
+ SendKeyRunnable(std::string keycode);
+ void run() const override;
+};
#include "AccessibleNode.h"
#include "Waiter.h"
+#include "Runnable.h"
+#include "A11yEvent.h"
+
#include <functional>
#include <string>
std::shared_ptr<UiObject> waitFor(
const std::function<std::shared_ptr<UiObject>(const ISearchable *)>
condition) const;
+
+ /**
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ bool waitForEvents(
+ const A11yEvent type, const int timeout) const;
+
+ /**
+ * @brief TBD
+ * @since_tizen 6.5
+ */
+ bool sendKeyAndWaitForEvents(
+ const std::string keycode, const A11yEvent type, const int timeout) const;
+private:
+ bool executeAndWaitForEvents(
+ const Runnable *cmd, const A11yEvent type, const int timeout) const;
public:
/**
* @brief TBD
* @brief TBD
*/
const Waiter *mWaiter;
-};
\ No newline at end of file
+};
--- /dev/null
+#pragma once
+#include <type_traits>
+
+template<typename E>
+struct enable_bitmask_operators{
+ static const bool enable=false;
+};
+
+#define enableEnumClassBitfield(E) template<> \
+ struct enable_bitmask_operators<E>{ \
+ static const bool enable=true; \
+ }
+
+template<typename E>
+typename std::enable_if_t<enable_bitmask_operators<E>::enable,E>
+operator|(E lhs,E rhs){
+ typedef typename std::underlying_type_t<E> underlying;
+ return static_cast<E>(
+ static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
+}
+
+template<typename E>
+typename std::enable_if_t<enable_bitmask_operators<E>::enable,E>
+operator&(E lhs,E rhs){
+ typedef typename std::underlying_type_t<E> underlying;
+ return static_cast<E>(
+ static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
+}
+
+template<typename E>
+typename std::enable_if_t<enable_bitmask_operators<E>::enable,E>
+operator^(E lhs,E rhs){
+ typedef typename std::underlying_type_t<E> underlying;
+ return static_cast<E>(
+ static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
+}
+
+template<typename E>
+typename std::enable_if_t<enable_bitmask_operators<E>::enable,E>
+operator~(E lhs){
+ typedef typename std::underlying_type_t<E> underlying;
+ return static_cast<E>(
+ ~static_cast<underlying>(lhs));
+}
+
+template<typename E>
+typename std::enable_if_t<enable_bitmask_operators<E>::enable,E&>
+operator|=(E& lhs,E rhs){
+ typedef typename std::underlying_type_t<E> underlying;
+ lhs=static_cast<E>(
+ static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
+ return lhs;
+}
+
+template<typename E>
+typename std::enable_if_t<enable_bitmask_operators<E>::enable,E&>
+operator&=(E& lhs,E rhs){
+ typedef typename std::underlying_type_t<E> underlying;
+ lhs=static_cast<E>(
+ static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
+ return lhs;
+}
+
+template<typename E>
+typename std::enable_if_t<enable_bitmask_operators<E>::enable,E&>
+operator^=(E& lhs,E rhs){
+ typedef typename std::underlying_type_t<E> underlying;
+ lhs=static_cast<E>(
+ static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
+ return lhs;
+}
+
'./inc/Waiter.h',
'./inc/ISearchable.h',
'./inc/IDevice.h',
+ './inc/A11yEvent.h',
+ './inc/bitmask.h',
'./inc/Accessibility/AccessibleNode.h',
'./inc/Accessibility/AccessibleUtils.h',
'./inc/Accessibility/AccessibleWatcher.h',
'./inc/Accessibility/AccessibleWindow.h',
'./inc/Accessibility/IEventConsumer.h',
'./inc/Accessibility/IEventSource.h',
+ './inc/Runnable/Runnable.h',
'./inc/Misc/Point2D.h',
'./inc/Misc/Rect.h',
'./inc/Aurum.h',
include_directories('./inc/Impl'),
include_directories('./inc/Impl/Accessibility'),
include_directories('./inc/Misc'),
+ include_directories('./inc/Runnable/'),
root_inc,
loguru_inc,
]
--- /dev/null
+#include "A11yEvent.h"
+
+#include <unordered_map>
+
+A11yEventInfo::A11yEventInfo() : A11yEventInfo(A11yEvent::EVENT_NONE, nullptr, nullptr) {}
+
+A11yEventInfo::~A11yEventInfo() {}
+
+A11yEventInfo::A11yEventInfo(A11yEvent event, std::string name, std::string pkg)
+ : mEvent(event),
+ mName(name),
+ mPkg(pkg)
+{
+}
+
+A11yEventInfo::A11yEventInfo(std::string event, std::string name, std::string pkg)
+ : mEvent(getEvent(event)),
+ mName(name),
+ mPkg(pkg)
+{
+}
+
+
+static std::unordered_map<std::string,A11yEvent> const table = { {"window:create", A11yEvent::EVENT_WINDOW_CREATE},
+ {"window:close", A11yEvent::EVENT_WINDOW_CLOSE},
+ {"window:minimize", A11yEvent::EVENT_WINDOW_MINIMIZE},
+ {"window:maxmize", A11yEvent::EVENT_WINDOW_MAXIMIZE},
+ {"window:restore", A11yEvent::EVENT_WINDOW_RESTORE},
+ {"window:activate", A11yEvent::EVENT_WINDOW_ACTIVATE},
+ {"window:deactivate", A11yEvent::EVENT_WINDOW_DEACTIVATE},
+ {"window:raise", A11yEvent::EVENT_WINDOW_RAISE},
+ {"window:lower", A11yEvent::EVENT_WINDOW_LOWER},
+ {"window:resize", A11yEvent::EVENT_WINDOW_RESIZE},
+ {"window:move", A11yEvent::EVENT_WINDOW_MOVE},
+ {"object:text-changed:insert", A11yEvent::EVENT_TEXT_CHANGED_INSERT},
+ {"object:text-changed:delete", A11yEvent::EVENT_TEXT_CHANGED_DELETE},
+ {"object:state-changed:VISIBLE", A11yEvent::EVENT_STATE_CHANGED_VISIBLE},
+ {"object:state-changed:focused", A11yEvent::EVENT_STATE_CHANGED_FOCUSED},
+ {"object:state-changed:checked", A11yEvent::EVENT_STATE_CHANGED_CHECKED},
+ {"object:state-changed:pressed", A11yEvent::EVENT_STATE_CHANGED_PRESSED},
+ {"object:state-changed:selected", A11yEvent::EVENT_STATE_CHANGED_SELECTED} };
+
+A11yEvent A11yEventInfo::getEvent()
+{
+ return mEvent;
+}
+
+A11yEvent A11yEventInfo::getEvent(std::string event)
+{
+ auto it = table.find(event);
+ if (it != table.end()) {
+ return it->second;
+ }
+ return A11yEvent::EVENT_NONE;
+}
+
+std::string A11yEventInfo::getName()
+{
+ return mName;
+}
+
+std::string A11yEventInfo::getPkg()
+{
+ return mPkg;
+}
default:
break;
}
-}
\ No newline at end of file
+}
#include "AtspiAccessibleNode.h"
#include "AtspiWrapper.h"
#include <algorithm>
+#include <chrono>
+#include <thread>
+#include <iostream>
#include <loguru.hpp>
-AtspiEventListener *AtspiAccessibleWatcher::listener = nullptr;
+std::vector<std::shared_ptr<A11yEventInfo>> AtspiAccessibleWatcher::mEventQueue;
+GThread *AtspiAccessibleWatcher::mEventThread = nullptr;
static bool iShowingNode(AtspiAccessible *node)
{
std::vector<AtspiAccessible *> ret{};
if (iShowingNode(node)) {
- g_object_ref(node);
char *name = AtspiWrapper::Atspi_accessible_get_name(node, NULL);
if (name) {
LOG_SCOPE_F(INFO, "%s", name);
return ret;
}
+static gpointer _event_thread_loop (gpointer data)
+{
+ LOG_F(INFO, "event thread start");
+ AtspiEventListener * listener =
+ atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiEvents, NULL, NULL);
+
+ atspi_event_listener_register(listener, "window:", NULL);
+ atspi_event_listener_register(listener, "object:state-changed:focused", NULL);
+ atspi_event_listener_register(listener, "object:text-changed:insert", NULL);
+
+ atspi_event_main();
+end:
+ LOG_F(INFO, "event thread end");
+ atspi_event_listener_deregister(listener, "object:state-changed:focused", NULL);
+ atspi_event_listener_deregister(listener, "object:text-changed:insert", NULL);
+ atspi_event_listener_deregister(listener, "window:", NULL);
+
+ g_object_unref(listener);
+
+ return NULL;
+}
AtspiAccessibleWatcher::AtspiAccessibleWatcher()
: mDbusProxy{nullptr}
{
atspi_set_main_context (g_main_context_default ());
atspi_init();
- listener =
- atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiEvents, this, NULL);
-
- atspi_event_listener_register(listener, "window:", NULL);
- atspi_event_listener_register(listener, "object:", NULL);
+ mEventThread = g_thread_new("AtspiEventThread", _event_thread_loop, nullptr);
mDbusProxy = g_dbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE,
g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
- g_variant_unref(enabled_variant);
g_variant_unref(result);
}
g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
- atspi_event_listener_deregister(listener, "window:", NULL);
- atspi_event_listener_deregister(listener, "object:", NULL);
-
- g_object_unref(listener);
g_object_unref(mDbusProxy);
- g_variant_unref(enabled_variant);
g_variant_unref(result);
atspi_event_quit();
+ g_thread_join(mEventThread);
atspi_exit();
}
-
void AtspiAccessibleWatcher::onAtspiEvents(AtspiEvent *event, void *user_data)
{
AtspiWrapper::lock();
- char *name = NULL, *pname = NULL;
+ if (!event->source)
+ {
+ AtspiWrapper::unlock();
+ return;
+ }
+ char *name = NULL, *pkg = NULL;
+ name = AtspiWrapper::Atspi_accessible_get_name(event->source, NULL);
+
+ AtspiAccessible *app = AtspiWrapper::Atspi_accessible_get_application(event->source, NULL);
+ if (app)
+ {
+ pkg = AtspiWrapper::Atspi_accessible_get_name(app, NULL);
+ g_object_unref(app);
+ }
+ else
+ pkg = strdup("");
+
+ mEventQueue.push_back(std::make_shared<A11yEventInfo>(std::string(event->type), std::string(name), std::string(pkg)));
+ if (name) free(name);
+ if (pkg) free(pkg);
+/* char *name = NULL, *pname = NULL;
AtspiAccessibleWatcher *instance = (AtspiAccessibleWatcher *)user_data;
if (!event->source)
static_cast<AtspiAccessible *>(event->source));
}
if (name) free(name);
- if (pname) free(pname);
+ if (pname) free(pname);*/
AtspiWrapper::unlock();
}
return ret;
}
+#define COMPARE(A, B) \
+ (B != A11yEvent::EVENT_NONE) && ((A & B) == B)
+
+bool AtspiAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout)
+{
+ AtspiWrapper::lock();
+ mEventQueue.clear();
+ AtspiWrapper::unlock();
+ if (cmd)
+ cmd->run();
+
+ std::chrono::system_clock::time_point start =
+ std::chrono::system_clock::now();
+ while (true)
+ {
+ std::vector<std::shared_ptr<A11yEventInfo>> localEvents;
+ AtspiWrapper::lock();
+ localEvents.assign(mEventQueue.begin(), mEventQueue.end());
+ mEventQueue.clear();
+ AtspiWrapper::unlock();
+
+ if (!localEvents.empty())
+ {
+ for (const auto &event : localEvents) {
+ if (COMPARE(type, event->getEvent()))
+ {
+ LOG_F(INFO, "type %d == %d name %s pkg %s",static_cast<int>(type), static_cast<int>(event->getEvent()), event->getName().c_str(), event->getPkg().c_str());
+ return true;
+ }
+ }
+ }
+ if ((std::chrono::system_clock::now() - start) >
+ std::chrono::milliseconds{timeout})
+ break;
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds{100});
+ }
+
+ return false;
+}
+
bool AtspiAccessibleWatcher::removeFromActivatedList(AtspiAccessible *node)
{
LOG_SCOPE_F(INFO,"remove from activelist node %p", node);
std::shared_ptr<MockAccessibleApplication> app = std::make_shared<MockAccessibleApplication>(appNode);
this->addApplication(app);
return app;
-}
\ No newline at end of file
+}
+
+bool MockAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout)
+{
+ return true;
+}
--- /dev/null
+#include "SendKeyRunnable.h"
+
+#include <UiDevice.h>
+#include <loguru.hpp>
+
+SendKeyRunnable::SendKeyRunnable(std::string keycode)
+ : mKeycode{keycode}
+{
+}
+
+void SendKeyRunnable::run() const
+{
+ LOG_F(INFO, "sendKey %s",mKeycode.c_str());
+ std::shared_ptr<UiDevice> mDevice = UiDevice::getInstance();
+ mDevice->pressKeyCode(mKeycode.c_str(), KeyRequestType::PRESS);
+ mDevice->pressKeyCode(mKeycode.c_str(), KeyRequestType::RELEASE);
+}
+
--- /dev/null
+libaurum_src += [
+ files('SendKeyRunnable.cc')
+]
#endif
#include "MockDeviceImpl.h"
+#include "Runnables.h"
+
#include <unistd.h>
#include <utility>
#include <vector>
return true;
}
+bool UiDevice::waitForEvents(
+ const A11yEvent type, const int timeout) const
+{
+ return executeAndWaitForEvents(NULL, type, timeout);
+}
+
+bool UiDevice::executeAndWaitForEvents(
+ const Runnable *cmd, const A11yEvent type, const int timeout) const
+{
+ return AccessibleWatcher::getInstance()->executeAndWaitForEvents(cmd, type, timeout);
+}
+
+bool UiDevice::sendKeyAndWaitForEvents(
+ const std::string keycode, const A11yEvent type, const int timeout) const
+{
+ std::unique_ptr<SendKeyRunnable> cmd = std::make_unique<SendKeyRunnable>(keycode);
+ return executeAndWaitForEvents(cmd.get(), type, timeout);
+}
+
bool UiDevice::click(const int x, const int y)
{
bool result = mDeviceImpl->click(x, y);
files('Until.cc'),
files('Waiter.cc'),
files('PartialMatch.cc'),
+ files('A11yEvent.cc'),
]
subdir('Accessibility')
-subdir('Impl')
\ No newline at end of file
+subdir('Impl')
+subdir('Runnable')