packages feed

kmonad-0.4.2: c_src/mac/dext.cpp

#include "keyio_mac.hpp"

#include "virtual_hid_device_driver.hpp"
#include "virtual_hid_device_service.hpp"

/*
 * Resources needed to post altered key events back to the OS. They
 * are global so that they can be kept track of in the C++ code rather
 * than in the Haskell.
 */
static pqrs::karabiner::driverkit::virtual_hid_device_service::client *client;
static pqrs::karabiner::driverkit::virtual_hid_device_driver::hid_report::keyboard_input keyboard;
static pqrs::karabiner::driverkit::virtual_hid_device_driver::hid_report::apple_vendor_top_case_input top_case;
static pqrs::karabiner::driverkit::virtual_hid_device_driver::hid_report::apple_vendor_keyboard_input apple_keyboard;
static pqrs::karabiner::driverkit::virtual_hid_device_driver::hid_report::consumer_input consumer;

int init_sink() {
    pqrs::dispatcher::extra::initialize_shared_dispatcher();
    std::filesystem::path client_socket_file_path("/tmp/karabiner_driverkit_virtual_hid_device_service_client.sock");
    client = new pqrs::karabiner::driverkit::virtual_hid_device_service::client(client_socket_file_path);
    auto copy = client;
    client->async_driver_loaded();
    client->async_driver_version_matched();
    client->async_virtual_hid_keyboard_ready();
    client->async_virtual_hid_pointing_ready();
    /**/
    client->connected.connect([copy] {
                                  std::cout << "connected" << std::endl;
                                  copy->async_virtual_hid_keyboard_initialize(pqrs::hid::country_code::us);
                              });
    client->connect_failed.connect([](auto&& error_code) {
                                       std::cout << "connect_failed " << error_code << std::endl;
                                   });
    client->closed.connect([] {
                               std::cout << "closed" << std::endl;
                           });
    client->error_occurred.connect([](auto&& error_code) {
                                       std::cout << "error_occurred " << error_code << std::endl;
                                   });
    client->driver_loaded_response.connect([](auto&& driver_loaded) {
                                               static std::optional<bool> previous_value;

                                               if (previous_value != driver_loaded) {
                                                   std::cout << "driver_loaded " << driver_loaded << std::endl;
                                                   previous_value = driver_loaded;
                                               }
                                           });
    client->driver_version_matched_response.connect([](auto&& driver_version_matched) {
                                                        static std::optional<bool> previous_value;
                                                        if (previous_value != driver_version_matched) {
                                                            std::cout << "driver_version_matched " << driver_version_matched << std::endl;
                                                            previous_value = driver_version_matched;
                                                        }
                                                    });
    /**/
    client->async_start();
    return 0;
}

int exit_sink() {
    free(client);
    pqrs::dispatcher::extra::terminate_shared_dispatcher();
    return 0;
}

/*
 * This gets us some code reuse (see the send_key overload below)
 */
template<typename T>
int send_key(T &keyboard, struct KeyEvent *e) {
    if(e->type == 1) keyboard.keys.insert(e->usage);
    else if(e->type == 0) keyboard.keys.erase(e->usage);
    else return 1;
    client->async_post_report(keyboard);
    return 0;
}


/*
 * Haskell calls this with a new key event to send back to the OS. It
 * posts the information to the karabiner kernel extension (which
 * represents a virtual keyboard).
 */
extern "C" int send_key(struct KeyEvent *e) {
    auto usage_page = pqrs::hid::usage_page::value_t(e->page);
    if(usage_page == pqrs::hid::usage_page::keyboard_or_keypad)
        return send_key(keyboard, e);
    else if(usage_page == pqrs::hid::usage_page::apple_vendor_top_case)
        return send_key(top_case, e);
    else if(usage_page == pqrs::hid::usage_page::apple_vendor_keyboard)
        return send_key(apple_keyboard, e);
    else if(usage_page == pqrs::hid::usage_page::consumer)
        return send_key(consumer, e);
    else
        return 1;
}