mouse 1.1.0 → 2.0.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/History.markdown +10 -0
- data/README.markdown +31 -0
- data/ext/mouse/CGEventAdditions.h +227 -0
- data/ext/mouse/IOHIDEventTypes.h +617 -0
- data/ext/mouse/mouse.c +326 -30
- data/ext/mouse/mouser.c +251 -18
- data/ext/mouse/mouser.h +21 -0
- data/lib/mouse.rb +3 -71
- data/lib/mouse/core_extensions.rb +29 -0
- data/lib/mouse/core_extensions/macruby.rb +10 -0
- data/lib/mouse/core_extensions/mri.rb +31 -0
- data/lib/mouse/version.rb +1 -1
- metadata +7 -2
data/ext/mouse/mouse.c
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
#include "mouser.h"
|
2
2
|
#include "ruby.h"
|
3
3
|
|
4
|
-
static VALUE rb_mMouse;
|
5
|
-
|
6
|
-
static ID sel_x;
|
7
|
-
|
8
|
-
static
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
static VALUE rb_mMouse, rb_cCGPoint;
|
5
|
+
|
6
|
+
static ID sel_x, sel_y, sel_to_point, sel_new;
|
7
|
+
|
8
|
+
static VALUE sym_pixel, sym_line,
|
9
|
+
sym_up, sym_down, sym_left, sym_right,
|
10
|
+
sym_zoom, sym_unzoom, sym_expand, sym_contract,
|
11
|
+
sym_cw, sym_clockwise, sym_clock_wise,
|
12
|
+
sym_ccw, sym_counter_clockwise, sym_counter_clock_wise;
|
12
13
|
|
13
14
|
#define CURRENT_POSITION rb_mouse_wrap_point(mouse_current_position())
|
14
15
|
|
@@ -16,7 +17,6 @@ static
|
|
16
17
|
VALUE
|
17
18
|
rb_mouse_wrap_point(CGPoint point)
|
18
19
|
{
|
19
|
-
// TODO: Data_Wrap_Struct instead
|
20
20
|
#if NOT_MACRUBY
|
21
21
|
return rb_struct_new(rb_cCGPoint, DBL2NUM(point.x), DBL2NUM(point.y));
|
22
22
|
#else
|
@@ -118,8 +118,11 @@ rb_mouse_drag_to(int argc, VALUE *argv, VALUE self)
|
|
118
118
|
* Returns number of lines scrolled. A positive `amount` will scroll up
|
119
119
|
* and a negative `amount` will scroll down.
|
120
120
|
*
|
121
|
+
* An animation duration can also be specified.
|
122
|
+
*
|
121
123
|
* @param amount [Number]
|
122
124
|
* @param units [Symbol] `:pixel` or `:line` (_default_: `:line` ) (__optional__)
|
125
|
+
* @param duration [Float] (_default_: `0.2`) (__optional__)
|
123
126
|
* @return [Number]
|
124
127
|
*/
|
125
128
|
static
|
@@ -133,29 +136,71 @@ rb_mouse_scroll(int argc, VALUE *argv, VALUE self)
|
|
133
136
|
|
134
137
|
if (argc == 1) {
|
135
138
|
mouse_scroll(amt);
|
136
|
-
return argv[0];
|
137
|
-
}
|
138
139
|
|
139
|
-
|
140
|
+
} else {
|
141
|
+
VALUE input_units = argv[1];
|
142
|
+
CGScrollEventUnit units;
|
140
143
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
mouse_scroll2(amt, kCGScrollEventUnitLine);
|
144
|
+
if (input_units == sym_pixel)
|
145
|
+
units = kCGScrollEventUnitPixel;
|
146
|
+
else if (input_units == sym_line)
|
147
|
+
units = kCGScrollEventUnitLine;
|
146
148
|
else
|
147
|
-
rb_raise(rb_eArgError, "unknown units `%s'", rb_id2name(
|
149
|
+
rb_raise(rb_eArgError, "unknown units `%s'", rb_id2name(input_units));
|
150
|
+
|
151
|
+
if (argc == 2)
|
152
|
+
mouse_scroll2(amt, units);
|
153
|
+
else
|
154
|
+
mouse_scroll3(amt, units, NUM2DBL(argv[2]));
|
148
155
|
}
|
149
156
|
|
150
|
-
|
151
|
-
|
157
|
+
return argv[0];
|
158
|
+
}
|
159
|
+
|
160
|
+
/*
|
161
|
+
* @note Scrolling by `:pixel` may not actually be by real pixels, but instead
|
162
|
+
* correspond to Cocoa co-ords (I don't have a retina display, so I haven't
|
163
|
+
* checked it out yet).
|
164
|
+
*
|
165
|
+
* Generate `amount` of horizontal scroll events at the current cursor position
|
166
|
+
*
|
167
|
+
* Returns number of lines scrolled. A positive `amount` will scroll left
|
168
|
+
* and a negative `amount` will scroll right.
|
169
|
+
*
|
170
|
+
* An animation duration can also be specified.
|
171
|
+
*
|
172
|
+
* @param amount [Number]
|
173
|
+
* @param units [Symbol] `:pixel` or `:line` (_default_: `:line` ) (__optional__)
|
174
|
+
* @param duration [Float] (_default_: `0.2`) (__optional__)
|
175
|
+
* @return [Number]
|
176
|
+
*/
|
177
|
+
static
|
178
|
+
VALUE
|
179
|
+
rb_mouse_horizontal_scroll(int argc, VALUE *argv, VALUE self)
|
180
|
+
{
|
181
|
+
if (argc == 0 || argc > 3)
|
182
|
+
rb_raise(rb_eArgError, "scroll requires 1..3 arguments, you gave %d", argc);
|
183
|
+
|
184
|
+
int amt = NUM2INT(argv[0]);
|
152
185
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
186
|
+
if (argc == 1) {
|
187
|
+
mouse_horizontal_scroll(amt);
|
188
|
+
|
189
|
+
} else {
|
190
|
+
VALUE input_units = argv[1];
|
191
|
+
CGScrollEventUnit units;
|
192
|
+
|
193
|
+
if (input_units == sym_pixel)
|
194
|
+
units = kCGScrollEventUnitPixel;
|
195
|
+
else if (input_units == sym_line)
|
196
|
+
units = kCGScrollEventUnitLine;
|
157
197
|
else
|
158
|
-
rb_raise(rb_eArgError, "unknown units `%s'", rb_id2name(
|
198
|
+
rb_raise(rb_eArgError, "unknown units `%s'", rb_id2name(input_units));
|
199
|
+
|
200
|
+
if (argc == 2)
|
201
|
+
mouse_horizontal_scroll2(amt, units);
|
202
|
+
else
|
203
|
+
mouse_horizontal_scroll3(amt, units, NUM2DBL(argv[2]));
|
159
204
|
}
|
160
205
|
|
161
206
|
return argv[0];
|
@@ -574,6 +619,231 @@ rb_mouse_triple_click(int argc, VALUE *argv, VALUE self)
|
|
574
619
|
return CURRENT_POSITION;
|
575
620
|
}
|
576
621
|
|
622
|
+
|
623
|
+
/* @!group Gestures */
|
624
|
+
|
625
|
+
/*
|
626
|
+
* Perform a smart magnify (double tap on trackpad)
|
627
|
+
*
|
628
|
+
* You can optionally specify the point on the screen where to perform
|
629
|
+
* the smart magnification.
|
630
|
+
*
|
631
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
632
|
+
* @return [CGPoint]
|
633
|
+
*/
|
634
|
+
static
|
635
|
+
VALUE
|
636
|
+
rb_mouse_smart_magnify(int argc, VALUE* argv, VALUE self)
|
637
|
+
{
|
638
|
+
switch (argc)
|
639
|
+
{
|
640
|
+
case 0:
|
641
|
+
mouse_smart_magnify();
|
642
|
+
break;
|
643
|
+
case 1:
|
644
|
+
default:
|
645
|
+
mouse_smart_magnify2(rb_mouse_unwrap_point(argv[0]));
|
646
|
+
}
|
647
|
+
|
648
|
+
return CURRENT_POSITION;
|
649
|
+
}
|
650
|
+
|
651
|
+
/*
|
652
|
+
* Perform a swipe gesture in the given `direction`
|
653
|
+
*
|
654
|
+
* You can optionally specify a point on screen for the mouse
|
655
|
+
* pointer to be moved to before the gesture begins. The movement will
|
656
|
+
* be instantaneous.
|
657
|
+
*
|
658
|
+
* You can also optionally specify the duration of the swipe event.
|
659
|
+
*
|
660
|
+
* @param direction [Symbol]
|
661
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
662
|
+
* @param duration [Float] (_default_: `0.2`) (__optional__)
|
663
|
+
* @return [CGPoint]
|
664
|
+
*/
|
665
|
+
static
|
666
|
+
VALUE
|
667
|
+
rb_mouse_swipe(int argc, VALUE* argv, VALUE self)
|
668
|
+
{
|
669
|
+
if (!argc)
|
670
|
+
rb_raise(rb_eArgError, "wrong number of arguments (0 for 1+)");
|
671
|
+
|
672
|
+
CGSwipeDirection direction;
|
673
|
+
VALUE direction_input = argv[0];
|
674
|
+
if (direction_input == sym_up)
|
675
|
+
direction = kCGSwipeDirectionUp;
|
676
|
+
else if (direction_input == sym_down)
|
677
|
+
direction = kCGSwipeDirectionDown;
|
678
|
+
else if (direction_input == sym_left)
|
679
|
+
direction = kCGSwipeDirectionLeft;
|
680
|
+
else if (direction_input == sym_right)
|
681
|
+
direction = kCGSwipeDirectionRight;
|
682
|
+
else
|
683
|
+
rb_raise(
|
684
|
+
rb_eArgError,
|
685
|
+
"invalid swipe direction `%s'",
|
686
|
+
rb_id2name(SYM2ID(direction_input))
|
687
|
+
);
|
688
|
+
|
689
|
+
if (argc == 1) {
|
690
|
+
mouse_swipe(direction);
|
691
|
+
return CURRENT_POSITION;
|
692
|
+
}
|
693
|
+
|
694
|
+
CGPoint point = rb_mouse_unwrap_point(argv[1]);
|
695
|
+
|
696
|
+
if (argc == 2)
|
697
|
+
mouse_swipe2(direction, point);
|
698
|
+
else
|
699
|
+
mouse_swipe3(direction, point, NUM2DBL(argv[1]));
|
700
|
+
|
701
|
+
return CURRENT_POSITION;
|
702
|
+
}
|
703
|
+
|
704
|
+
/*
|
705
|
+
* Perform a pinch gesture in given `direction`
|
706
|
+
*
|
707
|
+
* You can optionally specify the `magnification` factor and/or
|
708
|
+
* `duration` for the pinch event.
|
709
|
+
*
|
710
|
+
* Available pinch directions are:
|
711
|
+
*
|
712
|
+
* - `:zoom` or `:expand`
|
713
|
+
* - `:unzoom` or `:contract`
|
714
|
+
*
|
715
|
+
* Magnification is a relative magnification setting. A zoom value of
|
716
|
+
* `1.0` means `1.0` more than the current zoom level. `2.0` would be
|
717
|
+
* `2.0` levels higher than the current zoom.
|
718
|
+
*
|
719
|
+
* You can also optionally specify a point on screen for the mouse
|
720
|
+
* pointer to be moved to before the gesture begins. The movement will
|
721
|
+
* be instantaneous.
|
722
|
+
*
|
723
|
+
* An animation duration can also be specified.
|
724
|
+
*
|
725
|
+
* @param direction [Symbol]
|
726
|
+
* @param magnification [Float] (_default_: `1.0`) (__optional__)
|
727
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
728
|
+
* @param duration [Float] (_default_: `0.2`) (__optional__)
|
729
|
+
* @return [CGPoint]
|
730
|
+
*/
|
731
|
+
static
|
732
|
+
VALUE
|
733
|
+
rb_mouse_pinch(int argc, VALUE* argv, VALUE self)
|
734
|
+
{
|
735
|
+
if (!argc)
|
736
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1+)", argc);
|
737
|
+
|
738
|
+
VALUE input_direction = argv[0];
|
739
|
+
CGPinchDirection direction = kCGPinchNone;
|
740
|
+
|
741
|
+
if (input_direction == sym_expand || input_direction == sym_zoom)
|
742
|
+
direction = kCGPinchExpand;
|
743
|
+
else if (input_direction == sym_contract || input_direction == sym_unzoom)
|
744
|
+
direction = kCGPinchContract;
|
745
|
+
else
|
746
|
+
rb_raise(
|
747
|
+
rb_eArgError,
|
748
|
+
"invalid pinch direction `%s'",
|
749
|
+
rb_id2name(SYM2ID(input_direction))
|
750
|
+
);
|
751
|
+
|
752
|
+
if (argc == 1) {
|
753
|
+
mouse_pinch(direction);
|
754
|
+
return CURRENT_POSITION;
|
755
|
+
}
|
756
|
+
|
757
|
+
double magnification = NUM2DBL(argv[1]);
|
758
|
+
if (argc == 2) {
|
759
|
+
mouse_pinch2(direction, magnification);
|
760
|
+
return CURRENT_POSITION;
|
761
|
+
}
|
762
|
+
|
763
|
+
CGPoint point = rb_mouse_unwrap_point(argv[2]);
|
764
|
+
if (argc == 3) {
|
765
|
+
mouse_pinch3(direction, magnification, point);
|
766
|
+
return CURRENT_POSITION;
|
767
|
+
}
|
768
|
+
|
769
|
+
double duration = NUM2DBL(argv[3]);
|
770
|
+
mouse_pinch4(direction, magnification, point, duration);
|
771
|
+
return CURRENT_POSITION;
|
772
|
+
}
|
773
|
+
|
774
|
+
/*
|
775
|
+
* Perform a rotation gesture in the given `direction` the given `angle` degrees
|
776
|
+
*
|
777
|
+
* Possible directions are:
|
778
|
+
*
|
779
|
+
* - `:cw`, ':clockwise`, ':clock_wise` to rotate in the clockwise
|
780
|
+
* direction
|
781
|
+
* - `:ccw`, ':counter_clockwise`, `:counter_clock_wise` to rotate in
|
782
|
+
* the the counter clockwise direction
|
783
|
+
*
|
784
|
+
* The `angle` parameter is a number of degrees to rotate. There are 360
|
785
|
+
* degrees in a full rotation, as you would expect in Euclidian geometry.
|
786
|
+
*
|
787
|
+
* You can also optionally specify a point on screen for the mouse
|
788
|
+
* pointer to be moved to before the gesture begins. The movement will
|
789
|
+
* be instantaneous.
|
790
|
+
*
|
791
|
+
* An animation duration can also be specified.
|
792
|
+
*
|
793
|
+
* @param direction [Symbol]
|
794
|
+
* @param angle [Float]
|
795
|
+
* @param point [CGPoint] (_default_: {#current_position}) (__optional__)
|
796
|
+
* @param duration [Float] (_default_: `0.2`) (__optional__)
|
797
|
+
* @return [CGPoint]
|
798
|
+
*/
|
799
|
+
static
|
800
|
+
VALUE
|
801
|
+
rb_mouse_rotate(int argc, VALUE* argv, VALUE self)
|
802
|
+
{
|
803
|
+
if (argc < 2)
|
804
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 2+)", argc);
|
805
|
+
|
806
|
+
CGRotateDirection direction = kCGRotateNone;
|
807
|
+
VALUE input_dir = argv[0];
|
808
|
+
if (
|
809
|
+
input_dir == sym_cw ||
|
810
|
+
input_dir == sym_clockwise ||
|
811
|
+
input_dir == sym_clock_wise
|
812
|
+
)
|
813
|
+
direction = kCGRotateClockwise;
|
814
|
+
else if (
|
815
|
+
input_dir == sym_ccw ||
|
816
|
+
input_dir == sym_counter_clockwise ||
|
817
|
+
input_dir == sym_counter_clock_wise
|
818
|
+
)
|
819
|
+
direction = kCGRotateCounterClockwise;
|
820
|
+
else
|
821
|
+
rb_raise(
|
822
|
+
rb_eArgError,
|
823
|
+
"invalid rotation direction `%s'",
|
824
|
+
rb_id2name(SYM2ID(input_dir))
|
825
|
+
);
|
826
|
+
|
827
|
+
double angle = NUM2DBL(argv[1]);
|
828
|
+
|
829
|
+
if (argc == 2) {
|
830
|
+
mouse_rotate(direction, angle);
|
831
|
+
return CURRENT_POSITION;
|
832
|
+
}
|
833
|
+
|
834
|
+
CGPoint point = rb_mouse_unwrap_point(argv[2]);
|
835
|
+
if (argc == 3) {
|
836
|
+
mouse_rotate2(direction, angle, point);
|
837
|
+
return CURRENT_POSITION;
|
838
|
+
}
|
839
|
+
|
840
|
+
mouse_rotate3(direction, angle, point, NUM2DBL(argv[3]));
|
841
|
+
return CURRENT_POSITION;
|
842
|
+
}
|
843
|
+
|
844
|
+
/* @!endgroup */
|
845
|
+
|
846
|
+
|
577
847
|
void
|
578
848
|
Init_mouse()
|
579
849
|
{
|
@@ -585,8 +855,26 @@ Init_mouse()
|
|
585
855
|
sel_to_point = rb_intern("to_point");
|
586
856
|
sel_new = rb_intern("new");
|
587
857
|
|
588
|
-
|
589
|
-
|
858
|
+
sym_pixel = ID2SYM(rb_intern("pixel"));
|
859
|
+
sym_line = ID2SYM(rb_intern("line"));
|
860
|
+
|
861
|
+
sym_up = ID2SYM(rb_intern("up"));
|
862
|
+
sym_down = ID2SYM(rb_intern("down"));
|
863
|
+
sym_left = ID2SYM(rb_intern("left"));
|
864
|
+
sym_right = ID2SYM(rb_intern("right"));
|
865
|
+
|
866
|
+
sym_zoom = ID2SYM(rb_intern("zoom"));
|
867
|
+
sym_unzoom = ID2SYM(rb_intern("unzoom"));
|
868
|
+
sym_expand = ID2SYM(rb_intern("expand"));
|
869
|
+
sym_contract = ID2SYM(rb_intern("contract"));
|
870
|
+
|
871
|
+
sym_cw = ID2SYM(rb_intern("cw"));
|
872
|
+
sym_clockwise = ID2SYM(rb_intern("clockwise"));
|
873
|
+
sym_clock_wise = ID2SYM(rb_intern("clock_wise"));
|
874
|
+
sym_ccw = ID2SYM(rb_intern("ccw"));
|
875
|
+
sym_counter_clockwise = ID2SYM(rb_intern("counter_clockwise"));
|
876
|
+
sym_counter_clock_wise = ID2SYM(rb_intern("counter_clock_wise"));
|
877
|
+
|
590
878
|
|
591
879
|
/*
|
592
880
|
* Document-module: Mouse
|
@@ -611,6 +899,7 @@ Init_mouse()
|
|
611
899
|
rb_define_method(rb_mMouse, "move_to", rb_mouse_move_to, -1);
|
612
900
|
rb_define_method(rb_mMouse, "drag_to", rb_mouse_drag_to, -1);
|
613
901
|
rb_define_method(rb_mMouse, "scroll", rb_mouse_scroll, -1);
|
902
|
+
rb_define_method(rb_mMouse, "horizontal_scroll", rb_mouse_horizontal_scroll, -1);
|
614
903
|
rb_define_method(rb_mMouse, "click_down", rb_mouse_click_down, -1);
|
615
904
|
rb_define_method(rb_mMouse, "click_up", rb_mouse_click_up, -1);
|
616
905
|
rb_define_method(rb_mMouse, "click", rb_mouse_click, -1);
|
@@ -625,7 +914,14 @@ Init_mouse()
|
|
625
914
|
rb_define_method(rb_mMouse, "double_click", rb_mouse_double_click, -1);
|
626
915
|
rb_define_method(rb_mMouse, "triple_click", rb_mouse_triple_click, -1);
|
627
916
|
|
628
|
-
|
629
|
-
|
630
|
-
|
917
|
+
rb_define_method(rb_mMouse, "smart_magnify", rb_mouse_smart_magnify, -1);
|
918
|
+
rb_define_method(rb_mMouse, "swipe", rb_mouse_swipe, -1);
|
919
|
+
rb_define_method(rb_mMouse, "pinch", rb_mouse_pinch, -1);
|
920
|
+
rb_define_method(rb_mMouse, "rotate", rb_mouse_rotate, -1);
|
921
|
+
|
922
|
+
rb_define_alias(rb_mMouse, "hscroll", "horizontal_scroll");
|
923
|
+
rb_define_alias(rb_mMouse, "right_click_down", "secondary_click_down");
|
924
|
+
rb_define_alias(rb_mMouse, "right_click_up", "secondary_click_up");
|
925
|
+
rb_define_alias(rb_mMouse, "right_click", "secondary_click");
|
926
|
+
rb_define_alias(rb_mMouse, "two_finger_double_tap", "smart_magnify");
|
631
927
|
}
|
data/ext/mouse/mouser.c
CHANGED
@@ -9,10 +9,12 @@
|
|
9
9
|
#include <ApplicationServices/ApplicationServices.h>
|
10
10
|
#include "mouser.h"
|
11
11
|
|
12
|
-
static const uint_t FPS
|
13
|
-
static const uint_t QUANTUM
|
14
|
-
static const double DEFAULT_DURATION
|
12
|
+
static const uint_t FPS = 240;
|
13
|
+
static const uint_t QUANTUM = 1000000 / 240; // should be FPS, but GCC sucks
|
14
|
+
static const double DEFAULT_DURATION = 0.2; // seconds
|
15
|
+
static const double DEFAULT_MAGNIFICATION = 1.0; // factor
|
15
16
|
|
17
|
+
#define NEW_GESTURE(name) CGEventRef name = CGEventCreate(nil); CHANGE(name, kCGEventGesture);
|
16
18
|
#define NEW_EVENT(type,point,button) CGEventCreateMouseEvent(nil,type,point,button)
|
17
19
|
#define POST(event) CGEventPost(kCGHIDEventTap, event)
|
18
20
|
#define CHANGE(event,type) CGEventSetType(event, type)
|
@@ -27,9 +29,9 @@ static const double DEFAULT_DURATION = 0.2; // seconds
|
|
27
29
|
#endif
|
28
30
|
|
29
31
|
#define POSTRELEASE(x) do { \
|
30
|
-
CGEventRef
|
31
|
-
POST(
|
32
|
-
RELEASE(
|
32
|
+
CGEventRef _event = x; \
|
33
|
+
POST(_event); \
|
34
|
+
RELEASE(_event); \
|
33
35
|
} while(false);
|
34
36
|
|
35
37
|
|
@@ -147,21 +149,25 @@ mouse_drag_to(CGPoint point)
|
|
147
149
|
}
|
148
150
|
|
149
151
|
|
152
|
+
#define SCROLL(vval, hval) do { \
|
153
|
+
size_t steps = round(FPS * duration); \
|
154
|
+
double current = 0.0; \
|
155
|
+
double done = 0.0; \
|
156
|
+
int32_t scroll = 0; \
|
157
|
+
\
|
158
|
+
for (size_t step = 0; step < steps; step++) { \
|
159
|
+
done = (double)(step+1) / (double)steps; \
|
160
|
+
scroll = round((done - current) * amount); \
|
161
|
+
POSTRELEASE(CGEventCreateScrollWheelEvent(nil, units, 2, vval, hval)); \
|
162
|
+
mouse_sleep(2); \
|
163
|
+
current += (double)scroll / (double)amount; \
|
164
|
+
} \
|
165
|
+
} while (false);
|
166
|
+
|
150
167
|
void
|
151
168
|
mouse_scroll3(int amount, CGScrollEventUnit units, double duration)
|
152
169
|
{
|
153
|
-
|
154
|
-
double current = 0.0;
|
155
|
-
double done = 0.0;
|
156
|
-
int32_t scroll = 0;
|
157
|
-
|
158
|
-
for (size_t step = 0; step < steps; step++) {
|
159
|
-
done = (double)(step+1) / (double)steps;
|
160
|
-
scroll = round((done - current) * amount);
|
161
|
-
POSTRELEASE(CGEventCreateScrollWheelEvent(nil, units, 1, scroll));
|
162
|
-
mouse_sleep(2);
|
163
|
-
current += (double)scroll / (double)amount;
|
164
|
-
}
|
170
|
+
SCROLL(scroll, 0);
|
165
171
|
}
|
166
172
|
|
167
173
|
void
|
@@ -176,6 +182,23 @@ mouse_scroll(int amount)
|
|
176
182
|
mouse_scroll2(amount, kCGScrollEventUnitLine);
|
177
183
|
}
|
178
184
|
|
185
|
+
void
|
186
|
+
mouse_horizontal_scroll3(int amount, CGScrollEventUnit units, double duration)
|
187
|
+
{
|
188
|
+
SCROLL(0, scroll);
|
189
|
+
}
|
190
|
+
|
191
|
+
void
|
192
|
+
mouse_horizontal_scroll2(int amount, CGScrollEventUnit units)
|
193
|
+
{
|
194
|
+
mouse_horizontal_scroll3(amount, units, DEFAULT_DURATION);
|
195
|
+
}
|
196
|
+
|
197
|
+
void
|
198
|
+
mouse_horizontal_scroll(int amount)
|
199
|
+
{
|
200
|
+
mouse_horizontal_scroll2(amount, kCGScrollEventUnitLine);
|
201
|
+
}
|
179
202
|
|
180
203
|
void
|
181
204
|
mouse_click_down3(CGPoint point, uint_t sleep_quanta)
|
@@ -423,3 +446,213 @@ mouse_triple_click()
|
|
423
446
|
{
|
424
447
|
mouse_triple_click2(mouse_current_position());
|
425
448
|
}
|
449
|
+
|
450
|
+
|
451
|
+
static
|
452
|
+
void
|
453
|
+
mouse_gesture(CGPoint point, uint_t sleep_quanta, void (^gesture_block)(void))
|
454
|
+
{
|
455
|
+
POSTRELEASE(NEW_EVENT(kCGEventMouseMoved, point, kCGMouseButtonLeft));
|
456
|
+
|
457
|
+
NEW_GESTURE(gesture);
|
458
|
+
CGEventSetIntegerValueField(
|
459
|
+
gesture,
|
460
|
+
kCGEventGestureType,
|
461
|
+
kCGGestureTypeGestureStarted
|
462
|
+
);
|
463
|
+
POST(gesture);
|
464
|
+
|
465
|
+
gesture_block();
|
466
|
+
|
467
|
+
CGEventSetIntegerValueField(gesture, kCGEventGestureType, kCGGestureTypeGestureEnded);
|
468
|
+
POSTRELEASE(gesture);
|
469
|
+
|
470
|
+
mouse_sleep(sleep_quanta);
|
471
|
+
}
|
472
|
+
|
473
|
+
void
|
474
|
+
mouse_smart_magnify2(CGPoint point)
|
475
|
+
{
|
476
|
+
mouse_gesture(point, (FPS / 2), ^(void) {
|
477
|
+
NEW_GESTURE(event);
|
478
|
+
CGEventSetIntegerValueField(event, kCGEventGestureType, kCGGestureTypeSmartMagnify);
|
479
|
+
POSTRELEASE(event);
|
480
|
+
});
|
481
|
+
}
|
482
|
+
|
483
|
+
void
|
484
|
+
mouse_smart_magnify()
|
485
|
+
{
|
486
|
+
mouse_smart_magnify2(mouse_current_position());
|
487
|
+
}
|
488
|
+
|
489
|
+
void
|
490
|
+
mouse_swipe3(
|
491
|
+
CGSwipeDirection direction,
|
492
|
+
CGPoint point,
|
493
|
+
double duration
|
494
|
+
)
|
495
|
+
{
|
496
|
+
uint16_t axis = 0;
|
497
|
+
CGFloat distance = 1.0;
|
498
|
+
CGGestureMotion motion = kCGGestureMotionNone;
|
499
|
+
|
500
|
+
switch (direction)
|
501
|
+
{
|
502
|
+
case kCGSwipeDirectionUp:
|
503
|
+
axis = kCGEventGestureSwipePositionY;
|
504
|
+
motion = kCGGestureMotionVertical;
|
505
|
+
distance = -(distance);
|
506
|
+
break;
|
507
|
+
case kCGSwipeDirectionDown:
|
508
|
+
axis = kCGEventGestureSwipePositionY;
|
509
|
+
motion = kCGGestureMotionVertical;
|
510
|
+
break;
|
511
|
+
case kCGSwipeDirectionLeft:
|
512
|
+
axis = kCGEventGestureSwipePositionX;
|
513
|
+
motion = kCGGestureMotionHorizontal;
|
514
|
+
break;
|
515
|
+
case kCGSwipeDirectionRight:
|
516
|
+
axis = kCGEventGestureSwipePositionX;
|
517
|
+
motion = kCGGestureMotionHorizontal;
|
518
|
+
distance = -(distance);
|
519
|
+
break;
|
520
|
+
default:
|
521
|
+
return;
|
522
|
+
}
|
523
|
+
|
524
|
+
mouse_gesture(point, (FPS / 10), ^(void) {
|
525
|
+
NEW_GESTURE(swipe);
|
526
|
+
|
527
|
+
CGEventSetIntegerValueField(swipe, kCGEventGestureType, kCGGestureTypeSwipe);
|
528
|
+
CGEventSetIntegerValueField(swipe, kCGEventGestureSwipeMotion, motion);
|
529
|
+
CGEventSetIntegerValueField(swipe, kCGEventGestureSwipeDirection, direction);
|
530
|
+
CGEventSetIntegerValueField(swipe, kCGEventGesturePhase, kCGGesturePhaseBegan);
|
531
|
+
CGEventSetDoubleValueField( swipe, kCGEventGestureSwipeProgress, distance);
|
532
|
+
CGEventSetDoubleValueField( swipe, axis, distance);
|
533
|
+
|
534
|
+
// TODO: animation steps don't seem to do anything...
|
535
|
+
// kCGGesturePhaseChanged
|
536
|
+
// kCGGesturePhaseEnded
|
537
|
+
|
538
|
+
POSTRELEASE(swipe);
|
539
|
+
});
|
540
|
+
}
|
541
|
+
|
542
|
+
void
|
543
|
+
mouse_swipe2(CGSwipeDirection direction, CGPoint point)
|
544
|
+
{
|
545
|
+
mouse_swipe3(direction, point, DEFAULT_DURATION);
|
546
|
+
}
|
547
|
+
|
548
|
+
void
|
549
|
+
mouse_swipe(CGSwipeDirection direction)
|
550
|
+
{
|
551
|
+
mouse_swipe2(direction, mouse_current_position());
|
552
|
+
}
|
553
|
+
|
554
|
+
void
|
555
|
+
mouse_pinch4(
|
556
|
+
CGPinchDirection direction,
|
557
|
+
double magnification,
|
558
|
+
CGPoint point,
|
559
|
+
double duration
|
560
|
+
)
|
561
|
+
{
|
562
|
+
switch (direction)
|
563
|
+
{
|
564
|
+
case kCGPinchExpand:
|
565
|
+
break;
|
566
|
+
case kCGPinchContract:
|
567
|
+
magnification = -(magnification);
|
568
|
+
break;
|
569
|
+
default:
|
570
|
+
return;
|
571
|
+
}
|
572
|
+
|
573
|
+
mouse_gesture(point, FPS / 10, ^(void) {
|
574
|
+
NEW_GESTURE(pinch);
|
575
|
+
CGEventSetIntegerValueField(pinch, kCGEventGestureType, kCGGestureTypePinch);
|
576
|
+
|
577
|
+
size_t steps = FPS / duration;
|
578
|
+
double step_size = magnification / steps;
|
579
|
+
double step_period = (duration / steps) * 1000000;
|
580
|
+
|
581
|
+
CGEventSetDoubleValueField(pinch, kCGEventGesturePinchValue, step_size);
|
582
|
+
|
583
|
+
for (size_t i = 0; i < steps; i++) {
|
584
|
+
POST(pinch);
|
585
|
+
usleep(step_period);
|
586
|
+
}
|
587
|
+
|
588
|
+
RELEASE(pinch);
|
589
|
+
});
|
590
|
+
}
|
591
|
+
|
592
|
+
void
|
593
|
+
mouse_pinch3(CGPinchDirection direction, double magnification, CGPoint point)
|
594
|
+
{
|
595
|
+
mouse_pinch4(direction, magnification, point, DEFAULT_DURATION);
|
596
|
+
}
|
597
|
+
|
598
|
+
void
|
599
|
+
mouse_pinch2(CGPinchDirection direction, double magnification)
|
600
|
+
{
|
601
|
+
mouse_pinch3(direction, magnification, mouse_current_position());
|
602
|
+
}
|
603
|
+
|
604
|
+
void
|
605
|
+
mouse_pinch(CGPinchDirection direction)
|
606
|
+
{
|
607
|
+
mouse_pinch2(direction, DEFAULT_MAGNIFICATION);
|
608
|
+
}
|
609
|
+
|
610
|
+
void
|
611
|
+
mouse_rotate3(
|
612
|
+
CGRotateDirection direction,
|
613
|
+
double angle,
|
614
|
+
CGPoint point,
|
615
|
+
double duration
|
616
|
+
)
|
617
|
+
{
|
618
|
+
switch (direction)
|
619
|
+
{
|
620
|
+
case kCGRotateClockwise:
|
621
|
+
angle = -(angle);
|
622
|
+
break;
|
623
|
+
case kCGRotateCounterClockwise:
|
624
|
+
break;
|
625
|
+
default:
|
626
|
+
return;
|
627
|
+
}
|
628
|
+
|
629
|
+
mouse_gesture(point, (FPS / 10), ^(void) {
|
630
|
+
NEW_GESTURE(rotation);
|
631
|
+
CGEventSetIntegerValueField(rotation, kCGEventGestureType, kCGGestureTypeRotation);
|
632
|
+
|
633
|
+
size_t steps = FPS / duration;
|
634
|
+
double step_size = angle / steps;
|
635
|
+
double step_period = (duration / steps) * 1000000;
|
636
|
+
|
637
|
+
CGEventSetDoubleValueField(rotation, kCGEventGestureRotationValue, step_size);
|
638
|
+
|
639
|
+
for (size_t i = 0; i < steps; i++) {
|
640
|
+
POST(rotation);
|
641
|
+
usleep(step_period);
|
642
|
+
}
|
643
|
+
|
644
|
+
RELEASE(rotation);
|
645
|
+
});
|
646
|
+
}
|
647
|
+
|
648
|
+
void
|
649
|
+
mouse_rotate2(CGRotateDirection direction, double angle, CGPoint point)
|
650
|
+
{
|
651
|
+
mouse_rotate3(direction, angle, point, DEFAULT_DURATION);
|
652
|
+
}
|
653
|
+
|
654
|
+
void
|
655
|
+
mouse_rotate(CGRotateDirection direction, double angle)
|
656
|
+
{
|
657
|
+
mouse_rotate2(direction, angle, mouse_current_position());
|
658
|
+
}
|