From 8ebd373380467080dd2508864ce7d43a4abef58a Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Sun, 26 Feb 2023 13:54:52 -0700 Subject: [PATCH 01/10] attempting to fix duplicate symbols on mac --- actions/action/keystroke.cc | 10 +++++++++- actions/action/keystroke.h | 6 ++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/actions/action/keystroke.cc b/actions/action/keystroke.cc index bd05b88..b3e92bd 100644 --- a/actions/action/keystroke.cc +++ b/actions/action/keystroke.cc @@ -1,3 +1,11 @@ #include "actions/action/keystroke.h" -namespace actions::action {} // namespace actions::action \ No newline at end of file +namespace actions::action { +absl::StatusOr > ParseKeystroke(std::string str) noexcept { +#if defined(__linux__) + return internal::linux::ParseKeystroke(str); +#else + return std::vector(); +#endif +} +} // namespace actions::action \ No newline at end of file diff --git a/actions/action/keystroke.h b/actions/action/keystroke.h index beaea7c..f1aacb7 100644 --- a/actions/action/keystroke.h +++ b/actions/action/keystroke.h @@ -15,14 +15,12 @@ namespace actions::action { #if defined(__linux__) using internal::linux::Key; -using internal::linux::ParseKeystroke; #else using Key = unsigned int; -absl::StatusOr > ParseKeystroke(std::string) noexcept { - return std::vector(); -} #endif +absl::StatusOr > ParseKeystroke(std::string) noexcept; + /// @brief Represents a keystroke. A collection of keys with associated /// modifiers. using Keystroke = std::vector; From 680b5a23853e50f75a53d04a19e5e9a1fe3013c9 Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Sun, 9 Apr 2023 20:19:23 -0600 Subject: [PATCH 02/10] remove setup --- WORKSPACE | 4 ---- setup.bzl | 5 ----- 2 files changed, 9 deletions(-) delete mode 100644 setup.bzl diff --git a/WORKSPACE b/WORKSPACE index 1da6007..763f10d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -38,7 +38,3 @@ hedron_compile_commands_setup() load("//:repositories.bzl", "actions_repositories") actions_repositories() - -load("//:setup.bzl", "actions_setup") - -actions_setup() diff --git a/setup.bzl b/setup.bzl deleted file mode 100644 index 89b3cf0..0000000 --- a/setup.bzl +++ /dev/null @@ -1,5 +0,0 @@ -"""Setup for a workspace dependent on actions""" - -def actions_setup(): - """Setup for a workspace dependent on actions""" - pass From ace866cde25e00a7c5522f163c8b5dcbee445599 Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Mon, 10 Apr 2023 01:03:45 -0600 Subject: [PATCH 03/10] auto detect x11 installation --- WORKSPACE | 8 ++ actions/BUILD | 6 +- actions/action/BUILD | 6 +- actions/action/keystroke.cc | 4 +- actions/action/keystroke.h | 8 +- actions/actions.cc | 8 +- actions/internal/linux/keystroke.h | 19 --- actions/internal/{linux => x11}/BUILD | 6 +- actions/internal/{linux => x11}/keystroke.cc | 6 +- actions/internal/x11/keystroke.h | 19 +++ .../internal/{linux => x11}/xcb_connection.cc | 10 +- .../internal/{linux => x11}/xcb_connection.h | 12 +- actions/internal/{linux => x11}/xcb_error.cc | 6 +- actions/internal/{linux => x11}/xcb_error.h | 10 +- .../internal/{linux => x11}/xcb_keyboard.cc | 8 +- .../internal/{linux => x11}/xcb_keyboard.h | 10 +- display/BUILD | 5 + display/display.tpl.BUILD | 16 +++ display/display_configure.bzl | 121 ++++++++++++++++++ display/local_display.tpl.bzl | 49 +++++++ repositories.bzl | 14 -- third_party/X11.BUILD | 22 +++- third_party/xcb.BUILD | 33 +++-- 23 files changed, 316 insertions(+), 90 deletions(-) delete mode 100644 actions/internal/linux/keystroke.h rename actions/internal/{linux => x11}/BUILD (83%) rename actions/internal/{linux => x11}/keystroke.cc (88%) create mode 100644 actions/internal/x11/keystroke.h rename actions/internal/{linux => x11}/xcb_connection.cc (92%) rename actions/internal/{linux => x11}/xcb_connection.h (76%) rename actions/internal/{linux => x11}/xcb_error.cc (94%) rename actions/internal/{linux => x11}/xcb_error.h (74%) rename actions/internal/{linux => x11}/xcb_keyboard.cc (93%) rename actions/internal/{linux => x11}/xcb_keyboard.h (82%) create mode 100644 display/BUILD create mode 100644 display/display.tpl.BUILD create mode 100644 display/display_configure.bzl create mode 100644 display/local_display.tpl.bzl diff --git a/WORKSPACE b/WORKSPACE index 763f10d..237f8c5 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -38,3 +38,11 @@ hedron_compile_commands_setup() load("//:repositories.bzl", "actions_repositories") actions_repositories() + +load("@actions//display:display_configure.bzl", "display_configure") + +display_configure() + +load("@display//:local_display.bzl", "display_repositories") + +display_repositories() diff --git a/actions/BUILD b/actions/BUILD index 9299d1f..1086015 100644 --- a/actions/BUILD +++ b/actions/BUILD @@ -14,6 +14,10 @@ cc_library( name = "actions", srcs = ["actions.cc"], hdrs = ["actions.h"], + copts = select({ + "@display//:x11": ["-D __x11__"], + "//conditions:default": [], + }), deps = [ ":action", "//actions/internal:connection", @@ -21,7 +25,7 @@ cc_library( "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", ] + select({ - "@platforms//os:linux": ["//actions/internal/linux:xcb_connection"], + "@display//:x11": ["//actions/internal/x11:xcb_connection"], "//conditions:default": ["//actions/internal/stub:stub_connection"], }), ) diff --git a/actions/action/BUILD b/actions/action/BUILD index 88bd351..ca7895d 100644 --- a/actions/action/BUILD +++ b/actions/action/BUILD @@ -4,12 +4,16 @@ cc_library( name = "keystroke", srcs = ["keystroke.cc"], hdrs = ["keystroke.h"], + copts = select({ + "@display//:x11": ["-D __x11__"], + "//conditions:default": [], + }), deps = [ "@com_google_absl//absl/types:variant", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", ] + select({ - "@platforms//os:linux": ["//actions/internal/linux:keystroke"], + "@display//:x11": ["//actions/internal/x11:keystroke"], "//conditions:default": [], }), ) diff --git a/actions/action/keystroke.cc b/actions/action/keystroke.cc index b3e92bd..b4b42e4 100644 --- a/actions/action/keystroke.cc +++ b/actions/action/keystroke.cc @@ -2,8 +2,8 @@ namespace actions::action { absl::StatusOr > ParseKeystroke(std::string str) noexcept { -#if defined(__linux__) - return internal::linux::ParseKeystroke(str); +#if defined(__x11__) + return internal::x11::ParseKeystroke(str); #else return std::vector(); #endif diff --git a/actions/action/keystroke.h b/actions/action/keystroke.h index f1aacb7..e632a19 100644 --- a/actions/action/keystroke.h +++ b/actions/action/keystroke.h @@ -7,14 +7,14 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" -#if defined(__linux__) -#include "actions/internal/linux/keystroke.h" +#if defined(__x11__) +#include "actions/internal/x11/keystroke.h" #endif namespace actions::action { -#if defined(__linux__) -using internal::linux::Key; +#if defined(__x11__) +using internal::x11::Key; #else using Key = unsigned int; #endif diff --git a/actions/actions.cc b/actions/actions.cc index aaac12f..85a7586 100644 --- a/actions/actions.cc +++ b/actions/actions.cc @@ -5,8 +5,8 @@ #include "actions/internal/connection.h" #include "actions/internal/util.h" -#if defined(__linux) -#include "actions/internal/linux/xcb_connection.h" +#if defined(__x11__) +#include "actions/internal/x11/xcb_connection.h" #else #include "actions/internal/stub/stub_connection.h" #endif @@ -18,8 +18,8 @@ absl::StatusOr Actions::Create( } absl::StatusOr Actions::Create() noexcept { -#if defined(__linux) - auto conn = internal::linux::XcbConnection::Create(); +#if defined(__x11__) + auto conn = internal::x11::XcbConnection::Create(); #else auto conn = internal::stub::StubConnection::Create(); #endif diff --git a/actions/internal/linux/keystroke.h b/actions/internal/linux/keystroke.h deleted file mode 100644 index 45112e2..0000000 --- a/actions/internal/linux/keystroke.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ACTIONS_INTERNAL_LINUX_KEYSTROKE_H -#define ACTIONS_INTERNAL_LINUX_KEYSTROKE_H - -#include - -#include -#include - -#include "absl/status/statusor.h" - -namespace actions::internal::linux { - -using Key = xcb_keysym_t; - -absl::StatusOr> ParseKeystroke(std::string) noexcept; - -} // namespace actions::internal::linux - -#endif // ACTIONS_INTERNAL_LINUX_KEYSTROKE_H \ No newline at end of file diff --git a/actions/internal/linux/BUILD b/actions/internal/x11/BUILD similarity index 83% rename from actions/internal/linux/BUILD rename to actions/internal/x11/BUILD index 569a850..16076a3 100644 --- a/actions/internal/linux/BUILD +++ b/actions/internal/x11/BUILD @@ -4,6 +4,7 @@ cc_library( name = "keystroke", srcs = ["keystroke.cc"], hdrs = ["keystroke.h"], + target_compatible_with = ["@display//:x11"], deps = [ "@X11", "@com_google_absl//absl/status", @@ -17,6 +18,7 @@ cc_library( name = "xcb_connection", srcs = ["xcb_connection.cc"], hdrs = ["xcb_connection.h"], + target_compatible_with = ["@display//:x11"], deps = [ ":xcb_error", ":xcb_keyboard", @@ -33,8 +35,9 @@ cc_library( name = "xcb_error", srcs = ["xcb_error.cc"], hdrs = ["xcb_error.h"], + target_compatible_with = ["@display//:x11"], deps = [ - "@com_google_absl//absl/status:status", + "@com_google_absl//absl/status", "@xcb", ], ) @@ -43,6 +46,7 @@ cc_library( name = "xcb_keyboard", srcs = ["xcb_keyboard.cc"], hdrs = ["xcb_keyboard.h"], + target_compatible_with = ["@display//:x11"], deps = [ ":xcb_error", "//actions/action:keystroke", diff --git a/actions/internal/linux/keystroke.cc b/actions/internal/x11/keystroke.cc similarity index 88% rename from actions/internal/linux/keystroke.cc rename to actions/internal/x11/keystroke.cc index 4ba2f6b..fbad54b 100644 --- a/actions/internal/linux/keystroke.cc +++ b/actions/internal/x11/keystroke.cc @@ -1,4 +1,4 @@ -#include "actions/internal/linux/keystroke.h" +#include "actions/internal/x11/keystroke.h" #include @@ -7,7 +7,7 @@ #include #include -namespace actions::internal::linux { +namespace actions::internal::x11 { const static std::map symbol_map{ {"alt", "Alt_L"}, {"ctrl", "Control_L"}, @@ -44,4 +44,4 @@ absl::StatusOr> ParseKeystroke(std::string str) noexcept { return keys; } -} // namespace actions::internal::linux \ No newline at end of file +} // namespace actions::internal::x11 \ No newline at end of file diff --git a/actions/internal/x11/keystroke.h b/actions/internal/x11/keystroke.h new file mode 100644 index 0000000..dfb9c19 --- /dev/null +++ b/actions/internal/x11/keystroke.h @@ -0,0 +1,19 @@ +#ifndef ACTIONS_INTERNAL_X11_KEYSTROKE_H +#define ACTIONS_INTERNAL_X11_KEYSTROKE_H + +#include + +#include +#include + +#include "absl/status/statusor.h" + +namespace actions::internal::x11 { + +using Key = xcb_keysym_t; + +absl::StatusOr> ParseKeystroke(std::string) noexcept; + +} // namespace actions::internal::x11 + +#endif // ACTIONS_INTERNAL_X11_KEYSTROKE_H \ No newline at end of file diff --git a/actions/internal/linux/xcb_connection.cc b/actions/internal/x11/xcb_connection.cc similarity index 92% rename from actions/internal/linux/xcb_connection.cc rename to actions/internal/x11/xcb_connection.cc index 83ef3a6..8177ae8 100644 --- a/actions/internal/linux/xcb_connection.cc +++ b/actions/internal/x11/xcb_connection.cc @@ -1,4 +1,4 @@ -#include "actions/internal/linux/xcb_connection.h" +#include "actions/internal/x11/xcb_connection.h" #include #include @@ -7,11 +7,11 @@ #include "absl/status/status.h" #include "absl/types/variant.h" -#include "actions/internal/linux/xcb_error.h" -#include "actions/internal/linux/xcb_keyboard.h" #include "actions/internal/util.h" +#include "actions/internal/x11/xcb_error.h" +#include "actions/internal/x11/xcb_keyboard.h" -namespace actions::internal::linux { +namespace actions::internal::x11 { absl::StatusOr> XcbConnection::Create() noexcept { // Setup connection @@ -109,4 +109,4 @@ std::future XcbConnection::SendKeystroke( return keyboard.SendKeystrokes(keystroke, root); } -} // namespace actions::internal::linux \ No newline at end of file +} // namespace actions::internal::x11 \ No newline at end of file diff --git a/actions/internal/linux/xcb_connection.h b/actions/internal/x11/xcb_connection.h similarity index 76% rename from actions/internal/linux/xcb_connection.h rename to actions/internal/x11/xcb_connection.h index 179d645..1f52efb 100644 --- a/actions/internal/linux/xcb_connection.h +++ b/actions/internal/x11/xcb_connection.h @@ -1,5 +1,5 @@ -#ifndef ACTIONS_INTERNAL_LINUX_XCB_CONNECTION_H -#define ACTIONS_INTERNAL_LINUX_XCB_CONNECTION_H +#ifndef ACTIONS_INTERNAL_X11_XCB_CONNECTION_H +#define ACTIONS_INTERNAL_X11_XCB_CONNECTION_H #include @@ -8,9 +8,9 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "actions/internal/connection.h" -#include "actions/internal/linux/xcb_keyboard.h" +#include "actions/internal/x11/xcb_keyboard.h" -namespace actions::internal::linux { +namespace actions::internal::x11 { class XcbConnection : public Connection { private: @@ -36,6 +36,6 @@ class XcbConnection : public Connection { const action::Target& target) noexcept override; }; -} // namespace actions::internal::linux +} // namespace actions::internal::x11 -#endif // ACTIONS_INTERNAL_LINUX_XCB_CONNECTION_H \ No newline at end of file +#endif // ACTIONS_INTERNAL_X11_XCB_CONNECTION_H \ No newline at end of file diff --git a/actions/internal/linux/xcb_error.cc b/actions/internal/x11/xcb_error.cc similarity index 94% rename from actions/internal/linux/xcb_error.cc rename to actions/internal/x11/xcb_error.cc index 71cb89b..5fb1090 100644 --- a/actions/internal/linux/xcb_error.cc +++ b/actions/internal/x11/xcb_error.cc @@ -1,10 +1,10 @@ -#include "actions/internal/linux/xcb_error.h" +#include "actions/internal/x11/xcb_error.h" #include #include "absl/status/status.h" -namespace actions::internal::linux { +namespace actions::internal::x11 { absl::Status XcbStatus(int code) noexcept { switch (code) { case 0: @@ -58,4 +58,4 @@ absl::Status XcbErrorToStatus(xcb_connection_t *conn, std::to_string(error->major_code) + "." + std::to_string(error->minor_code)); } -} // namespace actions::internal::linux \ No newline at end of file +} // namespace actions::internal::x11 \ No newline at end of file diff --git a/actions/internal/linux/xcb_error.h b/actions/internal/x11/xcb_error.h similarity index 74% rename from actions/internal/linux/xcb_error.h rename to actions/internal/x11/xcb_error.h index bedcc9e..1e6564a 100644 --- a/actions/internal/linux/xcb_error.h +++ b/actions/internal/x11/xcb_error.h @@ -1,11 +1,11 @@ -#ifndef ACTIONS_INTERNAL_LINUX_XCB_ERROR_H -#define ACTIONS_INTERNAL_LINUX_XCB_ERROR_H +#ifndef ACTIONS_INTERNAL_X11_XCB_ERROR_H +#define ACTIONS_INTERNAL_X11_XCB_ERROR_H #include #include "absl/status/status.h" -namespace actions::internal::linux { +namespace actions::internal::x11 { /// @brief Converts an xcb status code to an `absl::Status`. /// @param code The xcb status code. /// @return The associated status. @@ -18,6 +18,6 @@ absl::Status XcbStatus(int code) noexcept; /// @return The associated status. absl::Status XcbErrorToStatus(xcb_connection_t *conn, xcb_generic_error_t *error) noexcept; -} // namespace actions::internal::linux +} // namespace actions::internal::x11 -#endif // ACTIONS_INTERNAL_LINUX_XCB_ERROR_H \ No newline at end of file +#endif // ACTIONS_INTERNAL_X11_XCB_ERROR_H \ No newline at end of file diff --git a/actions/internal/linux/xcb_keyboard.cc b/actions/internal/x11/xcb_keyboard.cc similarity index 93% rename from actions/internal/linux/xcb_keyboard.cc rename to actions/internal/x11/xcb_keyboard.cc index 5e33b4b..74465ef 100644 --- a/actions/internal/linux/xcb_keyboard.cc +++ b/actions/internal/x11/xcb_keyboard.cc @@ -1,4 +1,4 @@ -#include "actions/internal/linux/xcb_keyboard.h" +#include "actions/internal/x11/xcb_keyboard.h" #include #include @@ -11,10 +11,10 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "actions/action/keystroke.h" -#include "actions/internal/linux/xcb_error.h" #include "actions/internal/util.h" +#include "actions/internal/x11/xcb_error.h" -namespace actions::internal::linux { +namespace actions::internal::x11 { XcbKeyboard::XcbKeyboard(xcb_connection_t* conn) noexcept : conn(conn), key_symbols(xcb_key_symbols_alloc(conn)) {} @@ -93,4 +93,4 @@ std::future XcbKeyboard::SendFakeInput( }); } -} // namespace actions::internal::linux \ No newline at end of file +} // namespace actions::internal::x11 \ No newline at end of file diff --git a/actions/internal/linux/xcb_keyboard.h b/actions/internal/x11/xcb_keyboard.h similarity index 82% rename from actions/internal/linux/xcb_keyboard.h rename to actions/internal/x11/xcb_keyboard.h index d615593..3ad529a 100644 --- a/actions/internal/linux/xcb_keyboard.h +++ b/actions/internal/x11/xcb_keyboard.h @@ -1,5 +1,5 @@ -#ifndef ACTIONS_INTERNAL_LINUX_XCB_KEYBOARD_H -#define ACTIONS_INTERNAL_LINUX_XCB_KEYBOARD_H +#ifndef ACTIONS_INTERNAL_X11_XCB_KEYBOARD_H +#define ACTIONS_INTERNAL_X11_XCB_KEYBOARD_H #include #include @@ -12,7 +12,7 @@ #include "absl/status/statusor.h" #include "actions/action/keystroke.h" -namespace actions::internal::linux { +namespace actions::internal::x11 { class XcbKeyboard { private: @@ -39,6 +39,6 @@ class XcbKeyboard { xcb_window_t root) noexcept; }; -} // namespace actions::internal::linux +} // namespace actions::internal::x11 -#endif // ACTIONS_INTERNAL_LINUX_XCB_KEYBOARD_H \ No newline at end of file +#endif // ACTIONS_INTERNAL_X11_XCB_KEYBOARD_H \ No newline at end of file diff --git a/display/BUILD b/display/BUILD new file mode 100644 index 0000000..9c8c520 --- /dev/null +++ b/display/BUILD @@ -0,0 +1,5 @@ +load("@display//:local_display.bzl", "display_constraints") + +package(default_visibility = ["//visibility:public"]) + +display_constraints(name = "display_constraints") diff --git a/display/display.tpl.BUILD b/display/display.tpl.BUILD new file mode 100644 index 0000000..d40faf6 --- /dev/null +++ b/display/display.tpl.BUILD @@ -0,0 +1,16 @@ +package(default_visibility = ["//visibility:public"]) + +constraint_setting( + name = "display_type", + default_constraint_value = "${default_display_type}", +) + +constraint_value( + name = "unknown", + constraint_setting = ":display_type", +) + +constraint_value( + name = "x11", + constraint_setting = ":display_type", +) diff --git a/display/display_configure.bzl b/display/display_configure.bzl new file mode 100644 index 0000000..2646233 --- /dev/null +++ b/display/display_configure.bzl @@ -0,0 +1,121 @@ +""" +Rules for detecting and setting up display server dependencies +""" + +load("@bazel_skylib//lib:paths.bzl", "paths") + +_x11_install_paths = { + "default": { + "path": "/usr", + "include": "include/X11", + "lib": "lib", + }, +} + +_xcb_install_paths = { + "default": { + "path": "/usr", + "include": "include/xcb", + "lib": "lib", + }, +} + +def x11_install( + name, + path, + include, + lib): + if name in _x11_install_paths: + fail("x11 install with name %s already exists") + + _x11_install_paths[name] = { + "path": path, + "include": include, + "lib": lib, + } + +def xcb_install( + name, + path, + include, + lib): + if name in _xcb_install_paths: + fail("xcb install with name %s already exists") + + _xcb_install_paths[name] = { + "path": path, + "include": include, + "lib": lib, + } + +def _find_x11_install(repository_ctx): + for name, install_paths in _x11_install_paths.items(): + base = install_paths["path"] + + inc_abs = paths.join(base, install_paths["include"]) + lib_abs = paths.join(base, install_paths["lib"]) + + # print(inc_abs) + + if repository_ctx.path(inc_abs).exists and \ + repository_ctx.path(lib_abs).exists: + return True, install_paths + + return False, _x11_install_paths["default"] + +def _find_xcb_install(repository_ctx): + for name, install_paths in _xcb_install_paths.items(): + base = install_paths["path"] + + inc_abs = paths.join(base, install_paths["include"]) + lib_abs = paths.join(base, install_paths["lib"]) + + # print(inc_abs) + + if repository_ctx.path(inc_abs).exists and \ + repository_ctx.path(lib_abs).exists: + return True, install_paths + + return False, _xcb_install_paths["default"] + +def _display_autoconf_impl(repository_ctx): + display_type = "unknown" + + has_x11, local_x11 = _find_x11_install(repository_ctx) + has_xcb, local_xcb = _find_xcb_install(repository_ctx) + + if has_x11 and has_xcb: + display_type = "x11" + else: + print("Failed to detect display server") # buildifier: disable=print + + repository_ctx.file("BUILD", "# empty BUILD file so that bazel sees this as a valid package directory") + repository_ctx.template( + "BUILD", + repository_ctx.path(Label("@actions//display:display.tpl.BUILD")), + { + "${default_display_type}": display_type, + }, + ) + + repository_ctx.template( + "local_display.bzl", + repository_ctx.path(Label("@actions//display:local_display.tpl.bzl")), + { + "${x11_path}": local_x11["path"], + "${x11_include_path}": local_x11["include"], + "${x11_lib_path}": local_x11["lib"], + "${xcb_path}": local_xcb["path"], + "${xcb_include_path}": local_xcb["include"], + "${xcb_lib_path}": local_xcb["lib"], + "${default_display_type}": display_type, + }, + ) + +display_autoconf = repository_rule( + implementation = _display_autoconf_impl, + configure = True, +) + +def display_configure(): + display_autoconf(name = "display") diff --git a/display/local_display.tpl.bzl b/display/local_display.tpl.bzl new file mode 100644 index 0000000..d336593 --- /dev/null +++ b/display/local_display.tpl.bzl @@ -0,0 +1,49 @@ +""" +Local Qt installation helper functions +""" + +# load("@bazel_skylib//lib:paths.bzl", "paths") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") + +def local_x11_path(): + return "${x11_path}" + +def local_x11_include_path(): + return "${x11_include_path}" + +def local_x11_lib_path(): + return "${x11_lib_path}" + +def local_xcb_path(): + return "${xcb_path}" + +def local_xcb_include_path(): + return "${xcb_include_path}" + +def local_xcb_lib_path(): + return "${xcb_lib_path}" + +def display_constraints(name): + native.constraint_setting( + name = "display_type", + default_constraint_value = "${default_display_type}", + ) + + native.constraint_value(name = "unknown", constraint_setting = ":display_type") + + native.constraint_value(name = "x11", constraint_setting = ":display_type") + +def display_repositories(): + maybe( + native.new_local_repository, + name = "X11", + path = local_x11_path(), + build_file = "@actions//third_party:X11.BUILD", + ) + + maybe( + native.new_local_repository, + name = "xcb", + path = local_xcb_path(), + build_file = "@actions//third_party:xcb.BUILD", + ) diff --git a/repositories.bzl b/repositories.bzl index ea5529f..5e4b280 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -22,17 +22,3 @@ def actions_repositories(): strip_prefix = "abseil-cpp-20220623.1", sha256 = "91ac87d30cc6d79f9ab974c51874a704de9c2647c40f6932597329a282217ba8", ) - - maybe( - native.new_local_repository, - name = "xcb", - path = "/usr", - build_file = "@actions//third_party:xcb.BUILD", - ) - - maybe( - native.new_local_repository, - name = "X11", - path = "/usr", - build_file = "@actions//third_party:X11.BUILD", - ) diff --git a/third_party/X11.BUILD b/third_party/X11.BUILD index b4366d2..9b63f23 100644 --- a/third_party/X11.BUILD +++ b/third_party/X11.BUILD @@ -1,14 +1,26 @@ +load("@bazel_skylib//lib:paths.bzl", "paths") +load("@display//:local_display.bzl", "local_x11_include_path", "local_x11_lib_path", "local_x11_path") + cc_library( name = "X11", # buildifier: disable=constant-globs hdrs = glob([ - "include/X11/**/*.h*", + ("%s/**/*.h" % local_x11_include_path()), ]), includes = [ - "include/X11/", - ], - linkopts = [ - "-l:libX11.so", + local_x11_include_path(), ], + linkopts = select({ + "@platforms//os:linux": ["-lX11"], + # TODO: Check that this works on osx + "@platforms//os:osx": [ + ("-F%s" % paths.join( + local_x11_path(), + local_x11_lib_path(), + )), + "-framework X11", + ], + }), + target_compatible_with = ["@display//:x11"], visibility = ["//visibility:public"], ) diff --git a/third_party/xcb.BUILD b/third_party/xcb.BUILD index e85dfbb..38a980a 100644 --- a/third_party/xcb.BUILD +++ b/third_party/xcb.BUILD @@ -1,17 +1,34 @@ +load("@bazel_skylib//lib:paths.bzl", "paths") +load("@display//:local_display.bzl", "local_xcb_include_path", "local_xcb_lib_path", "local_xcb_path") + cc_library( name = "xcb", # buildifier: disable=constant-globs hdrs = glob([ - "include/xcb/**/*.h*", + ("%s/**/*.h" % local_xcb_include_path()), ]), includes = [ - "include/xcb/", - ], - linkopts = [ - "-l:libxcb-keysyms.so", - "-l:libxcb-util.so", - "-l:libxcb-xtest.so", - "-l:libxcb.so", + local_xcb_include_path(), ], + linkopts = select({ + "@platforms//os:linux": [ + "-lxcb", + "-lxcb-keysyms", + "-lxcb-util", + "-lxcb-xtest", + ], + # TODO: Check that this works on osx + "@platforms//os:osx": [ + ("-F%s" % paths.join( + local_xcb_path(), + local_xcb_lib_path(), + )), + "-framework xcb", + "-framework xcb-keysyms", + "-framework xcb-util", + "-framework xcb-xtest", + ], + }), + target_compatible_with = ["@display//:x11"], visibility = ["//visibility:public"], ) From 6c6cf8a0d96e544edfa2fb3967e321e2a65f421f Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Mon, 10 Apr 2023 13:29:34 -0600 Subject: [PATCH 04/10] implement cursor move action --- actions/BUILD | 1 + actions/action.h | 12 ++++- actions/action/BUILD | 5 ++ actions/action/cursor_move.h | 13 +++++ actions/actions.cc | 5 ++ actions/examples/BUILD | 10 ++++ actions/examples/actions_cursor.cc | 30 +++++++++++ actions/internal/connection.h | 4 ++ actions/internal/stub/stub_connection.cc | 6 +++ actions/internal/stub/stub_connection.h | 4 ++ actions/internal/x11/xcb_connection.cc | 66 ++++++++++++++++++++++++ actions/internal/x11/xcb_connection.h | 36 ++++++++++++- 12 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 actions/action/cursor_move.h create mode 100644 actions/examples/actions_cursor.cc diff --git a/actions/BUILD b/actions/BUILD index 1086015..53ddda6 100644 --- a/actions/BUILD +++ b/actions/BUILD @@ -4,6 +4,7 @@ cc_library( name = "action", hdrs = ["action.h"], deps = [ + "//actions/action:cursor_move", "//actions/action:keystroke", "//actions/action:target", "@com_google_absl//absl/types:variant", diff --git a/actions/action.h b/actions/action.h index f02e135..ac0f965 100644 --- a/actions/action.h +++ b/actions/action.h @@ -2,13 +2,21 @@ #define ACTIONS_ACTION_H #include "absl/types/variant.h" +#include "actions/action/cursor_move.h" #include "actions/action/keystroke.h" #include "actions/action/target.h" namespace actions { -using Action = absl::variant; +namespace action { -} +typedef struct NoOp { +} NoOp; +} // namespace action + +using Action = + absl::variant; + +} // namespace actions #endif // ACTIONS_ACTION_H \ No newline at end of file diff --git a/actions/action/BUILD b/actions/action/BUILD index ca7895d..ad725b4 100644 --- a/actions/action/BUILD +++ b/actions/action/BUILD @@ -18,6 +18,11 @@ cc_library( }), ) +cc_library( + name = "cursor_move", + hdrs = ["cursor_move.h"], +) + cc_library( name = "target", hdrs = ["target.h"], diff --git a/actions/action/cursor_move.h b/actions/action/cursor_move.h new file mode 100644 index 0000000..ed3b201 --- /dev/null +++ b/actions/action/cursor_move.h @@ -0,0 +1,13 @@ +#ifndef ACTIONS_ACTION_CURSOR_MOVE_H +#define ACTIONS_ACTION_CURSOR_MOVE_H + +namespace actions::action { + +typedef struct CursorMove { + double x; + double y; +} CursorMove; + +} // namespace actions::action + +#endif // ACTIONS_ACTION_CURSOR_MOVE_H \ No newline at end of file diff --git a/actions/actions.cc b/actions/actions.cc index 85a7586..f19cc98 100644 --- a/actions/actions.cc +++ b/actions/actions.cc @@ -47,8 +47,13 @@ std::future Actions::Perform( if (absl::holds_alternative(action)) { return conn->SendKeystroke(absl::get(action), target); + } else if (absl::holds_alternative(action)) { + return conn->MoveCursor(absl::get(action), target); + } else if (absl::holds_alternative(action)) { + return internal::util::Resolve(absl::OkStatus()); } + // Should be unreachable, but you can never be too careful return internal::util::Resolve( absl::UnimplementedError("Not Implemented.")); } diff --git a/actions/examples/BUILD b/actions/examples/BUILD index 494da05..777507d 100644 --- a/actions/examples/BUILD +++ b/actions/examples/BUILD @@ -10,3 +10,13 @@ cc_binary( "@com_google_absl//absl/status", ], ) + +cc_binary( + name = "actions_cursor", + srcs = ["actions_cursor.cc"], + deps = [ + "//actions", + "//actions:action", + "@com_google_absl//absl/status", + ], +) diff --git a/actions/examples/actions_cursor.cc b/actions/examples/actions_cursor.cc new file mode 100644 index 0000000..e61b4cc --- /dev/null +++ b/actions/examples/actions_cursor.cc @@ -0,0 +1,30 @@ +#include + +#include "absl/status/status.h" +#include "actions/action.h" +#include "actions/actions.h" + +using namespace actions; + +absl::Status run() { + auto actions = Actions::Create(); + + if (!actions.ok()) return actions.status(); + + return actions + ->Perform(action::CursorMove{.x = 0.5, .y = 0.5}, + action::target::Focused()) + .get(); +} + +int main(int argc, char** argv) { + std::cout << "Running Example" << std::endl; + absl::Status status = run(); + + if (!status.ok()) { + std::cout << status << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/actions/internal/connection.h b/actions/internal/connection.h index c96f7cd..ae29d90 100644 --- a/actions/internal/connection.h +++ b/actions/internal/connection.h @@ -21,6 +21,10 @@ class Connection { virtual std::future SendKeystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept = 0; + + virtual std::future MoveCursor( + const action::CursorMove& cursor_move, + const action::Target& target) noexcept = 0; }; } // namespace actions::internal diff --git a/actions/internal/stub/stub_connection.cc b/actions/internal/stub/stub_connection.cc index 0407a12..7833541 100644 --- a/actions/internal/stub/stub_connection.cc +++ b/actions/internal/stub/stub_connection.cc @@ -17,4 +17,10 @@ std::future StubConnection::SendKeystroke( return util::Resolve(absl::OkStatus()); } +std::future StubConnection::MoveCursor( + const action::CursorMove& cursor_move, + const action::Target& target) noexcept { + return util::Resolve(absl::OkStatus()); +} + } // namespace actions::internal::stub \ No newline at end of file diff --git a/actions/internal/stub/stub_connection.h b/actions/internal/stub/stub_connection.h index 460b98c..d972030 100644 --- a/actions/internal/stub/stub_connection.h +++ b/actions/internal/stub/stub_connection.h @@ -15,6 +15,10 @@ class StubConnection : public Connection { std::future SendKeystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept override; + + std::future MoveCursor( + const action::CursorMove& cursor_move, + const action::Target& target) noexcept override; }; } // namespace actions::internal::stub diff --git a/actions/internal/x11/xcb_connection.cc b/actions/internal/x11/xcb_connection.cc index 8177ae8..86ef183 100644 --- a/actions/internal/x11/xcb_connection.cc +++ b/actions/internal/x11/xcb_connection.cc @@ -1,6 +1,7 @@ #include "actions/internal/x11/xcb_connection.h" #include +#include #include #include @@ -109,4 +110,69 @@ std::future XcbConnection::SendKeystroke( return keyboard.SendKeystrokes(keystroke, root); } + +std::future XcbConnection::MoveCursor( + const action::CursorMove& cursor_move, + const action::Target& target) noexcept { + // TODO: get size of window to properly scale coordinates + + xcb_window_t dest_window = screen->root; + + return std::async(std::launch::deferred, [=]() { + auto geometry = GetWindowGeometry(dest_window).get(); + + if (!geometry.ok()) return geometry.status(); + + auto dest_width = geometry.value()->width; + auto dest_height = geometry.value()->height; + + std::cout << "width = " << dest_width << std::endl; + std::cout << "height = " << dest_height << std::endl; + + auto x = cursor_move.x * dest_width; + auto y = cursor_move.y * dest_height; + + xcb_void_cookie_t cookie = xcb_warp_pointer_checked( + conn, XCB_NONE, dest_window, 0, 0, 0, 0, x, y); + + xcb_flush(conn); + + return CheckCookie(cookie).get(); + }); +} + +std::future> +XcbConnection::GetWindowAttributes(xcb_window_t window) { + xcb_get_window_attributes_cookie_t cookie = + xcb_get_window_attributes(conn, window); + + xcb_flush(conn); + + return ResolveReply( + cookie, xcb_get_window_attributes_reply); +} + +std::future> +XcbConnection::GetWindowGeometry(xcb_window_t window) { + xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, window); + + xcb_flush(conn); + + return ResolveReply( + cookie, xcb_get_geometry_reply); +} + +std::future XcbConnection::CheckCookie(xcb_void_cookie_t cookie) { + return std::async(std::launch::deferred, [this, cookie]() { + xcb_generic_error_t* error = xcb_request_check(conn, cookie); + + if (error) { + return XcbErrorToStatus(conn, error); + } + + return absl::OkStatus(); + }); +} + } // namespace actions::internal::x11 \ No newline at end of file diff --git a/actions/internal/x11/xcb_connection.h b/actions/internal/x11/xcb_connection.h index 1f52efb..d496462 100644 --- a/actions/internal/x11/xcb_connection.h +++ b/actions/internal/x11/xcb_connection.h @@ -8,9 +8,12 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "actions/internal/connection.h" +#include "actions/internal/x11/xcb_error.h" #include "actions/internal/x11/xcb_keyboard.h" namespace actions::internal::x11 { +template +using XcbReply = absl::StatusOr; class XcbConnection : public Connection { private: @@ -34,8 +37,39 @@ class XcbConnection : public Connection { std::future SendKeystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept override; -}; + std::future MoveCursor( + const action::CursorMove& cursor_move, + const action::Target& target) noexcept override; + + private: + std::future> + GetWindowAttributes(xcb_window_t window); + + std::future> GetWindowGeometry( + xcb_window_t window); + + template + std::future> ResolveReply( + Cookie cookie, + std::function + reply_getter) { + return std::async(std::launch::deferred, + [this, cookie, reply_getter]() -> XcbReply { + xcb_generic_error_t* error; + + T* reply = reply_getter(conn, cookie, &error); + + if (error) { + return XcbErrorToStatus(conn, error); + } + + return reply; + }); + } + + std::future CheckCookie(xcb_void_cookie_t cookie); +}; } // namespace actions::internal::x11 #endif // ACTIONS_INTERNAL_X11_XCB_CONNECTION_H \ No newline at end of file From 59a281bcec9647350fd0c6c02ba9dc45aa14bcdd Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Mon, 10 Apr 2023 13:44:54 -0600 Subject: [PATCH 05/10] support relative cursor moves --- actions/action/BUILD | 5 +++++ actions/action/cursor_move.h | 1 + actions/examples/actions_cursor.cc | 2 +- actions/internal/x11/xcb_connection.cc | 28 +++++++++++++++++++++----- actions/internal/x11/xcb_connection.h | 2 ++ 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/actions/action/BUILD b/actions/action/BUILD index ad725b4..c16189f 100644 --- a/actions/action/BUILD +++ b/actions/action/BUILD @@ -23,6 +23,11 @@ cc_library( hdrs = ["cursor_move.h"], ) +cc_library( + name = "cursor_move_rel", + hdrs = ["cursor_move.h"], +) + cc_library( name = "target", hdrs = ["target.h"], diff --git a/actions/action/cursor_move.h b/actions/action/cursor_move.h index ed3b201..8f23804 100644 --- a/actions/action/cursor_move.h +++ b/actions/action/cursor_move.h @@ -6,6 +6,7 @@ namespace actions::action { typedef struct CursorMove { double x; double y; + bool relative = true; } CursorMove; } // namespace actions::action diff --git a/actions/examples/actions_cursor.cc b/actions/examples/actions_cursor.cc index e61b4cc..80ca74a 100644 --- a/actions/examples/actions_cursor.cc +++ b/actions/examples/actions_cursor.cc @@ -12,7 +12,7 @@ absl::Status run() { if (!actions.ok()) return actions.status(); return actions - ->Perform(action::CursorMove{.x = 0.5, .y = 0.5}, + ->Perform(action::CursorMove{.x = 0.1, .y = 0.1}, action::target::Focused()) .get(); } diff --git a/actions/internal/x11/xcb_connection.cc b/actions/internal/x11/xcb_connection.cc index 86ef183..7b4f9be 100644 --- a/actions/internal/x11/xcb_connection.cc +++ b/actions/internal/x11/xcb_connection.cc @@ -119,6 +119,18 @@ std::future XcbConnection::MoveCursor( xcb_window_t dest_window = screen->root; return std::async(std::launch::deferred, [=]() { + int16_t src_x = 0; + int16_t src_y = 0; + + if (cursor_move.relative) { + auto pointer_loc = QueryPointer().get(); + + if (!pointer_loc.ok()) return pointer_loc.status(); + + src_x = pointer_loc.value()->root_x; + src_y = pointer_loc.value()->root_y; + } + auto geometry = GetWindowGeometry(dest_window).get(); if (!geometry.ok()) return geometry.status(); @@ -126,11 +138,8 @@ std::future XcbConnection::MoveCursor( auto dest_width = geometry.value()->width; auto dest_height = geometry.value()->height; - std::cout << "width = " << dest_width << std::endl; - std::cout << "height = " << dest_height << std::endl; - - auto x = cursor_move.x * dest_width; - auto y = cursor_move.y * dest_height; + auto x = cursor_move.x * dest_width + src_x; + auto y = cursor_move.y * dest_height + src_y; xcb_void_cookie_t cookie = xcb_warp_pointer_checked( conn, XCB_NONE, dest_window, 0, 0, 0, 0, x, y); @@ -163,6 +172,15 @@ XcbConnection::GetWindowGeometry(xcb_window_t window) { cookie, xcb_get_geometry_reply); } +std::future> XcbConnection::QueryPointer() { + xcb_query_pointer_cookie_t cookie = xcb_query_pointer(conn, screen->root); + + xcb_flush(conn); + + return ResolveReply( + cookie, xcb_query_pointer_reply); +} + std::future XcbConnection::CheckCookie(xcb_void_cookie_t cookie) { return std::async(std::launch::deferred, [this, cookie]() { xcb_generic_error_t* error = xcb_request_check(conn, cookie); diff --git a/actions/internal/x11/xcb_connection.h b/actions/internal/x11/xcb_connection.h index d496462..f31afb0 100644 --- a/actions/internal/x11/xcb_connection.h +++ b/actions/internal/x11/xcb_connection.h @@ -49,6 +49,8 @@ class XcbConnection : public Connection { std::future> GetWindowGeometry( xcb_window_t window); + std::future> QueryPointer(); + template std::future> ResolveReply( Cookie cookie, From 5c9e4c76fc611739eb73b2c657920e8b4ac37b02 Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Mon, 10 Apr 2023 14:34:31 -0600 Subject: [PATCH 06/10] implement mouse button press actions --- actions/BUILD | 2 +- actions/action.h | 5 +- actions/action/BUILD | 9 +- actions/action/mouse.h | 24 +++++ actions/actions.cc | 7 ++ actions/examples/BUILD | 4 +- .../{actions_cursor.cc => actions_mouse.cc} | 10 +- actions/internal/connection.h | 12 +++ actions/internal/stub/stub_connection.cc | 18 ++++ actions/internal/stub/stub_connection.h | 12 +++ actions/internal/x11/xcb_connection.cc | 100 +++++++++++++++++- actions/internal/x11/xcb_connection.h | 19 ++++ 12 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 actions/action/mouse.h rename actions/examples/{actions_cursor.cc => actions_mouse.cc} (60%) diff --git a/actions/BUILD b/actions/BUILD index 53ddda6..2b52470 100644 --- a/actions/BUILD +++ b/actions/BUILD @@ -4,8 +4,8 @@ cc_library( name = "action", hdrs = ["action.h"], deps = [ - "//actions/action:cursor_move", "//actions/action:keystroke", + "//actions/action:mouse", "//actions/action:target", "@com_google_absl//absl/types:variant", ], diff --git a/actions/action.h b/actions/action.h index ac0f965..5f991e7 100644 --- a/actions/action.h +++ b/actions/action.h @@ -2,8 +2,8 @@ #define ACTIONS_ACTION_H #include "absl/types/variant.h" -#include "actions/action/cursor_move.h" #include "actions/action/keystroke.h" +#include "actions/action/mouse.h" #include "actions/action/target.h" namespace actions { @@ -15,7 +15,8 @@ typedef struct NoOp { } // namespace action using Action = - absl::variant; + absl::variant; } // namespace actions diff --git a/actions/action/BUILD b/actions/action/BUILD index c16189f..8d3d2a7 100644 --- a/actions/action/BUILD +++ b/actions/action/BUILD @@ -19,13 +19,8 @@ cc_library( ) cc_library( - name = "cursor_move", - hdrs = ["cursor_move.h"], -) - -cc_library( - name = "cursor_move_rel", - hdrs = ["cursor_move.h"], + name = "mouse", + hdrs = ["mouse.h"], ) cc_library( diff --git a/actions/action/mouse.h b/actions/action/mouse.h new file mode 100644 index 0000000..f155757 --- /dev/null +++ b/actions/action/mouse.h @@ -0,0 +1,24 @@ +#ifndef ACTIONS_ACTION_MOUSE_CLICK_H +#define ACTIONS_ACTION_MOUSE_CLICK_H + +namespace actions::action { + +typedef struct CursorMove { + double x; + double y; + bool relative = true; +} CursorMove; + +typedef enum MouseClick { LeftClick, RightClick, MiddleClick } MouseClick; + +typedef enum MousePress { LeftPress, RightPress, MiddlePress } MousePress; + +typedef enum MouseRelease { + LeftRelease, + RightRelease, + MiddleRelease +} MouseRelease; + +} // namespace actions::action + +#endif // ACTIONS_ACTION_MOUSE_CLICK_H \ No newline at end of file diff --git a/actions/actions.cc b/actions/actions.cc index f19cc98..11bb0d0 100644 --- a/actions/actions.cc +++ b/actions/actions.cc @@ -49,6 +49,13 @@ std::future Actions::Perform( target); } else if (absl::holds_alternative(action)) { return conn->MoveCursor(absl::get(action), target); + } else if (absl::holds_alternative(action)) { + return conn->MousePress(absl::get(action), target); + } else if (absl::holds_alternative(action)) { + return conn->MouseRelease(absl::get(action), + target); + } else if (absl::holds_alternative(action)) { + return conn->MouseClick(absl::get(action), target); } else if (absl::holds_alternative(action)) { return internal::util::Resolve(absl::OkStatus()); } diff --git a/actions/examples/BUILD b/actions/examples/BUILD index 777507d..637034d 100644 --- a/actions/examples/BUILD +++ b/actions/examples/BUILD @@ -12,8 +12,8 @@ cc_binary( ) cc_binary( - name = "actions_cursor", - srcs = ["actions_cursor.cc"], + name = "actions_mouse", + srcs = ["actions_mouse.cc"], deps = [ "//actions", "//actions:action", diff --git a/actions/examples/actions_cursor.cc b/actions/examples/actions_mouse.cc similarity index 60% rename from actions/examples/actions_cursor.cc rename to actions/examples/actions_mouse.cc index 80ca74a..dc4e2a5 100644 --- a/actions/examples/actions_cursor.cc +++ b/actions/examples/actions_mouse.cc @@ -11,9 +11,15 @@ absl::Status run() { if (!actions.ok()) return actions.status(); + absl::Status status = actions + ->Perform(action::CursorMove{.x = 0.1, .y = 0.1}, + action::target::Focused()) + .get(); + + if (!status.ok()) return status; + return actions - ->Perform(action::CursorMove{.x = 0.1, .y = 0.1}, - action::target::Focused()) + ->Perform(action::MouseClick::LeftClick, action::target::Focused()) .get(); } diff --git a/actions/internal/connection.h b/actions/internal/connection.h index ae29d90..5f331c9 100644 --- a/actions/internal/connection.h +++ b/actions/internal/connection.h @@ -25,6 +25,18 @@ class Connection { virtual std::future MoveCursor( const action::CursorMove& cursor_move, const action::Target& target) noexcept = 0; + + virtual std::future MousePress( + const action::MousePress& mouse_press, + const action::Target& target) noexcept = 0; + + virtual std::future MouseRelease( + const action::MouseRelease& mouse_release, + const action::Target& target) noexcept = 0; + + virtual std::future MouseClick( + const action::MouseClick& mouse_click, + const action::Target& target) noexcept = 0; }; } // namespace actions::internal diff --git a/actions/internal/stub/stub_connection.cc b/actions/internal/stub/stub_connection.cc index 7833541..93e3dc2 100644 --- a/actions/internal/stub/stub_connection.cc +++ b/actions/internal/stub/stub_connection.cc @@ -23,4 +23,22 @@ std::future StubConnection::MoveCursor( return util::Resolve(absl::OkStatus()); } +std::future StubConnection::MousePress( + const action::MousePress& mouse_press, + const action::Target& target) noexcept { + return util::Resolve(absl::OkStatus()); +} + +std::future StubConnection::MouseRelease( + const action::MouseRelease& mouse_release, + const action::Target& target) noexcept { + return util::Resolve(absl::OkStatus()); +} + +std::future StubConnection::MouseClick( + const action::MouseClick& mouse_click, + const action::Target& target) noexcept { + return util::Resolve(absl::OkStatus()); +} + } // namespace actions::internal::stub \ No newline at end of file diff --git a/actions/internal/stub/stub_connection.h b/actions/internal/stub/stub_connection.h index d972030..3aca18c 100644 --- a/actions/internal/stub/stub_connection.h +++ b/actions/internal/stub/stub_connection.h @@ -19,6 +19,18 @@ class StubConnection : public Connection { std::future MoveCursor( const action::CursorMove& cursor_move, const action::Target& target) noexcept override; + + std::future MousePress( + const action::MousePress& mouse_press, + const action::Target& target) noexcept override; + + std::future MouseRelease( + const action::MouseRelease& mouse_release, + const action::Target& target) noexcept override; + + std::future MouseClick( + const action::MouseClick& mouse_click, + const action::Target& target) noexcept override; }; } // namespace actions::internal::stub diff --git a/actions/internal/x11/xcb_connection.cc b/actions/internal/x11/xcb_connection.cc index 7b4f9be..56fef54 100644 --- a/actions/internal/x11/xcb_connection.cc +++ b/actions/internal/x11/xcb_connection.cc @@ -116,7 +116,13 @@ std::future XcbConnection::MoveCursor( const action::Target& target) noexcept { // TODO: get size of window to properly scale coordinates - xcb_window_t dest_window = screen->root; + xcb_window_t dest_window; + + if (absl::holds_alternative(target)) { + dest_window = screen->root; + } else { + return util::Resolve(absl::UnimplementedError("Not Implemented.")); + } return std::async(std::launch::deferred, [=]() { int16_t src_x = 0; @@ -150,6 +156,72 @@ std::future XcbConnection::MoveCursor( }); } +std::future XcbConnection::MousePress( + const action::MousePress& mouse_press, + const action::Target& _target) noexcept { + xcb_button_index_t button; + + switch (mouse_press) { + case action::MousePress::LeftPress: + button = XCB_BUTTON_INDEX_1; + break; + case action::MousePress::RightPress: + button = XCB_BUTTON_INDEX_2; + break; + case action::MousePress::MiddlePress: + button = XCB_BUTTON_INDEX_3; + break; + default: + return util::Resolve(absl::UnimplementedError("Not implemented")); + } + + return SendMouseInput(button, true); +} + +std::future XcbConnection::MouseRelease( + const action::MouseRelease& mouse_release, + const action::Target& target) noexcept { + xcb_button_index_t button; + + switch (mouse_release) { + case action::MouseRelease::LeftRelease: + button = XCB_BUTTON_INDEX_1; + break; + case action::MouseRelease::RightRelease: + button = XCB_BUTTON_INDEX_2; + break; + case action::MouseRelease::MiddleRelease: + button = XCB_BUTTON_INDEX_3; + break; + default: + return util::Resolve(absl::UnimplementedError("Not implemented")); + } + + return SendMouseInput(button, false); +} + +std::future XcbConnection::MouseClick( + const action::MouseClick& mouse_click, + const action::Target& target) noexcept { + xcb_button_index_t button; + + switch (mouse_click) { + case action::MouseClick::LeftClick: + button = XCB_BUTTON_INDEX_1; + break; + case action::MouseClick::RightClick: + button = XCB_BUTTON_INDEX_2; + break; + case action::MouseClick::MiddleClick: + button = XCB_BUTTON_INDEX_3; + break; + default: + return util::Resolve(absl::UnimplementedError("Not implemented")); + } + + return SendMouseClick(button); +} + std::future> XcbConnection::GetWindowAttributes(xcb_window_t window) { xcb_get_window_attributes_cookie_t cookie = @@ -181,6 +253,32 @@ std::future> XcbConnection::QueryPointer() { cookie, xcb_query_pointer_reply); } +std::future XcbConnection::SendMouseClick( + xcb_button_index_t button) { + return std::async(std::launch::deferred, [=]() { + auto status = SendMouseInput(button, true).get(); + + if (!status.ok()) return status; + + return SendMouseInput(button, false).get(); + }); +} + +std::future XcbConnection::SendMouseInput( + xcb_button_index_t button, bool press) { + return SendFakeInput(press ? XCB_BUTTON_PRESS : XCB_BUTTON_RELEASE, button); +} + +std::future XcbConnection::SendFakeInput(uint8_t type, + uint8_t detail) { + xcb_void_cookie_t cookie = xcb_test_fake_input_checked( + conn, type, detail, 0, screen->root, 0, 0, 0); + + xcb_flush(conn); + + return CheckCookie(cookie); +} + std::future XcbConnection::CheckCookie(xcb_void_cookie_t cookie) { return std::async(std::launch::deferred, [this, cookie]() { xcb_generic_error_t* error = xcb_request_check(conn, cookie); diff --git a/actions/internal/x11/xcb_connection.h b/actions/internal/x11/xcb_connection.h index f31afb0..cad70aa 100644 --- a/actions/internal/x11/xcb_connection.h +++ b/actions/internal/x11/xcb_connection.h @@ -42,6 +42,18 @@ class XcbConnection : public Connection { const action::CursorMove& cursor_move, const action::Target& target) noexcept override; + std::future MousePress( + const action::MousePress& mouse_press, + const action::Target& target) noexcept override; + + std::future MouseRelease( + const action::MouseRelease& mouse_release, + const action::Target& target) noexcept override; + + std::future MouseClick( + const action::MouseClick& mouse_click, + const action::Target& target) noexcept override; + private: std::future> GetWindowAttributes(xcb_window_t window); @@ -70,6 +82,13 @@ class XcbConnection : public Connection { }); } + std::future SendMouseClick(xcb_button_index_t button); + + std::future SendMouseInput(xcb_button_index_t button, + bool press); + + std::future SendFakeInput(uint8_t type, uint8_t detail); + std::future CheckCookie(xcb_void_cookie_t cookie); }; } // namespace actions::internal::x11 From 0ebf1618b218219013431fe498a117ef554aa505 Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Mon, 10 Apr 2023 15:18:40 -0600 Subject: [PATCH 07/10] implement key press and key release --- actions/action.h | 5 +- actions/action/cursor_move.h | 14 ------ actions/action/keystroke.h | 14 +++++- actions/action/mouse.h | 4 +- actions/actions.cc | 8 +++- actions/examples/BUILD | 10 ++++ actions/examples/actions_hybrid.cc | 61 ++++++++++++++++++++++++ actions/examples/actions_keystroke.cc | 9 ++-- actions/internal/connection.h | 10 +++- actions/internal/stub/stub_connection.cc | 14 +++++- actions/internal/stub/stub_connection.h | 10 +++- actions/internal/x11/xcb_connection.cc | 32 ++++++++++++- actions/internal/x11/xcb_connection.h | 10 +++- actions/internal/x11/xcb_keyboard.cc | 47 ++++++++++++++++-- actions/internal/x11/xcb_keyboard.h | 32 +++++++++---- 15 files changed, 238 insertions(+), 42 deletions(-) delete mode 100644 actions/action/cursor_move.h create mode 100644 actions/examples/actions_hybrid.cc diff --git a/actions/action.h b/actions/action.h index 5f991e7..ad37579 100644 --- a/actions/action.h +++ b/actions/action.h @@ -15,8 +15,9 @@ typedef struct NoOp { } // namespace action using Action = - absl::variant; + absl::variant; } // namespace actions diff --git a/actions/action/cursor_move.h b/actions/action/cursor_move.h deleted file mode 100644 index 8f23804..0000000 --- a/actions/action/cursor_move.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ACTIONS_ACTION_CURSOR_MOVE_H -#define ACTIONS_ACTION_CURSOR_MOVE_H - -namespace actions::action { - -typedef struct CursorMove { - double x; - double y; - bool relative = true; -} CursorMove; - -} // namespace actions::action - -#endif // ACTIONS_ACTION_CURSOR_MOVE_H \ No newline at end of file diff --git a/actions/action/keystroke.h b/actions/action/keystroke.h index e632a19..655a1a9 100644 --- a/actions/action/keystroke.h +++ b/actions/action/keystroke.h @@ -23,7 +23,19 @@ absl::StatusOr > ParseKeystroke(std::string) noexcept; /// @brief Represents a keystroke. A collection of keys with associated /// modifiers. -using Keystroke = std::vector; +using KeySequence = std::vector; + +typedef struct Keystroke { + KeySequence sequence; +} Keystroke; + +typedef struct KeysPress { + KeySequence sequence; +} KeysPress; + +typedef struct KeysRelease { + KeySequence sequence; +} KeysRelease; } // namespace actions::action diff --git a/actions/action/mouse.h b/actions/action/mouse.h index f155757..4dddf31 100644 --- a/actions/action/mouse.h +++ b/actions/action/mouse.h @@ -4,8 +4,8 @@ namespace actions::action { typedef struct CursorMove { - double x; - double y; + double x = 0; + double y = 0; bool relative = true; } CursorMove; diff --git a/actions/actions.cc b/actions/actions.cc index 11bb0d0..844499e 100644 --- a/actions/actions.cc +++ b/actions/actions.cc @@ -45,8 +45,12 @@ Actions& Actions::operator=(Actions&& other) noexcept { std::future Actions::Perform( const Action& action, const action::Target& target) noexcept { if (absl::holds_alternative(action)) { - return conn->SendKeystroke(absl::get(action), - target); + return conn->Keystroke(absl::get(action), target); + } else if (absl::holds_alternative(action)) { + return conn->KeysPress(absl::get(action), target); + } else if (absl::holds_alternative(action)) { + return conn->KeysRelease(absl::get(action), + target); } else if (absl::holds_alternative(action)) { return conn->MoveCursor(absl::get(action), target); } else if (absl::holds_alternative(action)) { diff --git a/actions/examples/BUILD b/actions/examples/BUILD index 637034d..ae34a20 100644 --- a/actions/examples/BUILD +++ b/actions/examples/BUILD @@ -20,3 +20,13 @@ cc_binary( "@com_google_absl//absl/status", ], ) + +cc_binary( + name = "actions_hybrid", + srcs = ["actions_hybrid.cc"], + deps = [ + "//actions", + "//actions:action", + "@com_google_absl//absl/status", + ], +) diff --git a/actions/examples/actions_hybrid.cc b/actions/examples/actions_hybrid.cc new file mode 100644 index 0000000..8bec533 --- /dev/null +++ b/actions/examples/actions_hybrid.cc @@ -0,0 +1,61 @@ +#include + +#include "absl/status/status.h" +#include "actions/action.h" +#include "actions/actions.h" + +using namespace actions; + +absl::Status run() { + auto keysequence = action::ParseKeystroke("shift"); + + if (!keysequence.ok()) return keysequence.status(); + + auto actions = Actions::Create(); + + if (!actions.ok()) return actions.status(); + + absl::Status status = actions + ->Perform(action::KeysPress{keysequence.value()}, + action::target::Focused()) + .get(); + + if (!status.ok()) return status; + + status = + actions + ->Perform(action::MousePress::LeftPress, action::target::Focused()) + .get(); + + if (!status.ok()) return status; + + status = actions + ->Perform(action::CursorMove{.x = 0.1, .y = 0}, + action::target::Focused()) + .get(); + + if (!status.ok()) return status; + + status = actions + ->Perform(action::KeysRelease{keysequence.value()}, + action::target::Focused()) + .get(); + + if (!status.ok()) return status; + + return actions + ->Perform(action::MouseRelease::LeftRelease, action::target::Focused()) + .get(); +} + +int main(int argc, char** argv) { + std::cout << "Running Example" << std::endl; + absl::Status status = run(); + + if (!status.ok()) { + std::cout << status << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/actions/examples/actions_keystroke.cc b/actions/examples/actions_keystroke.cc index 52a737d..30b066a 100644 --- a/actions/examples/actions_keystroke.cc +++ b/actions/examples/actions_keystroke.cc @@ -15,11 +15,14 @@ absl::Status run() { if (!actions.ok()) return actions.status(); - auto keystroke = action::ParseKeystroke(FLAGS_keystroke.CurrentValue()); + auto keysequence = action::ParseKeystroke(FLAGS_keystroke.CurrentValue()); - if (!keystroke.ok()) return keystroke.status(); + if (!keysequence.ok()) return keysequence.status(); - return actions->Perform(keystroke.value(), action::target::Focused()).get(); + return actions + ->Perform(action::Keystroke{keysequence.value()}, + action::target::Focused()) + .get(); } int main(int argc, char** argv) { diff --git a/actions/internal/connection.h b/actions/internal/connection.h index 5f331c9..dc31ec1 100644 --- a/actions/internal/connection.h +++ b/actions/internal/connection.h @@ -18,10 +18,18 @@ class Connection { /// @param target The target of the keystroke. /// @return A future which resolves to an ok status if the keystroke was /// successfully sent, or an error status otherwise. - virtual std::future SendKeystroke( + virtual std::future Keystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept = 0; + virtual std::future KeysPress( + const action::KeysPress& keys_press, + const action::Target& target) noexcept = 0; + + virtual std::future KeysRelease( + const action::KeysRelease& keys_release, + const action::Target& target) noexcept = 0; + virtual std::future MoveCursor( const action::CursorMove& cursor_move, const action::Target& target) noexcept = 0; diff --git a/actions/internal/stub/stub_connection.cc b/actions/internal/stub/stub_connection.cc index 93e3dc2..60db587 100644 --- a/actions/internal/stub/stub_connection.cc +++ b/actions/internal/stub/stub_connection.cc @@ -12,11 +12,23 @@ StubConnection::Create() noexcept { return std::make_unique(); } -std::future StubConnection::SendKeystroke( +std::future StubConnection::Keystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept { return util::Resolve(absl::OkStatus()); } +std::future StubConnection::KeysPress( + const action::KeysPress& keys_press, + const action::Target& target) noexcept { + return util::Resolve(absl::OkStatus()); +} + +std::future StubConnection::KeysRelease( + const action::KeysRelease& keys_release, + const action::Target& target) noexcept { + return util::Resolve(absl::OkStatus()); +} + std::future StubConnection::MoveCursor( const action::CursorMove& cursor_move, const action::Target& target) noexcept { diff --git a/actions/internal/stub/stub_connection.h b/actions/internal/stub/stub_connection.h index 3aca18c..a864da1 100644 --- a/actions/internal/stub/stub_connection.h +++ b/actions/internal/stub/stub_connection.h @@ -12,10 +12,18 @@ class StubConnection : public Connection { public: static absl::StatusOr> Create() noexcept; - std::future SendKeystroke( + std::future Keystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept override; + std::future KeysPress( + const action::KeysPress& keys_press, + const action::Target& target) noexcept override; + + std::future KeysRelease( + const action::KeysRelease& keys_release, + const action::Target& target) noexcept override; + std::future MoveCursor( const action::CursorMove& cursor_move, const action::Target& target) noexcept override; diff --git a/actions/internal/x11/xcb_connection.cc b/actions/internal/x11/xcb_connection.cc index 56fef54..eca2d4a 100644 --- a/actions/internal/x11/xcb_connection.cc +++ b/actions/internal/x11/xcb_connection.cc @@ -98,7 +98,7 @@ XcbConnection& XcbConnection::operator=(XcbConnection&& other) noexcept { return *this; } -std::future XcbConnection::SendKeystroke( +std::future XcbConnection::Keystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept { xcb_window_t root; @@ -108,7 +108,35 @@ std::future XcbConnection::SendKeystroke( return util::Resolve(absl::UnimplementedError("Not Implemented.")); } - return keyboard.SendKeystrokes(keystroke, root); + return keyboard.Keystroke(keystroke, root); +} + +std::future XcbConnection::KeysPress( + const action::KeysPress& keys_press, + const action::Target& target) noexcept { + xcb_window_t root; + + if (absl::holds_alternative(target)) { + root = screen->root; + } else { + return util::Resolve(absl::UnimplementedError("Not Implemented.")); + } + + return keyboard.KeysPress(keys_press, root); +} + +std::future XcbConnection::KeysRelease( + const action::KeysRelease& keys_release, + const action::Target& target) noexcept { + xcb_window_t root; + + if (absl::holds_alternative(target)) { + root = screen->root; + } else { + return util::Resolve(absl::UnimplementedError("Not Implemented.")); + } + + return keyboard.KeysRelease(keys_release, root); } std::future XcbConnection::MoveCursor( diff --git a/actions/internal/x11/xcb_connection.h b/actions/internal/x11/xcb_connection.h index cad70aa..5ef26a9 100644 --- a/actions/internal/x11/xcb_connection.h +++ b/actions/internal/x11/xcb_connection.h @@ -34,10 +34,18 @@ class XcbConnection : public Connection { XcbConnection(XcbConnection&&) noexcept; XcbConnection& operator=(XcbConnection&&) noexcept; - std::future SendKeystroke( + std::future Keystroke( const action::Keystroke& keystroke, const action::Target& target) noexcept override; + std::future KeysPress( + const action::KeysPress& keys_press, + const action::Target& target) noexcept override; + + std::future KeysRelease( + const action::KeysRelease& keys_release, + const action::Target& target) noexcept override; + std::future MoveCursor( const action::CursorMove& cursor_move, const action::Target& target) noexcept override; diff --git a/actions/internal/x11/xcb_keyboard.cc b/actions/internal/x11/xcb_keyboard.cc index 74465ef..c31ef20 100644 --- a/actions/internal/x11/xcb_keyboard.cc +++ b/actions/internal/x11/xcb_keyboard.cc @@ -41,16 +41,55 @@ XcbKeyboard& XcbKeyboard::operator=(XcbKeyboard&& other) noexcept { return *this; } -std::future XcbKeyboard::SendKeystrokes( +std::future XcbKeyboard::Keystroke( const action::Keystroke& keystroke, xcb_window_t root) noexcept { + return SendKeysClick(keystroke.sequence, root); +} + +std::future XcbKeyboard::KeysPress( + const action::KeysPress& keys_press, xcb_window_t root) noexcept { + return SendKeysPress(keys_press.sequence, root); +} + +std::future XcbKeyboard::KeysRelease( + const action::KeysRelease& keys_release, xcb_window_t root) noexcept { + return SendKeysRelease(keys_release.sequence, root); +} + +std::future XcbKeyboard::SendKeysClick( + const action::KeySequence& keysequence, xcb_window_t root) noexcept { std::vector> futures; - futures.reserve(keystroke.size() * 2); + futures.reserve(keysequence.size()); - for (xcb_keysym_t key : keystroke) { + for (xcb_keysym_t key : keysequence) { futures.push_back(SendKey(true, key, root)); } - for (xcb_keysym_t key : keystroke) { + for (xcb_keysym_t key : keysequence) { + futures.push_back(SendKey(false, key, root)); + } + + return util::AllOk(std::move(futures)); +} + +std::future XcbKeyboard::SendKeysPress( + const action::KeySequence& keysequence, xcb_window_t root) noexcept { + std::vector> futures; + futures.reserve(keysequence.size()); + + for (xcb_keysym_t key : keysequence) { + futures.push_back(SendKey(false, key, root)); + } + + return util::AllOk(std::move(futures)); +} + +std::future XcbKeyboard::SendKeysRelease( + const action::KeySequence& keysequence, xcb_window_t root) noexcept { + std::vector> futures; + futures.reserve(keysequence.size()); + + for (xcb_keysym_t key : keysequence) { futures.push_back(SendKey(false, key, root)); } diff --git a/actions/internal/x11/xcb_keyboard.h b/actions/internal/x11/xcb_keyboard.h index 3ad529a..934a757 100644 --- a/actions/internal/x11/xcb_keyboard.h +++ b/actions/internal/x11/xcb_keyboard.h @@ -19,12 +19,6 @@ class XcbKeyboard { xcb_connection_t* conn; xcb_key_symbols_t* key_symbols; - std::future SendKey(bool press, xcb_keysym_t key, - xcb_window_t root) noexcept; - - std::future SendFakeInput(uint8_t type, uint8_t detail, - xcb_window_t root) noexcept; - public: XcbKeyboard(xcb_connection_t* conn) noexcept; ~XcbKeyboard() noexcept; @@ -35,8 +29,30 @@ class XcbKeyboard { XcbKeyboard(XcbKeyboard&&) noexcept; XcbKeyboard& operator=(XcbKeyboard&&) noexcept; - std::future SendKeystrokes(const action::Keystroke& keystroke, - xcb_window_t root) noexcept; + std::future Keystroke(const action::Keystroke& keystroke, + xcb_window_t root) noexcept; + + std::future KeysPress(const action::KeysPress& keys_press, + xcb_window_t root) noexcept; + + std::future KeysRelease( + const action::KeysRelease& keys_release, xcb_window_t root) noexcept; + + private: + std::future SendKeysClick( + const action::KeySequence& keysequence, xcb_window_t root) noexcept; + + std::future SendKeysPress( + const action::KeySequence& keysequence, xcb_window_t root) noexcept; + + std::future SendKeysRelease( + const action::KeySequence& keysequence, xcb_window_t root) noexcept; + + std::future SendKey(bool press, xcb_keysym_t key, + xcb_window_t root) noexcept; + + std::future SendFakeInput(uint8_t type, uint8_t detail, + xcb_window_t root) noexcept; }; } // namespace actions::internal::x11 From 795b8785b7d8ef0b79cea68e66ca9f020af9ece8 Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Mon, 10 Apr 2023 15:21:58 -0600 Subject: [PATCH 08/10] add paths for xquartz --- display/display_configure.bzl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/display/display_configure.bzl b/display/display_configure.bzl index 2646233..777e860 100644 --- a/display/display_configure.bzl +++ b/display/display_configure.bzl @@ -10,6 +10,11 @@ _x11_install_paths = { "include": "include/X11", "lib": "lib", }, + "xquartz": { + "path": "/usr/X11", + "include": "include", + "lib": "lib", + }, } _xcb_install_paths = { @@ -18,6 +23,11 @@ _xcb_install_paths = { "include": "include/xcb", "lib": "lib", }, + "xquartz": { + "path": "/usr/xcb", + "include": "include", + "lib": "lib", + }, } def x11_install( From 2fe5c019df8bec0f873980dc1eac19dcfc6da83e Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Wed, 12 Apr 2023 15:35:56 -0600 Subject: [PATCH 09/10] add some new key mapping to parser --- actions/internal/x11/keystroke.cc | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/actions/internal/x11/keystroke.cc b/actions/internal/x11/keystroke.cc index fbad54b..b334a6f 100644 --- a/actions/internal/x11/keystroke.cc +++ b/actions/internal/x11/keystroke.cc @@ -19,27 +19,34 @@ const static std::map symbol_map{ { "return", "Return", - }}; + }, + {"pgup", "Page_Up"}, + {"pgdown", "Page_Down"}}; absl::StatusOr> ParseKeystroke(std::string str) noexcept { std::stringstream ss(std::move(str)); std::string s; std::vector keys; - while (std::getline(ss, str, '+')) { - // std::transform(str.begin(), str.end(), str.begin(), ::toupper); + while (std::getline(ss, str, ',')) { + std::stringstream ss2(std::move(str)); + while (std::getline(ss2, str, '+')) { + std::string lookup_str = str; + std::transform(lookup_str.begin(), lookup_str.end(), + lookup_str.begin(), ::tolower); - auto it = symbol_map.find(str); + auto it = symbol_map.find(lookup_str); - if (it != symbol_map.end()) str = it->second; + if (it != symbol_map.end()) str = it->second; - KeySym sym = XStringToKeysym(str.c_str()); + KeySym sym = XStringToKeysym(str.c_str()); - if (sym == NoSymbol) { - return absl::InvalidArgumentError("Unrecognized key: " + str); - } + if (sym == NoSymbol) { + return absl::InvalidArgumentError("Unrecognized key: " + str); + } - keys.push_back(sym); + keys.push_back(sym); + } } return keys; From 9462658062b074dbafac8e48c7f639417ea65bfc Mon Sep 17 00:00:00 2001 From: Carson Storm Date: Fri, 14 Apr 2023 14:10:07 -0600 Subject: [PATCH 10/10] add more key mappings --- actions/internal/x11/keystroke.cc | 50 +++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/actions/internal/x11/keystroke.cc b/actions/internal/x11/keystroke.cc index b334a6f..b3a74f2 100644 --- a/actions/internal/x11/keystroke.cc +++ b/actions/internal/x11/keystroke.cc @@ -21,7 +21,47 @@ const static std::map symbol_map{ "Return", }, {"pgup", "Page_Up"}, - {"pgdown", "Page_Down"}}; + {"pgdown", "Page_Down"}, + {"backspace", "BackSpace"}, + {"capslock", "Caps_Lock"}, + {"space", "space"}, + {"!", "exclam"}, + {"@", "at"}, + {"#", "numbersign"}, + {"$", "dollar"}, + {"%", "percent"}, + {"^", "caret"}, + {"&", "ampersand"}, + {"*", "asterisk"}, + {"(", "parenleft"}, + {")", "parenright"}, + {"-", "minus"}, + {"=", "equal"}, + {"_", "underscore"}, + {"+", "plus"}, + {"[", "bracketleft"}, + {"]", "bracketright"}, + {"{", "braceleft"}, + {"}", "braceright"}, + {"|", "bar"}, + {"\\", "backslash"}, + {".", "period"}, + {"<", "less"}, + {">", "greater"}, + {"?", "question"}, + {";", "semicolon"}, + {":", "colon"}, + {",", "comma"}, + {"\"", "quoteright"}, + {"'", "apostrophe"}, + {"/", "slash"}, + {"~", "asciitilde"}, + {"`", "grave"}, + {"scrolllock", "Scroll_Lock"}, + {"ins", "Insert"}, + {"del", "Delete"}, + {"numlock", "Num_Lock"}, +}; absl::StatusOr> ParseKeystroke(std::string str) noexcept { std::stringstream ss(std::move(str)); @@ -31,6 +71,11 @@ absl::StatusOr> ParseKeystroke(std::string str) noexcept { while (std::getline(ss, str, ',')) { std::stringstream ss2(std::move(str)); while (std::getline(ss2, str, '+')) { + str.erase(std::remove_if(str.begin(), str.end(), ::isspace), + str.end()); + + if (str == "") continue; + std::string lookup_str = str; std::transform(lookup_str.begin(), lookup_str.end(), lookup_str.begin(), ::tolower); @@ -42,7 +87,8 @@ absl::StatusOr> ParseKeystroke(std::string str) noexcept { KeySym sym = XStringToKeysym(str.c_str()); if (sym == NoSymbol) { - return absl::InvalidArgumentError("Unrecognized key: " + str); + return absl::InvalidArgumentError("Unrecognized key: \"" + str + + "\""); } keys.push_back(sym);