/
dext.cpp
94 lines (84 loc) · 4.2 KB
/
dext.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <filesystem> // Include this before virtual_hid_device_service.hpp to avoid compile error
#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();
client = new pqrs::karabiner::driverkit::virtual_hid_device_service::client();
auto copy = client;
/**/
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_connected.connect([](auto&& driver_connected) {
static std::optional<bool> previous_value;
if (previous_value != driver_connected) {
std::cout << "driver_connected " << driver_connected << std::endl;
previous_value = driver_connected;
}
});
client->driver_version_mismatched.connect([](auto&& driver_version_mismatched) {
static std::optional<bool> previous_value;
if (previous_value != driver_version_mismatched) {
std::cout << "driver_version_mismatched " << driver_version_mismatched << std::endl;
previous_value = driver_version_mismatched;
}
});
/**/
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;
}