reflexion 0.3.15 → 0.4.0

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.
data/src/ios/event.h CHANGED
@@ -4,7 +4,7 @@
4
4
  #define __REFLEX_SRC_IOS_EVENT_H__
5
5
 
6
6
 
7
- #import <UIKit/UIEvent.h>
7
+ #import <UIKit/UIKit.h>
8
8
  #include "../event.h"
9
9
 
10
10
 
@@ -12,6 +12,17 @@ namespace Reflex
12
12
  {
13
13
 
14
14
 
15
+ class NativeKeyEvent : public KeyEvent
16
+ {
17
+
18
+ public:
19
+
20
+ NativeKeyEvent (UIPress* press, Action action)
21
+ API_AVAILABLE(ios(13.4));
22
+
23
+ };// NativeKeyEvent
24
+
25
+
15
26
  class NativePointerEvent : public PointerEvent
16
27
  {
17
28
 
@@ -19,9 +30,22 @@ namespace Reflex
19
30
 
20
31
  NativePointerEvent (NSSet* touches, UIEvent* event, UIView* view);
21
32
 
33
+ NativePointerEvent (UIHoverGestureRecognizer* recognizer, UIView* view);
34
+
22
35
  };// NativePointerEvent
23
36
 
24
37
 
38
+ class NativeWheelEvent : public WheelEvent
39
+ {
40
+
41
+ public:
42
+
43
+ NativeWheelEvent (
44
+ UIPanGestureRecognizer* recognizer, UIView* view, CGPoint position);
45
+
46
+ };// NativeWheelEvent
47
+
48
+
25
49
  }// Reflex
26
50
 
27
51
 
data/src/ios/event.mm CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
 
5
5
  #include <assert.h>
6
+ #include <xot/util.h>
6
7
  #include "window.h"
7
8
 
8
9
 
@@ -11,7 +12,23 @@ namespace Reflex
11
12
 
12
13
 
13
14
  static uint
14
- get_type (UITouch* touch)
15
+ get_mouse_button_types (UIEvent* event)
16
+ {
17
+ if (!event) return 0;
18
+
19
+ uint ret = 0;
20
+ if (@available(iOS 13.4, *))
21
+ {
22
+ UIEventButtonMask mask = event.buttonMask;
23
+ if (mask & UIEventButtonMaskPrimary) ret |= Pointer::MOUSE_LEFT;
24
+ if (mask & UIEventButtonMaskSecondary) ret |= Pointer::MOUSE_RIGHT;
25
+ if (mask & UIEventButtonMaskForButtonNumber(3)) ret |= Pointer::MOUSE_MIDDLE;
26
+ }
27
+ return ret;
28
+ }
29
+
30
+ static uint
31
+ get_type (UITouch* touch, UIEvent* event)
15
32
  {
16
33
  assert(touch);
17
34
 
@@ -22,8 +39,15 @@ namespace Reflex
22
39
  {
23
40
  case UITouchTypeDirect: return Pointer::TOUCH;
24
41
  case UITouchTypePencil: return Pointer::PEN;
25
- default: return Pointer::TYPE_NONE;
26
42
  }
43
+
44
+ if (@available(iOS 13.4, *))
45
+ {
46
+ if (type == UITouchTypeIndirectPointer)
47
+ return Pointer::MOUSE | get_mouse_button_types(event);
48
+ }
49
+
50
+ return Pointer::TYPE_NONE;
27
51
  }
28
52
 
29
53
  static Pointer::Action
@@ -52,14 +76,8 @@ namespace Reflex
52
76
  }
53
77
 
54
78
  static uint
55
- get_modifiers (const UIEvent* event)
79
+ to_modifiers (NSInteger flags)
56
80
  {
57
- if (!event) return 0;
58
-
59
- NSInteger flags = 0;
60
- if (@available(iOS 13.4, *))
61
- flags = event.modifierFlags;
62
-
63
81
  return
64
82
  (flags & UIKeyModifierAlphaShift) ? MOD_CAPS : 0 |
65
83
  (flags & UIKeyModifierShift) ? MOD_SHIFT : 0 |
@@ -69,6 +87,18 @@ namespace Reflex
69
87
  (flags & UIKeyModifierNumericPad) ? MOD_NUMPAD : 0;
70
88
  }
