-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBatcher.cpp
More file actions
85 lines (81 loc) · 2.62 KB
/
Batcher.cpp
File metadata and controls
85 lines (81 loc) · 2.62 KB
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
// Batcher.cpp
// Worker thread that batches and sends keystroke data through IPC.
#include "Batcher.h"
#include <sstream>
// Escapes a string for JSON inclusion
static std::string Escape(const std::string &s)
{
std::string o;
o.reserve(s.size() + 4);
for (char c : s)
{
switch (c)
{
case '"':
o += "\\\"";
break;
case '\\':
o += "\\\\";
break;
case '\n':
o += "\\n";
break;
case '\r':
o += "\\r";
break;
case '\t':
o += "\\t";
break;
default:
o += c;
}
}
return o;
}
// Starts the batcher thread
void Batcher::Start()
{
if (_run.exchange(true))
return;
_t = std::thread([this]
{
std::vector<KeystrokeEvent> batch; batch.reserve(32);
while (_run.load()) {
// drain up to 32 events
KeystrokeEvent ev;
batch.clear();
for (int i=0; i<32 && _q.try_pop(ev); ++i) batch.push_back(ev);
if (!batch.empty()) {
std::ostringstream oss;
oss << R"({"schema":1,"events":[)";
for (size_t i=0; i<batch.size(); ++i) {
const auto& e = batch[i];
oss << R"({"t":")" << (e.type==KeystrokeEvent::Type::Down?"down":e.type==KeystrokeEvent::Type::Up?"up":"char") << R"(",)"
<< R"("vk":)" << e.vk << ','
<< R"("text":")" << (e.ch ? Escape(std::string{ static_cast<char>(e.ch) }) : "") << R"(",)"
<< R"("mods":[)" << (e.mods[0]?"\"Ctrl\"":"")
<< ((e.mods[0]&&e.mods[1])?",":"")
<< (e.mods[1]?"\"Alt\"":"")
<< (((e.mods[0]||e.mods[1])&&e.mods[2])?",":"")
<< (e.mods[2]?"\"Shift\"":"")
<< (((e.mods[0]||e.mods[1]||e.mods[2])&&e.mods[3])?",":"")
<< (e.mods[3]?"\"Win\"":"")
<< R"(],)"
<< R"("ts":)" << (e.ts_micros/1'000'000.0)
<< "}";
if (i+1<batch.size()) oss << ",";
}
oss << "]}";
_pipe.EnsureClient();
_pipe.SendFrame(oss.str());
}
Sleep(8); // ~120Hz batching
} });
}
void Batcher::Stop()
{
if (!_run.exchange(false))
return;
if (_t.joinable())
_t.join();
}