reflexion 0.3.4 → 0.3.6
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 +50 -0
- data/.doc/ext/reflex/native.cpp +6 -4
- data/.doc/ext/reflex/reflex.cpp +24 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- data/CONTRIBUTING.md +7 -0
- data/ChangeLog.md +20 -0
- data/README.md +46 -2
- 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/extconf.rb +3 -3
- data/ext/reflex/key_event.cpp +50 -0
- data/ext/reflex/native.cpp +6 -4
- data/ext/reflex/reflex.cpp +24 -0
- data/include/reflex/application.h +4 -0
- data/include/reflex/defs.h +60 -0
- data/include/reflex/device.h +22 -0
- data/include/reflex/event.h +25 -0
- data/include/reflex/gamepad.h +175 -0
- data/include/reflex/ruby/application.h +18 -0
- data/include/reflex/ruby/device.h +40 -0
- data/include/reflex/ruby/event.h +11 -0
- data/reflex.gemspec +3 -3
- data/src/application.cpp +67 -0
- data/src/application.h +9 -0
- data/src/device.cpp +24 -0
- data/src/event.cpp +38 -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.mm +2 -3
- data/src/ios/gamepad.mm +313 -0
- data/src/osx/app_delegate.mm +2 -2
- data/src/osx/application.mm +0 -25
- data/src/osx/event.h +3 -0
- data/src/osx/event.mm +11 -3
- 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/view.cpp +52 -18
- data/src/win32/application.cpp +5 -26
- data/src/win32/event.cpp +8 -7
- data/src/win32/event.h +5 -0
- data/src/win32/gamepad.cpp +110 -0
- data/src/win32/gamepad.h +20 -0
- data/src/win32/window.cpp +9 -1
- data/src/window.cpp +15 -0
- data/src/window.h +9 -0
- metadata +30 -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, get_key_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/view.cpp
CHANGED
@@ -39,23 +39,29 @@ namespace Reflex
|
|
39
39
|
enum Flag
|
40
40
|
{
|
41
41
|
|
42
|
-
|
42
|
+
UPDATING = Xot::bit(1, FLAG_LAST),
|
43
43
|
|
44
|
-
|
44
|
+
NO_SHAPE = Xot::bit(2, FLAG_LAST),
|
45
45
|
|
46
|
-
|
46
|
+
HAS_VARIABLE_LENGTHS = Xot::bit(3, FLAG_LAST),
|
47
47
|
|
48
|
-
|
48
|
+
HAS_CHILDREN_TO_REMOVE = Xot::bit(4, FLAG_LAST),
|
49
49
|
|
50
|
-
|
50
|
+
REMOVE_FROM_PARENT = Xot::bit(5, FLAG_LAST),
|
51
51
|
|
52
|
-
|
52
|
+
REDRAW = Xot::bit(6, FLAG_LAST),
|
53
53
|
|
54
|
-
|
54
|
+
APPLY_STYLE = Xot::bit(7, FLAG_LAST),
|
55
55
|
|
56
|
-
|
56
|
+
UPDATE_STYLE = Xot::bit(8, FLAG_LAST),
|
57
57
|
|
58
|
-
|
58
|
+
UPDATE_SHAPES = Xot::bit(9, FLAG_LAST),
|
59
|
+
|
60
|
+
UPDATE_LAYOUT = Xot::bit(10, FLAG_LAST),
|
61
|
+
|
62
|
+
SORT_CHILDREN = Xot::bit(11, FLAG_LAST),
|
63
|
+
|
64
|
+
FIT_TO_CONTENT = Xot::bit(12, FLAG_LAST),
|
59
65
|
|
60
66
|
};// Flag
|
61
67
|
|
@@ -1045,6 +1051,20 @@ namespace Reflex
|
|
1045
1051
|
}
|
1046
1052
|
}
|
1047
1053
|
|
1054
|
+
static void
|
1055
|
+
remove_children (View* view, View::ChildList* children)
|
1056
|
+
{
|
1057
|
+
assert(children);
|
1058
|
+
|
1059
|
+
int size = (int) children->size();
|
1060
|
+
for (int i = size - 1; i >= 0; --i)
|
1061
|
+
{
|
1062
|
+
View* child = (*children)[i].get();
|
1063
|
+
if (child->self->check_and_remove_flag(View::Data::REMOVE_FROM_PARENT))
|
1064
|
+
view->remove_child(child);
|
1065
|
+
}
|
1066
|
+
}
|
1067
|
+
|
1048
1068
|
void
|
1049
1069
|
View_update_tree (View* view, const UpdateEvent& event)
|
1050
1070
|
{
|
@@ -1053,13 +1073,16 @@ namespace Reflex
|
|
1053
1073
|
|
1054
1074
|
View::Data* self = view->self.get();
|
1055
1075
|
|
1076
|
+
self->add_flag(View::Data::UPDATING);
|
1077
|
+
|
1056
1078
|
fire_timers(view, event.now());
|
1057
1079
|
|
1058
1080
|
View::ChildList* children = self->children();
|
1059
1081
|
if (children)
|
1060
1082
|
{
|
1061
|
-
|
1062
|
-
|
1083
|
+
size_t size = children->size();
|
1084
|
+
for (size_t i = 0; i < size; ++i)
|
1085
|
+
View_update_tree((*children)[i].get(), event);
|
1063
1086
|
}
|
1064
1087
|
|
1065
1088
|
update_view_shapes(view);
|
@@ -1081,6 +1104,11 @@ namespace Reflex
|
|
1081
1104
|
|
1082
1105
|
if (self->check_and_remove_flag(View::Data::FIT_TO_CONTENT))
|
1083
1106
|
fit_view_to_content(view);
|
1107
|
+
|
1108
|
+
self->remove_flag(View::Data::UPDATING);
|
1109
|
+
|
1110
|
+
if (self->check_and_remove_flag(View::Data::HAS_CHILDREN_TO_REMOVE))
|
1111
|
+
remove_children(view, children);
|
1084
1112
|
}
|
1085
1113
|
|
1086
1114
|
static bool
|
@@ -1792,13 +1820,19 @@ namespace Reflex
|
|
1792
1820
|
else if (found != belong)
|
1793
1821
|
invalid_state_error(__FILE__, __LINE__);
|
1794
1822
|
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1823
|
+
if (self->has_flag(Data::UPDATING))
|
1824
|
+
{
|
1825
|
+
// delay removing child to avoid breaking child list looped on View_update_tree()
|
1826
|
+
self->add_flag(Data::HAS_CHILDREN_TO_REMOVE);
|
1827
|
+
child->self->add_flag(Data::REMOVE_FROM_PARENT);
|
1828
|
+
}
|
1829
|
+
else
|
1830
|
+
{
|
1831
|
+
set_parent(child, NULL);
|
1832
|
+
erase_child_from_children(this, child);
|
1833
|
+
self->sort_children();
|
1834
|
+
update_view_layout(this);
|
1835
|
+
}
|
1802
1836
|
}
|
1803
1837
|
|
1804
1838
|
void
|