71
89
 
90
+ static uint
91
+ get_modifiers (const UIEvent* event)
92
+ {
93
+ if (!event) return 0;
94
+
95
+ NSInteger flags = 0;
96
+ if (@available(iOS 13.4, *))
97
+ flags = event.modifierFlags;
98
+
99
+ return to_modifiers(flags);
100
+ }
101
+
72
102
  uint
73
103
  KeyEvent_get_modifiers ()
74
104
  {
@@ -76,25 +106,45 @@ namespace Reflex
76
106
  }
77
107
 
78
108
 
109
+ static const char*
110
+ get_chars (UIKey* key) API_AVAILABLE(ios(13.4))
111
+ {
112
+ NSString* s = key.characters;
113
+ if (!s || [s hasPrefix: @"UIKeyInput"])
114
+ return NULL;
115
+ return s.UTF8String;
116
+ }
117
+
118
+ NativeKeyEvent::NativeKeyEvent (UIPress* press, Action action)
119
+ : KeyEvent(
120
+ action, get_chars(press.key), (int) press.key.keyCode,
121
+ to_modifiers(press.key.modifierFlags), 0)
122
+ {
123
+ }
124
+
125
+
79
126
  NativePointerEvent::NativePointerEvent (
80
127
  NSSet* touches, UIEvent* event, UIView* view)
81
128
  {
82
129
  for (UITouch* touch in touches)
83
130
  {
84
131
  Pointer::Action action = get_action(touch);
132
+ uint type = get_type(touch, event);
85
133
 
86
134
  Pointer pointer(
87
135
  0,
88
- get_type(touch),
136
+ type,
89
137
  action,
90
138
  to_point([touch locationInView: view]),
91
139
  get_modifiers(event),
92
140
  (uint) touch.tapCount,
93
141
  action == Pointer::MOVE,
94
142
  touch.timestamp);
95
- Pointer_set_system_id(&pointer, (Pointer::ID) touch);
96
143
 
97
- if (pointer.action() != Pointer::DOWN)
144
+ if (!(type & Pointer::MOUSE))
145
+ Pointer_set_system_id(&pointer, (Pointer::ID) touch);
146
+
147
+ if (action != Pointer::DOWN)
98
148
  {
99
149
  Pointer_set_prev_position(
100
150
  &pointer, to_point([touch previousLocationInView: view]));
@@ -105,5 +155,38 @@ namespace Reflex
105
155
  }
106
156
  }
107
157
 
158
+ NativePointerEvent::NativePointerEvent (
159
+ UIHoverGestureRecognizer* recognizer, UIView* view)
160
+ {
161
+ assert(recognizer && view);
162
+
163
+ Pointer pointer(
164
+ 0,
165
+ Pointer::MOUSE,
166
+ Pointer::MOVE,
167
+ to_point([recognizer locationInView: view]),
168
+ get_modifiers(nil),
169
+ 0,
170
+ false,
171
+ Xot::time());
172
+
173
+ if (pointer)
174
+ PointerEvent_add_pointer(this, pointer);
175
+ }
176
+
177
+
178
+ NativeWheelEvent::NativeWheelEvent (
179
+ UIPanGestureRecognizer* recognizer, UIView* view, CGPoint position)
180
+ : WheelEvent(0, 0, 0, 0, 0, 0, get_modifiers(nil))
181
+ {
182
+ assert(recognizer && view);
183
+
184
+ WheelEvent_set_position(this, to_point(position));
185
+
186
+ CGPoint delta = [recognizer translationInView: view];
187
+ this->dposition().x = delta.x;
188
+ this->dposition().y = delta.y;
189
+ }
190
+
108
191
 
109
192
  }// Reflex
@@ -121,12 +121,14 @@ ReflexViewController_get_show_fun ()
121
121
  @end
122
122
 
123
123
 
124
- @interface ReflexViewController () <GLKViewDelegate>
124
+ @interface ReflexViewController () <GLKViewDelegate, UIGestureRecognizerDelegate>
125
125
 
126
126
  @property(nonatomic, strong) ReflexView* reflexView;
127
127
 
