reflexion 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.doc/ext/reflex/application.cpp +16 -0
- data/.doc/ext/reflex/device.cpp +46 -3
- data/.doc/ext/reflex/device_event.cpp +62 -0
- data/.doc/ext/reflex/key_event.cpp +49 -19
- data/.doc/ext/reflex/midi.cpp +82 -0
- data/.doc/ext/reflex/native.cpp +10 -4
- data/.doc/ext/reflex/note_event.cpp +121 -0
- data/.doc/ext/reflex/reflex.cpp +30 -8
- data/.doc/ext/reflex/view.cpp +11 -16
- data/.doc/ext/reflex/window.cpp +24 -0
- data/ChangeLog.md +16 -0
- data/Rakefile +7 -0
- data/VERSION +1 -1
- data/ext/reflex/application.cpp +18 -0
- data/ext/reflex/device.cpp +48 -3
- data/ext/reflex/device_event.cpp +65 -0
- data/ext/reflex/key_event.cpp +49 -19
- data/ext/reflex/midi.cpp +87 -0
- data/ext/reflex/native.cpp +10 -4
- data/ext/reflex/note_event.cpp +130 -0
- data/ext/reflex/reflex.cpp +31 -8
- data/ext/reflex/view.cpp +11 -16
- data/ext/reflex/window.cpp +27 -0
- data/include/reflex/application.h +4 -0
- data/include/reflex/defs.h +58 -21
- data/include/reflex/device.h +22 -0
- data/include/reflex/event.h +64 -2
- data/include/reflex/gamepad.h +175 -0
- data/include/reflex/midi.h +53 -0
- data/include/reflex/reflex.h +2 -0
- data/include/reflex/ruby/application.h +18 -0
- data/include/reflex/ruby/device.h +40 -0
- data/include/reflex/ruby/event.h +22 -0
- data/include/reflex/ruby/midi.h +84 -0
- data/include/reflex/ruby/window.h +27 -0
- data/include/reflex/view.h +9 -1
- data/include/reflex/window.h +6 -0
- data/lib/reflex/note_event.rb +34 -0
- data/lib/reflex/view.rb +2 -1
- data/lib/reflex.rb +9 -8
- data/reflex.gemspec +3 -3
- data/src/application.cpp +70 -0
- data/src/application.h +9 -0
- data/src/device.cpp +24 -0
- data/src/event.cpp +133 -7
- data/src/event.h +5 -0
- data/src/gamepad.cpp +176 -0
- data/src/gamepad.h +74 -0
- data/src/ios/app_delegate.mm +2 -2
- data/src/ios/application.mm +0 -25
- data/src/ios/event.h +0 -5
- data/src/ios/event.mm +11 -87
- data/src/ios/gamepad.mm +314 -0
- data/src/ios/reflex.mm +0 -5
- data/src/midi.cpp +379 -0
- data/src/midi.h +32 -0
- data/src/osx/app_delegate.mm +2 -2
- data/src/osx/application.mm +0 -25
- data/src/osx/event.h +0 -5
- data/src/osx/event.mm +9 -86
- data/src/osx/gamepad.mm +40 -0
- data/src/osx/gamepad_gc.mm +299 -0
- data/src/osx/gamepad_hid.mm +567 -0
- data/src/osx/reflex.mm +0 -5
- data/src/queue.h +71 -0
- data/src/reflex.cpp +18 -0
- data/src/timer.cpp +3 -10
- data/src/view.cpp +39 -0
- data/src/view.h +2 -0
- data/src/win32/application.cpp +5 -26
- data/src/win32/event.cpp +6 -89
- data/src/win32/event.h +1 -1
- data/src/win32/gamepad.cpp +110 -0
- data/src/win32/gamepad.h +20 -0
- data/src/win32/window.cpp +2 -1
- data/src/window.cpp +61 -10
- data/src/window.h +2 -0
- data/test/test_capture_event.rb +20 -16
- data/test/test_key_event.rb +8 -1
- data/test/test_note_event.rb +43 -0
- data/test/test_view.rb +24 -12
- metadata +43 -14
@@ -0,0 +1,567 @@
|
|
1
|
+
// -*- objc -*-
|
2
|
+
#include "../gamepad.h"
|
3
|
+
|
4
|
+
|
5
|
+
#include <memory>
|
6
|
+
#include <vector>
|
7
|
+
#include <map>
|
8
|
+
#import <IOKit/hid/IOHIDManager.h>
|
9
|
+
#import <IOKit/hid/IOHIDDevice.h>
|
10
|
+
#import <GameController/GameController.h>
|
11
|
+
#include <xot/util.h>
|
12
|
+
#include "reflex/exception.h"
|
13
|
+
#include "reflex/debug.h"
|
14
|
+
#include "event.h"
|
15
|
+
#include "window.h"
|
16
|
+
|
17
|
+
|
18
|
+
namespace Reflex
|
19
|
+
{
|
20
|
+
|
21
|
+
|
22
|
+
static int
|
23
|
+
get_int_property (IOHIDDeviceRef device, CFStringRef key)
|
24
|
+
{
|
25
|
+
CFNumberRef ref = (CFNumberRef) IOHIDDeviceGetProperty(device, key);
|
26
|
+
if (!ref) return 0;
|
27
|
+
|
28
|
+
int value = 0;
|
29
|
+
CFNumberGetValue(ref, kCFNumberIntType, &value);
|
30
|
+
return value;
|
31
|
+
}
|
32
|
+
|
33
|
+
static String
|
34
|
+
get_string_property (IOHIDDeviceRef device, CFStringRef key)
|
35
|
+
{
|
36
|
+
return Xot::to_s((CFStringRef) IOHIDDeviceGetProperty(device, key));
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
struct HIDGamepadData : Gamepad::Data
|
41
|
+
{
|
42
|
+
|
43
|
+
typedef Gamepad::Data Super;
|
44
|
+
|
45
|
+
enum Mapping {RSTICK_UNKNOWN, RSTICK_RxRy, RSTICK_ZRz};
|
46
|
+
|
47
|
+
IOHIDDeviceRef device;
|
48
|
+
|
49
|
+
Mapping mapping = RSTICK_UNKNOWN;
|
50
|
+
|
51
|
+
CFIndex prev_hatswitch = 8;// neutral
|
52
|
+
|
53
|
+
mutable String name_cache;
|
54
|
+
|
55
|
+
HIDGamepadData (IOHIDDeviceRef device)
|
56
|
+
: device(device)
|
57
|
+
{
|
58
|
+
if (!device)
|
59
|
+
argument_error(__FILE__, __LINE__);
|
60
|
+
|
61
|
+
CFRetain(device);
|
62
|
+
prev.reset(new Gamepad());
|
63
|
+
}
|
64
|
+
|
65
|
+
~HIDGamepadData ()
|
66
|
+
{
|
67
|
+
CFRelease(device);
|
68
|
+
}
|
69
|
+
|
70
|
+
const char* name () const override
|
71
|
+
{
|
72
|
+
if (name_cache.empty())
|
73
|
+
{
|
74
|
+
String& name = name_cache;
|
75
|
+
name = get_string_property(device, CFSTR(kIOHIDManufacturerKey));
|
76
|
+
String product = get_string_property(device, CFSTR(kIOHIDProductKey));
|
77
|
+
String serial = get_string_property(device, CFSTR(kIOHIDSerialNumberKey));
|
78
|
+
|
79
|
+
if (!product.empty())
|
80
|
+
{
|
81
|
+
if (!name.empty() && name[name.size() - 1] != ' ') name_cache += " ";
|
82
|
+
name += product;
|
83
|
+
}
|
84
|
+
|
85
|
+
if (!serial.empty())
|
86
|
+
{
|
87
|
+
if (!name.empty() && name[name.size() - 1] != ' ')
|
88
|
+
{
|
89
|
+
name += " ";
|
90
|
+
serial = "[" + serial + "]";
|
91
|
+
}
|
92
|
+
name += serial;
|
93
|
+
}
|
94
|
+
|
95
|
+
if (name.empty()) name = "Unknown";
|
96
|
+
}
|
97
|
+
return name_cache;
|
98
|
+
}
|
99
|
+
|
100
|
+
bool is_valid () const override
|
101
|
+
{
|
102
|
+
return Super::is_valid() && device;
|
103
|
+
}
|
104
|
+
|
105
|
+
bool has_handle (void* handle) const override
|
106
|
+
{
|
107
|
+
return handle == device;
|
108
|
+
}
|
109
|
+
|
110
|
+
};// HIDGamepadData
|
111
|
+
|
112
|
+
|
113
|
+
static Gamepad*
|
114
|
+
Gamepad_create (IOHIDDeviceRef device)
|
115
|
+
{
|
116
|
+
Gamepad* g = Gamepad_create();
|
117
|
+
g->self.reset(new HIDGamepadData(device));
|
118
|
+
return g;
|
119
|
+
}
|
120
|
+
|
121
|
+
static HIDGamepadData*
|
122
|
+
get_data (Gamepad* gamepad)
|
123
|
+
{
|
124
|
+
return (HIDGamepadData*) gamepad->self.get();
|
125
|
+
}
|
126
|
+
|
127
|
+
static std::map<IOHIDElementRef, IOHIDDeviceRef> element2device;
|
128
|
+
|
129
|
+
static void
|
130
|
+
each_element (IOHIDDeviceRef device, std::function<bool(IOHIDElementRef)> fun)
|
131
|
+
{
|
132
|
+
std::shared_ptr<const __CFArray> elements(
|
133
|
+
IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone),
|
134
|
+
Xot::safe_cfrelease);
|
135
|
+
if (!elements) return;
|
136
|
+
|
137
|
+
CFIndex count = CFArrayGetCount(elements.get());
|
138
|
+
for (CFIndex i = 0; i < count; ++i)
|
139
|
+
{
|
140
|
+
IOHIDElementRef element =
|
141
|
+
(IOHIDElementRef) CFArrayGetValueAtIndex(elements.get(), i);
|
142
|
+
if (!element) continue;
|
143
|
+
|
144
|
+
if (!fun(element)) break;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
static void
|
149
|
+
register_to_device_map (IOHIDDeviceRef device)
|
150
|
+
{
|
151
|
+
if (@available(macOS 11.0, *))
|
152
|
+
return;
|
153
|
+
|
154
|
+
each_element(device, [&](IOHIDElementRef element)
|
155
|
+
{
|
156
|
+
element2device[element] = device;
|
157
|
+
return true;
|
158
|
+
});
|
159
|
+
}
|
160
|
+
|
161
|
+
static void
|
162
|
+
unregister_to_device_map (IOHIDDeviceRef device)
|
163
|
+
{
|
164
|
+
if (@available(macOS 11.0, *))
|
165
|
+
return;
|
166
|
+
|
167
|
+
std::erase_if(
|
168
|
+
element2device,
|
169
|
+
[&](const auto& e) {return e.second == device;});
|
170
|
+
}
|
171
|
+
|
172
|
+
static IOHIDDeviceRef
|
173
|
+
get_device (IOHIDElementRef element)
|
174
|
+
{
|
175
|
+
if (@available(macOS 11.0, *))
|
176
|
+
return IOHIDElementGetDevice(element);
|
177
|
+
else
|
178
|
+
{
|
179
|
+
auto it = element2device.find(element);
|
180
|
+
if (it == element2device.end())
|
181
|
+
return NULL;
|
182
|
+
|
183
|
+
return it->second;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
static float
|
188
|
+
get_current_value (IOHIDDeviceRef device, uint32_t usage)
|
189
|
+
{
|
190
|
+
float value = 0;
|
191
|
+
each_element(device, [&](IOHIDElementRef element)
|
192
|
+
{
|
193
|
+
if (IOHIDElementGetUsage(element) != usage)
|
194
|
+
return true;
|
195
|
+
|
196
|
+
IOHIDValueRef valref = NULL;
|
197
|
+
IOReturn result = IOHIDDeviceGetValue(device, element, &valref);
|
198
|
+
if (result != kIOReturnSuccess || !valref)
|
199
|
+
return true;
|
200
|
+
|
201
|
+
CFIndex val = IOHIDValueGetIntegerValue(valref);
|
202
|
+
CFIndex min = IOHIDElementGetLogicalMin(element);
|
203
|
+
CFIndex max = IOHIDElementGetLogicalMax(element);
|
204
|
+
|
205
|
+
value = (val - min) / (float) (max - min);
|
206
|
+
return false;
|
207
|
+
});
|
208
|
+
|
209
|
+
return value;
|
210
|
+
}
|
211
|
+
|
212
|
+
static HIDGamepadData::Mapping
|
213
|
+
get_mapping (IOHIDDeviceRef device)
|
214
|
+
{
|
215
|
+
float Z = get_current_value(device, kHIDUsage_GD_Z);
|
216
|
+
float Rx = get_current_value(device, kHIDUsage_GD_Rx);
|
217
|
+
if (0.4 < Z && Z < 0.6) return HIDGamepadData::RSTICK_ZRz;
|
218
|
+
if (0.4 < Rx && Rx < 0.6) return HIDGamepadData::RSTICK_RxRy;
|
219
|
+
return HIDGamepadData::RSTICK_UNKNOWN;
|
220
|
+
}
|
221
|
+
|
222
|
+
static void
|
223
|
+
add_gamepad (Application* app, IOHIDDeviceRef device)
|
224
|
+
{
|
225
|
+
Gamepad* gamepad = Gamepad_create(device);
|
226
|
+
get_data(gamepad)->mapping = get_mapping(device);
|
227
|
+
Gamepad_add(app, gamepad);
|
228
|
+
}
|
229
|
+
|
230
|
+
static void
|
231
|
+
remove_gamepad (Application* app, IOHIDDeviceRef device)
|
232
|
+
{
|
233
|
+
Gamepad* gamepad = Gamepad_find(device);
|
234
|
+
if (!gamepad) return;
|
235
|
+
|
236
|
+
Gamepad_remove(app, gamepad);
|
237
|
+
}
|
238
|
+
|
239
|
+
static bool
|
240
|
+
can_handle (IOHIDDeviceRef device)
|
241
|
+
{
|
242
|
+
int page = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
|
243
|
+
int usage = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
|
244
|
+
return
|
245
|
+
page == kHIDPage_GenericDesktop &&
|
246
|
+
(usage == kHIDUsage_GD_GamePad || usage == kHIDUsage_GD_Joystick);
|
247
|
+
}
|
248
|
+
|
249
|
+
static void
|
250
|
+
handle_disconnect_event (void* context, IOReturn result, void* sender)
|
251
|
+
{
|
252
|
+
IOHIDDeviceRef device = (IOHIDDeviceRef) context;
|
253
|
+
|
254
|
+
remove_gamepad(app(), device);
|
255
|
+
unregister_to_device_map(device);
|
256
|
+
}
|
257
|
+
|
258
|
+
static void
|
259
|
+
handle_connect_event (
|
260
|
+
void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
|
261
|
+
{
|
262
|
+
Application* app = (Application*) context;
|
263
|
+
|
264
|
+
if (!can_handle(device))
|
265
|
+
return;
|
266
|
+
|
267
|
+
if (@available(macOS 11.0, *))
|
268
|
+
{
|
269
|
+
if ([GCController supportsHIDDevice: device])
|
270
|
+
return;
|
271
|
+
}
|
272
|
+
|
273
|
+
IOHIDDeviceRegisterRemovalCallback(device, handle_disconnect_event, device);
|
274
|
+
|
275
|
+
register_to_device_map(device);
|
276
|
+
add_gamepad(app, device);
|
277
|
+
}
|
278
|
+
|
279
|
+
enum
|
280
|
+
{
|
281
|
+
DPAD_UP = Xot::bit(0),
|
282
|
+
DPAD_RIGHT = Xot::bit(1),
|
283
|
+
DPAD_DOWN = Xot::bit(2),
|
284
|
+
DPAD_LEFT = Xot::bit(3)
|
285
|
+
};
|
286
|
+
|
287
|
+
static uint
|
288
|
+
to_dpad (CFIndex hatswitch)
|
289
|
+
{
|
290
|
+
switch (hatswitch)
|
291
|
+
{
|
292
|
+
case 0: return DPAD_UP;
|
293
|
+
case 1: return DPAD_UP | DPAD_RIGHT;
|
294
|
+
case 2: return DPAD_RIGHT;
|
295
|
+
case 3: return DPAD_RIGHT | DPAD_DOWN;
|
296
|
+
case 4: return DPAD_DOWN;
|
297
|
+
case 5: return DPAD_DOWN | DPAD_LEFT;
|
298
|
+
case 6: return DPAD_LEFT;
|
299
|
+
case 7: return DPAD_LEFT | DPAD_UP;
|
300
|
+
}
|
301
|
+
return 0;
|
302
|
+
}
|
303
|
+
|
304
|
+
static void
|
305
|
+
call_gamepad_event (int key_code, bool pressed)
|
306
|
+
{
|
307
|
+
Window* win = Window_get_active();
|
308
|
+
if (!win) return;
|
309
|
+
|
310
|
+
auto action = pressed ? KeyEvent::DOWN : KeyEvent::UP;
|
311
|
+
KeyEvent e(action, NULL, key_code, KeyEvent_get_modifiers(), 0);
|
312
|
+
Window_call_key_event(win, &e);
|
313
|
+
}
|
314
|
+
|
315
|
+
static void
|
316
|
+
call_button_event (
|
317
|
+
Gamepad* gamepad, ulonglong button, int key_code, float value)
|
318
|
+
{
|
319
|
+
Gamepad::Data* self = gamepad->self.get();
|
320
|
+
|
321
|
+
bool pressed = value > Gamepad_get_button_press_threshold();
|
322
|
+
bool current = self->state.buttons & button;
|
323
|
+
if (pressed == current) return;
|
324
|
+
|
325
|
+
self->update_prev();
|
326
|
+
if (pressed)
|
327
|
+
self->state.buttons |= button;
|
328
|
+
else
|
329
|
+
self->state.buttons &= ~button;
|
330
|
+
|
331
|
+
call_gamepad_event(key_code, pressed);
|
332
|
+
}
|
333
|
+
|
334
|
+
static void
|
335
|
+
handle_hatswitch_event (
|
336
|
+
Gamepad* gamepad, IOHIDElementRef element, CFIndex hatswitch)
|
337
|
+
{
|
338
|
+
HIDGamepadData* data = get_data(gamepad);
|
339
|
+
|
340
|
+
CFIndex prev = data->prev_hatswitch;
|
341
|
+
data->prev_hatswitch = hatswitch;
|
342
|
+
|
343
|
+
uint prev_dpad = to_dpad(prev);
|
344
|
+
uint dpad = to_dpad(hatswitch);
|
345
|
+
uint diff = prev_dpad ^ dpad;
|
346
|
+
|
347
|
+
#define HANDLE_BUTTON(button, value) \
|
348
|
+
call_button_event( \
|
349
|
+
gamepad, \
|
350
|
+
Gamepad::button, KEY_GAMEPAD_##button, \
|
351
|
+
(value) ? 1 : 0)
|
352
|
+
|
353
|
+
if (diff & DPAD_UP) HANDLE_BUTTON(UP, dpad & DPAD_UP);
|
354
|
+
if (diff & DPAD_RIGHT) HANDLE_BUTTON(RIGHT, dpad & DPAD_RIGHT);
|
355
|
+
if (diff & DPAD_DOWN) HANDLE_BUTTON(DOWN, dpad & DPAD_DOWN);
|
356
|
+
if (diff & DPAD_LEFT) HANDLE_BUTTON(LEFT, dpad & DPAD_LEFT);
|
357
|
+
|
358
|
+
#undef HANDLE_BUTTON
|
359
|
+
}
|
360
|
+
|
361
|
+
static void
|
362
|
+
handle_stick_dpad_event (
|
363
|
+
Gamepad* gamepad, auto* state, float value,
|
364
|
+
ulonglong button_negative, int key_code_negative,
|
365
|
+
ulonglong button_positive, int key_code_positive)
|
366
|
+
{
|
367
|
+
*state = value;
|
368
|
+
|
369
|
+
if (value < 0)
|
370
|
+
call_button_event(gamepad, button_negative, key_code_negative, -value);
|
371
|
+
else
|
372
|
+
call_button_event(gamepad, button_positive, key_code_positive, value);
|
373
|
+
}
|
374
|
+
|
375
|
+
static void
|
376
|
+
handle_trigger_event (Gamepad* gamepad, auto* state, float value)
|
377
|
+
{
|
378
|
+
*state = value;
|
379
|
+
}
|
380
|
+
|
381
|
+
static void
|
382
|
+
handle_analog_event (
|
383
|
+
Gamepad* gamepad, uint32_t usage, IOHIDElementRef element, CFIndex intval)
|
384
|
+
{
|
385
|
+
int value = (int) intval;
|
386
|
+
int min = (int) IOHIDElementGetLogicalMin(element);
|
387
|
+
int max = (int) IOHIDElementGetLogicalMax(element);
|
388
|
+
float range = min == max ? max : max - min;
|
389
|
+
if (range == 0) range = 1;
|
390
|
+
|
391
|
+
float linear = (value - min) / range;
|
392
|
+
float centered = linear * 2 - 1;
|
393
|
+
|
394
|
+
#define HANDLE_DPAD(stick, neg, pos, var, value) \
|
395
|
+
handle_stick_dpad_event( \
|
396
|
+
gamepad, \
|
397
|
+
&gamepad->self->state.var, \
|
398
|
+
value, \
|
399
|
+
Gamepad::stick##_##neg, KEY_GAMEPAD_##stick##_##neg, \
|
400
|
+
Gamepad::stick##_##pos, KEY_GAMEPAD_##stick##_##pos)
|
401
|
+
|
402
|
+
#define HANDLE_TRIGGER(trigger, var, value) \
|
403
|
+
handle_trigger_event( \
|
404
|
+
gamepad, \
|
405
|
+
&gamepad->self->state.var, \
|
406
|
+
value)
|
407
|
+
|
408
|
+
switch (get_data(gamepad)->mapping)
|
409
|
+
{
|
410
|
+
case HIDGamepadData::RSTICK_RxRy:
|
411
|
+
switch (usage)
|
412
|
+
{
|
413
|
+
case kHIDUsage_GD_X: HANDLE_DPAD(LSTICK, LEFT, RIGHT, sticks[0].x, centered); break;
|
414
|
+
case kHIDUsage_GD_Y: HANDLE_DPAD(LSTICK, UP, DOWN, sticks[0].y, -centered); break;
|
415
|
+
case kHIDUsage_GD_Rx: HANDLE_DPAD(RSTICK, LEFT, RIGHT, sticks[1].x, centered); break;
|
416
|
+
case kHIDUsage_GD_Ry: HANDLE_DPAD(RSTICK, UP, DOWN, sticks[1].y, -centered); break;
|
417
|
+
case kHIDUsage_GD_Z: HANDLE_TRIGGER(LTRIGGER, triggers[0], linear); break;
|
418
|
+
case kHIDUsage_GD_Rz: HANDLE_TRIGGER(RTRIGGER, triggers[1], linear); break;
|
419
|
+
}
|
420
|
+
break;
|
421
|
+
|
422
|
+
case HIDGamepadData::RSTICK_ZRz:
|
423
|
+
switch (usage)
|
424
|
+
{
|
425
|
+
case kHIDUsage_GD_X: HANDLE_DPAD(LSTICK, LEFT, RIGHT, sticks[0].x, centered); break;
|
426
|
+
case kHIDUsage_GD_Y: HANDLE_DPAD(LSTICK, UP, DOWN, sticks[0].y, -centered); break;
|
427
|
+
case kHIDUsage_GD_Z: HANDLE_DPAD(RSTICK, LEFT, RIGHT, sticks[1].x, centered); break;
|
428
|
+
case kHIDUsage_GD_Rz: HANDLE_DPAD(RSTICK, UP, DOWN, sticks[1].y, -centered); break;
|
429
|
+
case kHIDUsage_GD_Rx: HANDLE_TRIGGER(LTRIGGER, triggers[0], linear); break;
|
430
|
+
case kHIDUsage_GD_Ry: HANDLE_TRIGGER(RTRIGGER, triggers[1], linear); break;
|
431
|
+
}
|
432
|
+
break;
|
433
|
+
|
434
|
+
default:
|
435
|
+
switch (usage)
|
436
|
+
{
|
437
|
+
case kHIDUsage_GD_X: HANDLE_DPAD(LSTICK, LEFT, RIGHT, sticks[0].x, centered); break;
|
438
|
+
case kHIDUsage_GD_Y: HANDLE_DPAD(LSTICK, UP, DOWN, sticks[0].y, -centered); break;
|
439
|
+
}
|
440
|
+
break;
|
441
|
+
}
|
442
|
+
|
443
|
+
#undef HANDLE_DPAD
|
444
|
+
#undef HANDLE_TRIGGER
|
445
|
+
}
|
446
|
+
|
447
|
+
static void
|
448
|
+
handle_gamepad_events (
|
449
|
+
void* context, IOReturn result, void* sender, IOHIDValueRef valref)
|
450
|
+
{
|
451
|
+
IOHIDElementRef element = IOHIDValueGetElement(valref);
|
452
|
+
if (!element) return;
|
453
|
+
|
454
|
+
Gamepad* gamepad = Gamepad_find(get_device(element));
|
455
|
+
if (!gamepad) return;
|
456
|
+
|
457
|
+
uint32_t page = IOHIDElementGetUsagePage(element);
|
458
|
+
uint32_t usage = IOHIDElementGetUsage(element);
|
459
|
+
CFIndex value = IOHIDValueGetIntegerValue(valref);
|
460
|
+
|
461
|
+
switch (page)
|
462
|
+
{
|
463
|
+
case kHIDPage_GenericDesktop:
|
464
|
+
switch (usage)
|
465
|
+
{
|
466
|
+
case kHIDUsage_GD_Hatswitch:
|
467
|
+
handle_hatswitch_event(gamepad, element, value);
|
468
|
+
break;
|
469
|
+
|
470
|
+
case kHIDUsage_GD_X:
|
471
|
+
case kHIDUsage_GD_Y:
|
472
|
+
case kHIDUsage_GD_Z:
|
473
|
+
case kHIDUsage_GD_Rx:
|
474
|
+
case kHIDUsage_GD_Ry:
|
475
|
+
case kHIDUsage_GD_Rz:
|
476
|
+
handle_analog_event(gamepad, usage, element, value);
|
477
|
+
break;
|
478
|
+
}
|
479
|
+
break;
|
480
|
+
|
481
|
+
case kHIDPage_Button:
|
482
|
+
{
|
483
|
+
int nth = (int) usage - 1;
|
484
|
+
if (0 <= nth && nth < (KEY_GAMEPAD_BUTTON_MAX - KEY_GAMEPAD_BUTTON_0))
|
485
|
+
{
|
486
|
+
ulonglong button = Xot::bit<ulonglong>(nth, Gamepad::BUTTON_0);
|
487
|
+
int key_code = KEY_GAMEPAD_BUTTON_0 + nth;
|
488
|
+
call_button_event(gamepad, button, key_code, value > 0 ? 1 : 0);
|
489
|
+
}
|
490
|
+
break;
|
491
|
+
}
|
492
|
+
}
|
493
|
+
}
|
494
|
+
|
495
|
+
static IOHIDManagerRef manager = NULL;
|
496
|
+
|
497
|
+
static void
|
498
|
+
add_connected_gamepads (Application* app)
|
499
|
+
{
|
500
|
+
std::shared_ptr<const __CFSet> set(
|
501
|
+
IOHIDManagerCopyDevices(manager),
|
502
|
+
Xot::safe_cfrelease);
|
503
|
+
if (!set) return;
|
504
|
+
|
505
|
+
CFIndex count = CFSetGetCount(set.get());
|
506
|
+
std::vector<IOHIDDeviceRef> devices(count, NULL);
|
507
|
+
CFSetGetValues(set.get(), (const void**) &devices[0]);
|
508
|
+
|
509
|
+
for (CFIndex i = 0; i < count; ++i)
|
510
|
+
handle_connect_event(app, kIOReturnSuccess, manager, devices[i]);
|
511
|
+
}
|
512
|
+
|
513
|
+
void
|
514
|
+
init_hid_gamepads (Application* app)
|
515
|
+
{
|
516
|
+
if (manager)
|
517
|
+
invalid_state_error(__FILE__, __LINE__);
|
518
|
+
|
519
|
+
manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
520
|
+
if (!manager)
|
521
|
+
system_error(__FILE__, __LINE__);
|
522
|
+
|
523
|
+
add_connected_gamepads(app);
|
524
|
+
|
525
|
+
NSDictionary* gamepad =
|
526
|
+
@{
|
527
|
+
@kIOHIDDeviceUsagePageKey: @(kHIDPage_GenericDesktop),
|
528
|
+
@kIOHIDDeviceUsageKey: @(kHIDUsage_GD_GamePad)
|
529
|
+
};
|
530
|
+
NSDictionary* joystick =
|
531
|
+
@{
|
532
|
+
@kIOHIDDeviceUsagePageKey: @(kHIDPage_GenericDesktop),
|
533
|
+
@kIOHIDDeviceUsageKey: @(kHIDUsage_GD_Joystick)
|
534
|
+
};
|
535
|
+
NSArray* matchings = @[gamepad, joystick];
|
536
|
+
IOHIDManagerSetDeviceMatchingMultiple(
|
537
|
+
manager, (__bridge CFArrayRef) matchings);
|
538
|
+
|
539
|
+
IOHIDManagerRegisterDeviceMatchingCallback(
|
540
|
+
manager, handle_connect_event, app);
|
541
|
+
IOHIDManagerRegisterInputValueCallback(
|
542
|
+
manager, handle_gamepad_events, app);
|
543
|
+
|
544
|
+
IOHIDManagerScheduleWithRunLoop(
|
545
|
+
manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
546
|
+
|
547
|
+
IOReturn ret = IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone);
|
548
|
+
if (ret != kIOReturnSuccess)
|
549
|
+
system_error(__FILE__, __LINE__);
|
550
|
+
}
|
551
|
+
|
552
|
+
void
|
553
|
+
fin_hid_gamepads (Application* app)
|
554
|
+
{
|
555
|
+
if (!manager)
|
556
|
+
invalid_state_error(__FILE__, __LINE__);
|
557
|
+
|
558
|
+
IOHIDManagerUnscheduleFromRunLoop(
|
559
|
+
manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
560
|
+
IOHIDManagerClose(manager, kIOHIDOptionsTypeNone);
|
561
|
+
|
562
|
+
CFRelease(manager);
|
563
|
+
manager = NULL;
|
564
|
+
}
|
565
|
+
|
566
|
+
|
567
|
+
}// Reflex
|
data/src/osx/reflex.mm
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
#import <Cocoa/Cocoa.h>
|
6
6
|
#include "reflex/exception.h"
|
7
|
-
#include "event.h"
|
8
7
|
|
9
8
|
|
10
9
|
namespace Reflex
|
@@ -26,8 +25,6 @@ namespace Reflex
|
|
26
25
|
reflex_error(__FILE__, __LINE__, "already initialized.");
|
27
26
|
|
28
27
|
global::pool = [[NSAutoreleasePool alloc] init];
|
29
|
-
|
30
|
-
init_game_controllers();
|
31
28
|
}
|
32
29
|
|
33
30
|
void
|
@@ -36,8 +33,6 @@ namespace Reflex
|
|
36
33
|
if (!global::pool)
|
37
34
|
reflex_error(__FILE__, __LINE__, "not initialized.");
|
38
35
|
|
39
|
-
fin_game_controllers();
|
40
|
-
|
41
36
|
[global::pool release];
|
42
37
|
global::pool = nil;
|
43
38
|
}
|
data/src/queue.h
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
// -*- c++ -*-
|
2
|
+
#pragma once
|
3
|
+
#ifndef __REFLEX_SRC_QUEUE_H__
|
4
|
+
#define __REFLEX_SRC_QUEUE_H__
|
5
|
+
|
6
|
+
|
7
|
+
#include <queue>
|
8
|
+
#include <mutex>
|
9
|
+
#include <condition_variable>
|
10
|
+
|
11
|
+
|
12
|
+
namespace Reflex
|
13
|
+
{
|
14
|
+
|
15
|
+
|
16
|
+
template <typename T>
|
17
|
+
class Queue
|
18
|
+
{
|
19
|
+
|
20
|
+
public:
|
21
|
+
|
22
|
+
void push (const T& value)
|
23
|
+
{
|
24
|
+
{
|
25
|
+
std::lock_guard<std::mutex> lock(mutex);
|
26
|
+
queue.push(value);
|
27
|
+
}
|
28
|
+
condvar.notify_one();
|
29
|
+
}
|
30
|
+
|
31
|
+
T pop ()
|
32
|
+
{
|
33
|
+
std::unique_lock<std::mutex> lock(mutex);
|
34
|
+
condvar.wait(lock, [this] {return !queue.empty();});
|
35
|
+
|
36
|
+
T value = queue.front();
|
37
|
+
queue.pop();
|
38
|
+
return value;
|
39
|
+
}
|
40
|
+
|
41
|
+
bool try_pop (T* value)
|
42
|
+
{
|
43
|
+
std::lock_guard<std::mutex> lock(mutex);
|
44
|
+
if (queue.empty()) return false;
|
45
|
+
|
46
|
+
*value = queue.front();
|
47
|
+
queue.pop();
|
48
|
+
return true;
|
49
|
+
}
|
50
|
+
|
51
|
+
bool empty () const
|
52
|
+
{
|
53
|
+
std::lock_guard<std::mutex> lock(mutex);
|
54
|
+
return queue.empty();
|
55
|
+
}
|
56
|
+
|
57
|
+
private:
|
58
|
+
|
59
|
+
std::queue<T> queue;
|
60
|
+
|
61
|
+
std::mutex mutex;
|
62
|
+
|
63
|
+
std::condition_variable condvar;
|
64
|
+
|
65
|
+
};// Queue
|
66
|
+
|
67
|
+
|
68
|
+
}// Reflex
|
69
|
+
|
70
|
+
|
71
|
+
#endif//EOH
|
data/src/reflex.cpp
ADDED
data/src/timer.cpp
CHANGED
@@ -40,25 +40,18 @@ namespace Reflex
|
|
40
40
|
};// Data
|
41
41
|
|
42
42
|
|
43
|
-
|
44
|
-
{
|
45
|
-
|
46
|
-
static Timer_CreateFun create_fun = NULL;
|
47
|
-
|
48
|
-
}// global
|
43
|
+
static Timer_CreateFun timer_create_fun = NULL;
|
49
44
|
|
50
45
|
void
|
51
46
|
Timer_set_create_fun (Timer_CreateFun fun)
|
52
47
|
{
|
53
|
-
|
48
|
+
timer_create_fun = fun;
|
54
49
|
}
|
55
50
|
|
56
51
|
static Timer*
|
57
52
|
Timer_create ()
|
58
53
|
{
|
59
|
-
return
|
60
|
-
? global::create_fun()
|
61
|
-
: new Timer();
|
54
|
+
return timer_create_fun ? timer_create_fun() : new Timer();
|
62
55
|
}
|
63
56
|
|
64
57
|
|