1 |
// Steering Wheel Remote |
2 |
// |
3 |
// Douglas Thrift |
4 |
// |
5 |
// $Id$ |
6 |
|
7 |
#include <cassert> |
8 |
#include <iostream> |
9 |
|
10 |
#include <fcntl.h> |
11 |
|
12 |
#include <posix.hpp> |
13 |
#include <regex.hpp> |
14 |
#include <truck.hpp> |
15 |
#include <vector.hpp> |
16 |
|
17 |
#include <Audacious.hpp> |
18 |
|
19 |
bool debug(false); |
20 |
|
21 |
enum Button |
22 |
{ |
23 |
None = 000, |
24 |
PlayPause = 001, |
25 |
VolumeUp = 002, |
26 |
VolumeDown = 004, |
27 |
Next = 010, |
28 |
Previous = 020 |
29 |
}; |
30 |
|
31 |
const _V<Button> buttons(PlayPause, VolumeUp, VolumeDown, Next, Previous); |
32 |
|
33 |
inline std::ostream &operator<<(std::ostream &output, Button button) |
34 |
{ |
35 |
switch (button) |
36 |
{ |
37 |
case None: |
38 |
return output << _B("None"); |
39 |
case PlayPause: |
40 |
return output << _B("PlayPause"); |
41 |
case Previous: |
42 |
return output << _B("Previous"); |
43 |
case Next: |
44 |
return output << _B("Next"); |
45 |
case VolumeDown: |
46 |
return output << _B("VolumeDown"); |
47 |
case VolumeUp: |
48 |
return output << _B("VolumeUp"); |
49 |
default: |
50 |
return output << _B("Unknown"); |
51 |
} |
52 |
} |
53 |
|
54 |
class Buttons |
55 |
{ |
56 |
uint8_t current, previous; |
57 |
_L<Button> events; |
58 |
|
59 |
inline bool Pressed(Button button, bool current_ = true) const |
60 |
{ |
61 |
return ((current_ ? current : previous) & button) == button; |
62 |
} |
63 |
|
64 |
public: |
65 |
Buttons() : current(0) {} |
66 |
|
67 |
inline const _L<Button> &Events() const |
68 |
{ |
69 |
return events; |
70 |
} |
71 |
|
72 |
inline const _L<Button> &Events(uint8_t bytes[8]) |
73 |
{ |
74 |
if (debug) |
75 |
{ |
76 |
assert (bytes[0] == 3); |
77 |
assert (bytes[1] == 2); |
78 |
assert (bytes[2] == 0); |
79 |
assert (bytes[3] == -(bytes[4] - 0373)); |
80 |
assert (bytes[5] == 0); |
81 |
assert (bytes[6] == 0); |
82 |
assert (bytes[7] == 0); |
83 |
} |
84 |
|
85 |
previous = current; |
86 |
current = bytes[3]; |
87 |
|
88 |
events.clear(); |
89 |
|
90 |
_foreach (const _V<Button>, button, buttons) |
91 |
if (Pressed(*button, false) && !Pressed(*button)) |
92 |
events.push_back(*button); |
93 |
|
94 |
return events; |
95 |
} |
96 |
|
97 |
template <Button button> |
98 |
inline bool Pressed() |
99 |
{ |
100 |
return Pressed(button); |
101 |
} |
102 |
}; |
103 |
|
104 |
int main(int argc, char *argv[]) |
105 |
{ |
106 |
std::string device; |
107 |
|
108 |
{ |
109 |
Pcre::RegEx devicePath(_B("^-device=(/.+)$")); |
110 |
Pcre::RegEx deviceNumber(_B("^-device=([0-9]+)$")); |
111 |
Pcre::RegEx deviceName(_B("^-device=(.+)$")); |
112 |
|
113 |
for (char **arg = argv + 1; *arg; ++arg) |
114 |
{ |
115 |
Pcre::RegEx::Match match; |
116 |
|
117 |
if (*arg == _B("-debug")) |
118 |
debug = true; |
119 |
else if (match = devicePath(*arg)) |
120 |
device = match[1]; |
121 |
else if (match = deviceNumber(*arg)) |
122 |
device = _B("/dev/uhid") + match[1]; |
123 |
else if (match = deviceName(*arg)) |
124 |
device = _B("/dev/") + match[1]; |
125 |
else |
126 |
goto usage; |
127 |
} |
128 |
} |
129 |
|
130 |
if (device.empty()) |
131 |
{ |
132 |
usage: std::cout << _B("Usage: ") << argv[0] << _B(" [-debug] [-device=device]") << std::endl; |
133 |
|
134 |
return 2; |
135 |
} |
136 |
|
137 |
try |
138 |
{ |
139 |
int uhid(Posix::Open(device, O_RDONLY)); |
140 |
uint8_t bytes[8]; |
141 |
Buttons buttons; |
142 |
Audacious::Audacious audacious; |
143 |
|
144 |
_forever |
145 |
{ |
146 |
Posix::ReadMost(uhid, bytes, sizeof (bytes)); |
147 |
|
148 |
_foreach (const _L<Button>, button, buttons.Events(bytes)) |
149 |
{ |
150 |
if (debug) |
151 |
std::cerr << _B("button=") << *button << std::endl; |
152 |
|
153 |
if (audacious.IsRunning()) |
154 |
switch (*button) |
155 |
{ |
156 |
default: |
157 |
break; |
158 |
|
159 |
case PlayPause: |
160 |
audacious.PlayPause(); |
161 |
|
162 |
break; |
163 |
|
164 |
case Previous: |
165 |
audacious.PlaylistPrevious(); |
166 |
|
167 |
break; |
168 |
|
169 |
case Next: |
170 |
audacious.PlaylistNext(); |
171 |
|
172 |
break; |
173 |
|
174 |
case VolumeDown: |
175 |
case VolumeUp: |
176 |
int volume(audacious.GetMainVolume() + (*button == VolumeUp ? 1 : -1)); |
177 |
|
178 |
audacious.SetMainVolume(volume); |
179 |
} |
180 |
} |
181 |
} |
182 |
} |
183 |
catch (const std::exception &exception) |
184 |
{ |
185 |
std::cerr << argv[0] << _B(": ") << exception.what() << std::endl; |
186 |
|
187 |
return 1; |
188 |
} |
189 |
|
190 |
return 0; |
191 |
} |