128
128
  @property(nonatomic, strong) CADisplayLink* displayLink;
129
129
 
130
+ @property(nonatomic, strong) UIHoverGestureRecognizer* hoverRecognizer;
131
+
130
132
  @end
131
133
 
132
134
 
@@ -264,10 +266,36 @@ ReflexViewController_get_show_fun ()
264
266
  //view.drawableMultisample = GLKViewDrawableMultisample4X;
265
267
 
266
268
  [self.view addSubview: view];
269
+ [self setupMouseRecognizers: view];
267
270
 
268
271
  self.reflexView = view;
269
272
  }
270
273
 
274
+ - (void) setupMouseRecognizers: (UIView*) view
275
+ {
276
+ if (@available(iOS 13.4, *))
277
+ {
278
+ UIHoverGestureRecognizer* hover = [[[UIHoverGestureRecognizer alloc]
279
+ initWithTarget: self action: @selector(hoverChanged:)]
280
+ autorelease];
281
+ hover.delegate = self;
282
+ [view addGestureRecognizer: hover];
283
+ self.hoverRecognizer = hover;
284
+
285
+ UIPanGestureRecognizer* pan = [[[UIPanGestureRecognizer alloc]
286
+ initWithTarget: self action: @selector(scrollChanged:)]
287
+ autorelease];
288
+ pan.allowedScrollTypesMask = UIScrollTypeMaskAll;
289
+ // 0/0 touches means the recognizer only fires from indirect scroll
290
+ // (mouse wheel / trackpad scroll) — touch-based panning is left to
291
+ // the touchesBegan/etc. path so this won't intercept finger pans.
292
+ pan.minimumNumberOfTouches = 0;
293
+ pan.maximumNumberOfTouches = 0;
294
+ pan.delegate = self;
295
+ [view addGestureRecognizer: pan];
296
+ }
297
+ }
298
+
271
299
  - (void) cleanupReflexView
272
300
  {
273
301
  ReflexView* view = self.reflexView;
@@ -299,10 +327,14 @@ ReflexViewController_get_show_fun ()
299
327
  selector: @selector(willResignActive)
300
328
  name: UIApplicationWillResignActiveNotification
301
329
  object: nil];
330
+
331
+ [self becomeFirstResponder];
302
332
  }
303
333
 
304
334
  - (void) viewDidDisappear: (BOOL) animated
305
335
  {
336
+ [self resignFirstResponder];
337
+
306
338
  [NSNotificationCenter.defaultCenter
307
339
  removeObserver: self
308
340
  name: UIApplicationDidBecomeActiveNotification
@@ -334,6 +366,11 @@ ReflexViewController_get_show_fun ()
334
366
  self.reflexView.frame = self.view.bounds;
335
367
  }
336
368
 
369
+ - (BOOL) canBecomeFirstResponder
370
+ {
371
+ return YES;
372
+ }
373
+
337
374
  - (void) startTimer
338
375
  {
339
376
  [self startTimer: 60];
@@ -509,4 +546,99 @@ ReflexViewController_get_show_fun ()
509
546
  Window_call_pointer_event(win, &e);
510
547
  }
511
548
 
549
+ - (void) hoverChanged: (UIHoverGestureRecognizer*) recognizer
550
+ API_AVAILABLE(ios(13.4))
551
+ {
552
+ Reflex::Window* win = self.window;
553
+ if (!win) return;
554
+
555
+ if (touching_count > 0) return;
556
+
557
+ if (
558
+ recognizer.state != UIGestureRecognizerStateBegan &&
559
+ recognizer.state != UIGestureRecognizerStateChanged)
560
+ {
561
+ return;
562
+ }
563
+
564
+ Reflex::NativePointerEvent e(recognizer, self.reflexView);
565
+ if (e.size() > 0)
566
+ Window_call_pointer_event(win, &e);
567
+ }
568
+
569
+ - (void) scrollChanged: (UIPanGestureRecognizer*) recognizer
570
+ API_AVAILABLE(ios(13.4))
571
+ {
572
+ Reflex::Window* win = self.window;
573
+ if (!win) return;
574
+
575
+ if (
576
+ recognizer.state != UIGestureRecognizerStateBegan &&
577
+ recognizer.state != UIGestureRecognizerStateChanged)
578
+ {
579
+ return;
580
+ }
581
+
582
+ // The pan recognizer's locationInView drifts with the synthetic scroll
583
+ // touch, so use the hover recognizer's location — it tracks the actual
584
+ // cursor and exposes the last known position regardless of its state.
585
+ CGPoint pos = [self.hoverRecognizer locationInView: self.reflexView];
586
+
587
+ Reflex::NativeWheelEvent e(recognizer, self.reflexView, pos);
588
+ Window_call_wheel_event(win, &e);
589
+
590
+ // reset translation so subsequent deltas are incremental
591
+ [recognizer setTranslation: CGPointZero inView: self.reflexView];
592
+ }
593
+
594
+ - (BOOL) gestureRecognizer: (UIGestureRecognizer*) recognizer
595
+ shouldRecognizeSimultaneouslyWithGestureRecognizer: (UIGestureRecognizer*) other
596
+ {
597
+ // UIKit only calls this delegate method when at least one of the two
598
+ // recognizers has us set as its delegate, and we only set ourselves as
599
+ // the delegate for our mouse recognizers (hover / indirect scroll). So
600
+ // every call here already involves one of ours, and we want it to run
601
+ // alongside whatever else is on the view (touches, app-added gestures).
602
+ return YES;
603
+ }
604
+
605
+ - (void) pressesBegan: (NSSet<UIPress*>*) presses
606
+ withEvent: (UIPressesEvent*) event
607
+ {
608
+ if (@available(iOS 13.4, *))
609
+ [self handlePresses: presses action: Reflex::KeyEvent::DOWN];
610
+ [super pressesBegan: presses withEvent: event];
611
+ }
612
+
613
+ - (void) pressesEnded: (NSSet<UIPress*>*) presses
614
+ withEvent: (UIPressesEvent*) event
615
+ {
616
+ if (@available(iOS 13.4, *))
617
+ [self handlePresses: presses action: Reflex::KeyEvent::UP];
618
+ [super pressesEnded: presses withEvent: event];
619
+ }
620
+
621
+ - (void) pressesCancelled: (NSSet<UIPress*>*) presses
622
+ withEvent: (UIPressesEvent*) event
623
+ {
624
+ if (@available(iOS 13.4, *))
625
+ [self handlePresses: presses action: Reflex::KeyEvent::UP];
626
+ [super pressesCancelled: presses withEvent: event];
627
+ }
628
+
629
+ - (void) handlePresses: (NSSet<UIPress*>*) presses
630
+ action: (Reflex::KeyEvent::Action) action
631
+ API_AVAILABLE(ios(13.4))
632
+ {
633
+ Reflex::Window* win = self.window;
634
+ if (!win) return;
635
+
636
+ for (UIPress* press in presses)
637
+ {
638
+ if (!press.key) continue;
639
+ Reflex::NativeKeyEvent e(press, action);
640
+ Window_call_key_event(win, &e);
641
+ }
642
+ }
643
+
512
644
  @end// ReflexViewController
data/src/osx/event.mm CHANGED
@@ -163,7 +163,7 @@ namespace Reflex
163
163
 
164
164
 
165
165
  NativeWheelEvent::NativeWheelEvent (NSEvent* e, NSView* view)
166
- : WheelEvent(0, 0, 0, [e deltaX], [e deltaY], [e deltaZ], get_modifiers(e))
166
+ : WheelEvent(0, 0, 0, [e deltaX], -[e deltaY], [e deltaZ], get_modifiers(e))
167
167
  {
168
168
  WheelEvent_set_position(this, get_pointer_position(e, view));
169
169
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reflexion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.15
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - xordog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-09 00:00:00.000000000 Z
11
+ date: 2026-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xot
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.12
19
+ version: 0.3.13
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.12
26
+ version: 0.3.13
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rucy
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.3.12
33
+ version: 0.3.13
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.3.12
40
+ version: 0.3.13
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rays
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.3.12
47
+ version: 0.3.13
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.3.12
54
+ version: 0.3.13
55
55
  description: This library helps you to develop interactive graphical user interface.
56
56
  email: xordog@gmail.com
57
57
  executables: []