special_input_device 0.0.1 → 0.1.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.
- checksums.yaml +4 -4
- data/ext/special_input_device/image.c +13 -13
- data/ext/special_input_device/interception.c +151 -7
- data/ext/special_input_device/interception.h +2 -0
- data/ext/special_input_device/keyboard.c +44 -0
- data/ext/special_input_device/keyboard.h +6 -0
- data/ext/special_input_device/mouse.c +22 -20
- data/ext/special_input_device/mouse.h +6 -0
- data/ext/special_input_device/ruby_macro.h +10 -6
- data/ext/special_input_device/screen.c +3 -4
- data/ext/special_input_device/special_input_device.c +36 -1
- data/ext/special_input_device/special_input_device.h +7 -0
- data/ext/special_input_device/window.c +207 -60
- data/lib/special_input_device/color.rb +4 -4
- data/lib/special_input_device/image.rb +2 -1
- data/lib/special_input_device/point.rb +2 -2
- data/lib/special_input_device/rectangle.rb +40 -37
- data/lib/special_input_device/special_input_device.rb +6 -4
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be0868fbceeb98ef86c51bf95099a3ba60e6ee80
|
|
4
|
+
data.tar.gz: 726061d79c40698e7bc9d09f3f2dd61fc564f2fa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 94035fa8ecb71c41153232256ad261ecc4436aaef1a0f8fb721997c8b022c70758a10942d366084e8ba09894d6feaefde4ad5ae9caa080a5d1f740db063f80c3
|
|
7
|
+
data.tar.gz: d3eec4a2ba8c5f598a9c888a56b2529990fd1b9cb924cb3e7df607c0bac01a395ae95702ce03618ce5bdc59c0e006be9c05bde33a54d16d48637cb74a6fa0508
|
|
@@ -272,7 +272,7 @@ static VALUE ruby__load(VALUE self, VALUE path) {
|
|
|
272
272
|
case 24:
|
|
273
273
|
case 32: {
|
|
274
274
|
BYTE *cPixel;
|
|
275
|
-
|
|
275
|
+
UINT cBytePrePixel = (UINT) cDIBHeader.v1.biBitCount / 8;
|
|
276
276
|
LONG cValue;
|
|
277
277
|
LONG cMask;
|
|
278
278
|
LONG cBuffer;
|
|
@@ -354,8 +354,8 @@ static VALUE ruby_initialize(VALUE self, VALUE width, VALUE height) {
|
|
|
354
354
|
UINT cWidth = NUM2UINT(width);
|
|
355
355
|
UINT cHeight = NUM2UINT(height);
|
|
356
356
|
SID_IMAGE_DATA *cData = GET_SELF_DATA_OBJECT();
|
|
357
|
-
|
|
358
|
-
|
|
357
|
+
UINT cT0;
|
|
358
|
+
UINT cT1;
|
|
359
359
|
cData->height = cHeight;
|
|
360
360
|
cData->pixelTable = ALLOC_N(LPRGBQUAD, cHeight);
|
|
361
361
|
for (cT0 = 0; cT0 < cHeight; cT0++) {
|
|
@@ -389,7 +389,7 @@ static VALUE ruby_save(VALUE self, VALUE path) {
|
|
|
389
389
|
BITMAPFILEHEADER cFileHeader;
|
|
390
390
|
BITMAPV5HEADER cDIBHeader;
|
|
391
391
|
DWORD cByteWritten;
|
|
392
|
-
|
|
392
|
+
UINT cT;
|
|
393
393
|
cFile = CreateFile(cPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
394
394
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
395
395
|
if (cFile == INVALID_HANDLE_VALUE)
|
|
@@ -453,7 +453,7 @@ static VALUE ruby_OS_CS(VALUE self, VALUE x, VALUE y) {
|
|
|
453
453
|
rb_raise(rb_eRangeError, "The image only has %d columns. x = %d is out of range.", cWidth, cX);
|
|
454
454
|
if (cX < 0)
|
|
455
455
|
cX += cWidth;
|
|
456
|
-
if (cY < (INT) -cData->height || cY >= cData->height)
|
|
456
|
+
if (cY < (INT) -cData->height || cY >= (INT) cData->height)
|
|
457
457
|
rb_raise(rb_eRangeError, "The image only has %d rows. y = %d is out of range.", cData->height, cY);
|
|
458
458
|
if (cY < 0)
|
|
459
459
|
cY += cData->height;
|
|
@@ -477,7 +477,7 @@ static VALUE ruby_OS_CS_EQ(VALUE self, VALUE x, VALUE y, VALUE value) {
|
|
|
477
477
|
rb_raise(rb_eRangeError, "The image only has %d columns. x = %d is out of range.", cWidth, cX);
|
|
478
478
|
if (cX < 0)
|
|
479
479
|
cX += cWidth;
|
|
480
|
-
if (cY < (INT) -cData->height || cY >= cData->height)
|
|
480
|
+
if (cY < (INT) -cData->height || cY >= (INT) cData->height)
|
|
481
481
|
rb_raise(rb_eRangeError, "The image only has %d rows. y = %d is out of range.", cData->height, cY);
|
|
482
482
|
if (cY < 0)
|
|
483
483
|
cY += cData->height;
|
|
@@ -496,7 +496,7 @@ static VALUE ruby_try_get(VALUE self, VALUE x, VALUE y) {
|
|
|
496
496
|
INT cX = NUM2INT(x);
|
|
497
497
|
INT cY = NUM2INT(y);
|
|
498
498
|
SID_IMAGE_DATA *cData = GET_SELF_DATA_OBJECT();
|
|
499
|
-
if (cX < -cWidth || cX >= cWidth || cY < (INT) -cData->height || cY >= cData->height)
|
|
499
|
+
if (cX < -cWidth || cX >= cWidth || cY < (INT) -cData->height || cY >= (INT) cData->height)
|
|
500
500
|
return Qnil;
|
|
501
501
|
if (cX < 0)
|
|
502
502
|
cX += cWidth;
|
|
@@ -518,7 +518,7 @@ static VALUE ruby_try_set(VALUE self, VALUE x, VALUE y, VALUE value) {
|
|
|
518
518
|
INT cY = NUM2INT(y);
|
|
519
519
|
RGBQUAD cVALUE = ruby___color_to_rgb_quad(value);
|
|
520
520
|
SID_IMAGE_DATA *cData = GET_SELF_DATA_OBJECT();
|
|
521
|
-
if (cX >= -cWidth && cX < cWidth && cY >= (INT) -cData->height && cY < cData->height) {
|
|
521
|
+
if (cX >= -cWidth && cX < cWidth && cY >= (INT) -cData->height && cY < (INT) cData->height) {
|
|
522
522
|
if (cX < 0)
|
|
523
523
|
cX += cWidth;
|
|
524
524
|
if (cY < 0)
|
|
@@ -574,7 +574,7 @@ static VALUE ruby_each_row(VARIABLE_ARGUMENTS_C) {
|
|
|
574
574
|
SCAN_ARGUMENTS("&", &block);
|
|
575
575
|
if (RTEST(block)) {
|
|
576
576
|
UINT cT0;
|
|
577
|
-
|
|
577
|
+
LONG cT1;
|
|
578
578
|
VALUE *cRow = ALLOC_N(VALUE, cWidth);
|
|
579
579
|
for (cT0 = 0; cT0 < cData->height; cT0++) {
|
|
580
580
|
for (cT1 = 0; cT1 < cWidth; cT1++) {
|
|
@@ -602,7 +602,7 @@ static VALUE ruby_each_row(VARIABLE_ARGUMENTS_C) {
|
|
|
602
602
|
static VALUE ruby_each_column(VARIABLE_ARGUMENTS_C) {
|
|
603
603
|
VALUE block;
|
|
604
604
|
SID_IMAGE_DATA *cData = GET_SELF_DATA_OBJECT();
|
|
605
|
-
|
|
605
|
+
UINT cWidth = NUM2UINT(rb_iv_get(self, "@width"));
|
|
606
606
|
SCAN_ARGUMENTS("&", &block);
|
|
607
607
|
if (RTEST(block)) {
|
|
608
608
|
UINT cT0;
|
|
@@ -637,15 +637,15 @@ static VALUE ruby_each_in_row(VARIABLE_ARGUMENTS_C) {
|
|
|
637
637
|
VALUE block;
|
|
638
638
|
SID_IMAGE_DATA *cData = GET_SELF_DATA_OBJECT();
|
|
639
639
|
INT cY;
|
|
640
|
-
|
|
640
|
+
INT cWidth = NUM2INT(rb_iv_get(self, "@width"));
|
|
641
641
|
SCAN_ARGUMENTS("1&", &y, &block);
|
|
642
642
|
cY = NUM2INT(y);
|
|
643
|
-
if (cY < (INT) -cData->height || cY >= cData->height)
|
|
643
|
+
if (cY < (INT) -cData->height || cY >= (INT) cData->height)
|
|
644
644
|
rb_raise(rb_eRangeError, "The image only has %d rows. y = %d is out of range.", cData->height, cY);
|
|
645
645
|
if (cY < 0)
|
|
646
646
|
cY += cWidth;
|
|
647
647
|
if (RTEST(block)) {
|
|
648
|
-
|
|
648
|
+
INT cT;
|
|
649
649
|
VALUE cPixel;
|
|
650
650
|
for (cT = 0; cT < cWidth; cT++) {
|
|
651
651
|
cPixel = ruby___color_new_from_rgb_quad(&PixelAt(cT, cY));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#include "special_input_device.h"
|
|
2
2
|
#include "_vendor__interception.h"
|
|
3
|
+
#include "keyboard.h"
|
|
4
|
+
#include "mouse.h"
|
|
3
5
|
|
|
4
6
|
#define MAXIMUM_HARDWARE_IDENTIFIER_LENGTH 512
|
|
5
7
|
|
|
@@ -7,9 +9,13 @@ typedef struct {
|
|
|
7
9
|
InterceptionContext context;
|
|
8
10
|
InterceptionDevice keyboard;
|
|
9
11
|
InterceptionDevice mouse;
|
|
12
|
+
BOOL lockMouse;
|
|
13
|
+
BOOL lockKeyboard;
|
|
10
14
|
} SID_INTERCEPTION_DATA;
|
|
11
15
|
|
|
12
16
|
static SID_INTERCEPTION_DATA *cData;
|
|
17
|
+
static BOOL cCustomExitKeysDown[CUSTOM_EXIT_KEY_SIZE] = {FALSE};
|
|
18
|
+
static BOOL cDefaultExitKeysDown[DEFAULT_EXIT_KEY_SIZE] = {FALSE};
|
|
13
19
|
|
|
14
20
|
inline InterceptionContext ruby___interception_get_context() {
|
|
15
21
|
return cData->context;
|
|
@@ -18,12 +24,12 @@ inline InterceptionContext ruby___interception_get_context() {
|
|
|
18
24
|
InterceptionDevice ruby___interception_find_keyboard() {
|
|
19
25
|
TCHAR cHardwareIdentifier[MAXIMUM_HARDWARE_IDENTIFIER_LENGTH];
|
|
20
26
|
if (interceptionGetHardwareIdentifier(cData->context, cData->keyboard, cHardwareIdentifier,
|
|
21
|
-
|
|
27
|
+
MAXIMUM_HARDWARE_IDENTIFIER_LENGTH))
|
|
22
28
|
return cData->keyboard;
|
|
23
29
|
for (cData->keyboard = INTERCEPTION_KEYBOARD(0);
|
|
24
30
|
cData->keyboard < INTERCEPTION_KEYBOARD(INTERCEPTION_MAX_KEYBOARD); cData->keyboard++) {
|
|
25
31
|
if (interceptionGetHardwareIdentifier(cData->context, cData->keyboard, cHardwareIdentifier,
|
|
26
|
-
|
|
32
|
+
MAXIMUM_HARDWARE_IDENTIFIER_LENGTH))
|
|
27
33
|
return cData->keyboard;
|
|
28
34
|
}
|
|
29
35
|
rb_raise(rb_eRuntimeError, "Can not find any keyboard connected. Make sure you have at least one keyboard connected"
|
|
@@ -34,12 +40,12 @@ InterceptionDevice ruby___interception_find_keyboard() {
|
|
|
34
40
|
InterceptionDevice ruby___interception_find_mouse() {
|
|
35
41
|
TCHAR cHardwareIdentifier[MAXIMUM_HARDWARE_IDENTIFIER_LENGTH];
|
|
36
42
|
if (interceptionGetHardwareIdentifier(cData->context, cData->mouse, cHardwareIdentifier,
|
|
37
|
-
|
|
43
|
+
MAXIMUM_HARDWARE_IDENTIFIER_LENGTH))
|
|
38
44
|
return cData->mouse;
|
|
39
45
|
for (cData->mouse = INTERCEPTION_MOUSE(0);
|
|
40
46
|
cData->mouse < INTERCEPTION_MOUSE(INTERCEPTION_MAX_MOUSE); cData->mouse++) {
|
|
41
47
|
if (interceptionGetHardwareIdentifier(cData->context, cData->mouse, cHardwareIdentifier,
|
|
42
|
-
|
|
48
|
+
MAXIMUM_HARDWARE_IDENTIFIER_LENGTH))
|
|
43
49
|
return cData->mouse;
|
|
44
50
|
}
|
|
45
51
|
rb_raise(rb_eRuntimeError, "Can not find any mouse connected. Make sure you have at least one keyboard connected"
|
|
@@ -47,15 +53,152 @@ InterceptionDevice ruby___interception_find_mouse() {
|
|
|
47
53
|
" interception mode.");
|
|
48
54
|
}
|
|
49
55
|
|
|
56
|
+
VOID ruby___interception_exit_keys_updated() {
|
|
57
|
+
UINT *cExitKeys = ruby___special_input_device_get_exit_keys();
|
|
58
|
+
INT cT;
|
|
59
|
+
for (cT = 0; cT < CUSTOM_EXIT_KEY_SIZE; cT++)
|
|
60
|
+
cCustomExitKeysDown[cT] = !cExitKeys[cT];
|
|
61
|
+
}
|
|
62
|
+
|
|
50
63
|
static VOID callback_interception_free(SID_INTERCEPTION_DATA *cData) {
|
|
51
64
|
interceptionDestroyContext(cData->context);
|
|
52
65
|
xfree(cData);
|
|
53
66
|
}
|
|
54
67
|
|
|
55
68
|
static VALUE ruby__alloc(VALUE self) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
return NEW_DATA_OBJECT(self, SID_INTERCEPTION_DATA, NULL, callback_interception_free);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static VALUE ruby_initialize_thread() {
|
|
73
|
+
InterceptionStroke cStroke;
|
|
74
|
+
InterceptionDevice cDevice;
|
|
75
|
+
UINT *cCustomExitKeys;
|
|
76
|
+
INT cT;
|
|
77
|
+
interceptionSetFilter(cData->context, interceptionIsKeyboard, INTERCEPTION_FILTER_KEY_ALL);
|
|
78
|
+
interceptionSetFilter(cData->context, interceptionIsMouse, INTERCEPTION_FILTER_MOUSE_ALL);
|
|
79
|
+
while (TRUE) {
|
|
80
|
+
cDevice = interceptionWait(cData->context);
|
|
81
|
+
if (!interceptionReceive(cData->context, cDevice, &cStroke, 1))
|
|
82
|
+
break;
|
|
83
|
+
cCustomExitKeys = ruby___special_input_device_get_exit_keys();
|
|
84
|
+
if (interceptionIsMouse(cDevice)) {
|
|
85
|
+
InterceptionMouseStroke *cMouseStroke = (InterceptionMouseStroke *) &cStroke;
|
|
86
|
+
for (cT = 0; cT < CUSTOM_EXIT_KEY_SIZE; cT++) {
|
|
87
|
+
switch (cCustomExitKeys[cT]) {
|
|
88
|
+
case VK_LBUTTON:
|
|
89
|
+
switch (cMouseStroke->state) {
|
|
90
|
+
case INTERCEPTION_MOUSE_BUTTON_1_DOWN:
|
|
91
|
+
cCustomExitKeysDown[cT] = TRUE;
|
|
92
|
+
break;
|
|
93
|
+
case INTERCEPTION_MOUSE_BUTTON_1_UP:
|
|
94
|
+
cCustomExitKeysDown[cT] = FALSE;
|
|
95
|
+
break;
|
|
96
|
+
default:
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
case VK_RBUTTON:
|
|
101
|
+
switch (cMouseStroke->state) {
|
|
102
|
+
case INTERCEPTION_MOUSE_BUTTON_2_DOWN:
|
|
103
|
+
cCustomExitKeysDown[cT] = TRUE;
|
|
104
|
+
break;
|
|
105
|
+
case INTERCEPTION_MOUSE_BUTTON_2_UP:
|
|
106
|
+
cCustomExitKeysDown[cT] = FALSE;
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
case VK_MBUTTON:
|
|
113
|
+
switch (cMouseStroke->state) {
|
|
114
|
+
case INTERCEPTION_MOUSE_BUTTON_3_DOWN:
|
|
115
|
+
cCustomExitKeysDown[cT] = TRUE;
|
|
116
|
+
break;
|
|
117
|
+
case INTERCEPTION_MOUSE_BUTTON_3_UP:
|
|
118
|
+
cCustomExitKeysDown[cT] = FALSE;
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case VK_XBUTTON1:
|
|
125
|
+
switch (cMouseStroke->state) {
|
|
126
|
+
case INTERCEPTION_MOUSE_BUTTON_4_DOWN:
|
|
127
|
+
cCustomExitKeysDown[cT] = TRUE;
|
|
128
|
+
break;
|
|
129
|
+
case INTERCEPTION_MOUSE_BUTTON_4_UP:
|
|
130
|
+
cCustomExitKeysDown[cT] = FALSE;
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
case VK_XBUTTON2:
|
|
137
|
+
switch (cMouseStroke->state) {
|
|
138
|
+
case INTERCEPTION_MOUSE_BUTTON_5_DOWN:
|
|
139
|
+
cCustomExitKeysDown[cT] = TRUE;
|
|
140
|
+
break;
|
|
141
|
+
case INTERCEPTION_MOUSE_BUTTON_5_UP:
|
|
142
|
+
cCustomExitKeysDown[cT] = FALSE;
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
default:
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
for (cT = 0; cT < CUSTOM_EXIT_KEY_SIZE; cT++) {
|
|
153
|
+
if (!cCustomExitKeysDown[cT])
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
if (cT == CUSTOM_EXIT_KEY_SIZE)
|
|
157
|
+
rb_raise(rb_eSystemExit, "Exit keys pressed.");
|
|
158
|
+
if (!ruby___mouse_is_locked())
|
|
159
|
+
interceptionSend(cData->context, cDevice, (InterceptionStroke const *) &cStroke, 1);
|
|
160
|
+
}
|
|
161
|
+
if (interceptionIsKeyboard(cDevice)) {
|
|
162
|
+
InterceptionKeyStroke *cKeyStroke = (InterceptionKeyStroke *) (InterceptionMouseStroke *) &cStroke;
|
|
163
|
+
for (cT = 0; cT < DEFAULT_EXIT_KEY_SIZE; cT++) {
|
|
164
|
+
if (cKeyStroke->code == MapVirtualKeyA(cDefaultExitKeys[cT], MAPVK_VK_TO_VSC))
|
|
165
|
+
cDefaultExitKeysDown[cT] = !(cKeyStroke->state & INTERCEPTION_KEY_UP);
|
|
166
|
+
}
|
|
167
|
+
for (cT = 0; cT < DEFAULT_EXIT_KEY_SIZE; cT++) {
|
|
168
|
+
if (!cDefaultExitKeysDown[cT])
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
if (cT == DEFAULT_EXIT_KEY_SIZE)
|
|
172
|
+
rb_raise(rb_eSystemExit, "Exit keys pressed.");
|
|
173
|
+
for (cT = 0; cT < CUSTOM_EXIT_KEY_SIZE; cT++) {
|
|
174
|
+
if (cKeyStroke->code == MapVirtualKeyA(cCustomExitKeys[cT], MAPVK_VK_TO_VSC))
|
|
175
|
+
cCustomExitKeysDown[cT] = !(cKeyStroke->state & INTERCEPTION_KEY_UP);
|
|
176
|
+
}
|
|
177
|
+
for (cT = 0; cT < CUSTOM_EXIT_KEY_SIZE; cT++) {
|
|
178
|
+
if (!cCustomExitKeysDown[cT])
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
if (cT == CUSTOM_EXIT_KEY_SIZE)
|
|
182
|
+
rb_raise(rb_eSystemExit, "Exit keys pressed.");
|
|
183
|
+
if (!ruby___keyboard_is_locked())
|
|
184
|
+
interceptionSend(cData->context, cDevice, (InterceptionStroke const *) &cStroke, 1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return Qnil;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/*
|
|
191
|
+
* @!visibility private
|
|
192
|
+
*/
|
|
193
|
+
static VALUE ruby_initialize(VALUE self) {
|
|
194
|
+
cData = GET_SELF_DATA_OBJECT();
|
|
195
|
+
cData->context = interceptionCreateContext();
|
|
196
|
+
cData->mouse = 0;
|
|
197
|
+
cData->keyboard = 0;
|
|
198
|
+
cData->lockMouse = FALSE;
|
|
199
|
+
cData->lockKeyboard = FALSE;
|
|
200
|
+
rb_thread_create(ruby_initialize_thread, NULL);
|
|
201
|
+
return Qnil;
|
|
59
202
|
}
|
|
60
203
|
|
|
61
204
|
VOID Init_interception() {
|
|
@@ -71,6 +214,7 @@ VOID Init_interception() {
|
|
|
71
214
|
*/
|
|
72
215
|
VALUE specialInputDevice_interception = rb_define_class_under(specialInputDevice, "Interception", rb_cData);
|
|
73
216
|
rb_define_alloc_func(specialInputDevice_interception, (rb_alloc_func_t) ruby__alloc);
|
|
217
|
+
rb_define_method(specialInputDevice_interception, "initialize", ruby_initialize, 0);
|
|
74
218
|
|
|
75
219
|
rb_require("singleton");
|
|
76
220
|
singleton = RUBY_MODULE_CONST_GET(rb_mKernel, rb_intern_const("Singleton"));
|
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
#include "special_input_device.h"
|
|
2
2
|
#include "interception.h"
|
|
3
3
|
|
|
4
|
+
static BOOL cLocked;
|
|
5
|
+
|
|
6
|
+
inline BOOL ruby___keyboard_is_locked() {
|
|
7
|
+
return cLocked;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Lock the keyboard.
|
|
12
|
+
* @return [Module] self
|
|
13
|
+
*/
|
|
14
|
+
static VALUE ruby__lock(VALUE self) {
|
|
15
|
+
cLocked = TRUE;
|
|
16
|
+
switch (ruby___special_input_device_get_mode_identifier()) {
|
|
17
|
+
case MODE_INTERCEPTION:
|
|
18
|
+
break;
|
|
19
|
+
case MODE_WIN_API:
|
|
20
|
+
rb_raise(rb_eRuntimeError, "WinAPI mode does not support lock mouse function.");
|
|
21
|
+
default: {
|
|
22
|
+
PCHAR cModeName = ruby___special_input_device_get_mode_name();
|
|
23
|
+
rb_raise(rb_eRuntimeError, "Undefined mode '%s'.", cModeName);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return self;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Unlock the keyboard.
|
|
31
|
+
* @return [Module] self
|
|
32
|
+
*/
|
|
33
|
+
static VALUE ruby__unlock(VALUE self) {
|
|
34
|
+
cLocked = FALSE;
|
|
35
|
+
switch (ruby___special_input_device_get_mode_identifier()) {
|
|
36
|
+
case MODE_INTERCEPTION:
|
|
37
|
+
break;
|
|
38
|
+
case MODE_WIN_API:
|
|
39
|
+
rb_raise(rb_eRuntimeError, "WinAPI mode does not support lock mouse function.");
|
|
40
|
+
default: {
|
|
41
|
+
PCHAR cModeName = ruby___special_input_device_get_mode_name();
|
|
42
|
+
rb_raise(rb_eRuntimeError, "Undefined mode '%s'.", cModeName);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return self;
|
|
46
|
+
}
|
|
47
|
+
|
|
4
48
|
/*
|
|
5
49
|
* @overload hold(key_code)
|
|
6
50
|
* Simulate holding the specified key down.
|
|
@@ -3,19 +3,21 @@
|
|
|
3
3
|
#include "interception.h"
|
|
4
4
|
#include "point.h"
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
static BOOL cLocked;
|
|
7
|
+
|
|
8
|
+
inline BOOL ruby___mouse_is_locked() {
|
|
9
|
+
return cLocked;
|
|
10
|
+
}
|
|
7
11
|
|
|
8
12
|
/*
|
|
9
13
|
* Lock the mouse.
|
|
10
14
|
* @return [Module] self
|
|
11
15
|
*/
|
|
12
16
|
static VALUE ruby__lock(VALUE self) {
|
|
17
|
+
cLocked = TRUE;
|
|
13
18
|
switch (ruby___special_input_device_get_mode_identifier()) {
|
|
14
|
-
case MODE_INTERCEPTION:
|
|
15
|
-
InterceptionContext cContext = ruby___interception_get_context();
|
|
16
|
-
interceptionSetFilter(cContext, interceptionIsMouse, INTERCEPTION_FILTER_MOUSE_ALL);
|
|
19
|
+
case MODE_INTERCEPTION:
|
|
17
20
|
break;
|
|
18
|
-
}
|
|
19
21
|
case MODE_WIN_API:
|
|
20
22
|
rb_raise(rb_eRuntimeError, "WinAPI mode does not support lock mouse function.");
|
|
21
23
|
default: {
|
|
@@ -31,12 +33,10 @@ static VALUE ruby__lock(VALUE self) {
|
|
|
31
33
|
* @return [Module] self
|
|
32
34
|
*/
|
|
33
35
|
static VALUE ruby__unlock(VALUE self) {
|
|
36
|
+
cLocked = FALSE;
|
|
34
37
|
switch (ruby___special_input_device_get_mode_identifier()) {
|
|
35
|
-
case MODE_INTERCEPTION:
|
|
36
|
-
InterceptionContext cContext = ruby___interception_get_context();
|
|
37
|
-
interceptionSetFilter(cContext, interceptionIsMouse, INTERCEPTION_FILTER_MOUSE_NONE);
|
|
38
|
+
case MODE_INTERCEPTION:
|
|
38
39
|
break;
|
|
39
|
-
}
|
|
40
40
|
case MODE_WIN_API:
|
|
41
41
|
rb_raise(rb_eRuntimeError, "WinAPI mode does not support lock mouse function.");
|
|
42
42
|
default: {
|
|
@@ -47,6 +47,8 @@ static VALUE ruby__unlock(VALUE self) {
|
|
|
47
47
|
return self;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
//region cursor
|
|
51
|
+
|
|
50
52
|
/*
|
|
51
53
|
* @return [SpecialInputDevice::Point] the point of cursor position
|
|
52
54
|
* @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx Windows Dev Center - SendInput function
|
|
@@ -204,9 +206,9 @@ static VALUE ruby__move_to_virtual(VALUE self, VALUE x, VALUE y) {
|
|
|
204
206
|
return self;
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
|
|
209
|
+
//endregion cursor
|
|
208
210
|
|
|
209
|
-
|
|
211
|
+
//region left_button
|
|
210
212
|
|
|
211
213
|
/*
|
|
212
214
|
* Simulate clicking the left button on the mouse.
|
|
@@ -347,9 +349,9 @@ static VALUE ruby__left_up(VALUE self) {
|
|
|
347
349
|
return self;
|
|
348
350
|
}
|
|
349
351
|
|
|
350
|
-
|
|
352
|
+
//endregion left_button
|
|
351
353
|
|
|
352
|
-
|
|
354
|
+
//region right_button
|
|
353
355
|
|
|
354
356
|
/*
|
|
355
357
|
* Simulate clicking the right button on the mouse.
|
|
@@ -490,9 +492,9 @@ static VALUE ruby__right_up(VALUE self) {
|
|
|
490
492
|
return self;
|
|
491
493
|
}
|
|
492
494
|
|
|
493
|
-
|
|
495
|
+
//endregion right_button
|
|
494
496
|
|
|
495
|
-
|
|
497
|
+
//region middle_button
|
|
496
498
|
|
|
497
499
|
/*
|
|
498
500
|
* Simulate clicking the middle button on the mouse.
|
|
@@ -633,9 +635,9 @@ static VALUE ruby__middle_up(VALUE self) {
|
|
|
633
635
|
return self;
|
|
634
636
|
}
|
|
635
637
|
|
|
636
|
-
|
|
638
|
+
//endregion middle_button
|
|
637
639
|
|
|
638
|
-
|
|
640
|
+
//region x_button
|
|
639
641
|
|
|
640
642
|
/*
|
|
641
643
|
* Simulate clicking the x1 button on the mouse.
|
|
@@ -915,9 +917,9 @@ static VALUE ruby__x2_up(VALUE self) {
|
|
|
915
917
|
return self;
|
|
916
918
|
}
|
|
917
919
|
|
|
918
|
-
|
|
920
|
+
//endregion x_button
|
|
919
921
|
|
|
920
|
-
|
|
922
|
+
//region wheel
|
|
921
923
|
|
|
922
924
|
/*
|
|
923
925
|
* Simulate wheeling the scroll backward.
|
|
@@ -1095,7 +1097,7 @@ static VALUE ruby__scroll_wheel_to_right(VALUE self) {
|
|
|
1095
1097
|
#endif
|
|
1096
1098
|
}
|
|
1097
1099
|
|
|
1098
|
-
|
|
1100
|
+
//endregion wheel
|
|
1099
1101
|
|
|
1100
1102
|
VOID Init_mouse() {
|
|
1101
1103
|
#ifdef YARD
|
|
@@ -10,14 +10,16 @@ NORETURN(VOID _RUBY_KERNEL_RAISE();)
|
|
|
10
10
|
|
|
11
11
|
# define RUBY_KERNEL_RAISE(exception) \
|
|
12
12
|
(rb_funcall(rb_mKernel, rb_intern_const("raise"), 1, exception), _RUBY_KERNEL_RAISE())
|
|
13
|
+
# define RUBY_MODULE_CONST_GET(module, id) rb_funcall(module, rb_intern_const("const_get"), 1, id)
|
|
13
14
|
# define RUBY_OBJECT_IS_A_qs(object, _class) rb_funcall(object, rb_intern_const("is_a?"), 1, _class)
|
|
15
|
+
# define RUBY_OBJECT_SINGLETON_CLASS(object) rb_funcall(object, rb_intern_const("singleton_class"), 0)
|
|
14
16
|
# define RUBY_REGEXP_MATCH(regexp, string) rb_funcall(regexp, rb_intern_const("match"), 1, string)
|
|
15
|
-
# define RUBY_MODULE_CONST_GET(module, id) rb_funcall(module, rb_intern_const("const_get"), 1, id)
|
|
16
17
|
#else
|
|
17
18
|
# define RUBY_KERNEL_RAISE(exception) rb_exc_raise(exception)
|
|
19
|
+
# define RUBY_MODULE_CONST_GET(module, id) rb_const_get(module, id)
|
|
18
20
|
# define RUBY_OBJECT_IS_A_qs(object, _class) rb_obj_is_kind_of(object, _class)
|
|
21
|
+
# define RUBY_OBJECT_SINGLETON_CLASS(object) rb_singleton_class(object)
|
|
19
22
|
# define RUBY_REGEXP_MATCH(regexp, string) rb_reg_match(regexp, string)
|
|
20
|
-
# define RUBY_MODULE_CONST_GET(module, id) rb_const_get(module, id)
|
|
21
23
|
#endif
|
|
22
24
|
|
|
23
25
|
// Encoding
|
|
@@ -75,13 +77,15 @@ VALUE __ruby_string_converter_temp_variable;
|
|
|
75
77
|
#define RAISE_WIN32_ERROR_FROM_CODE(code) RUBY_KERNEL_RAISE(ruby___win32error_new_from_code(code))
|
|
76
78
|
#define RAISE_ARGUMENT_ERROR(expected) \
|
|
77
79
|
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected %s)", cCount, expected)
|
|
78
|
-
#define RAISE_TYPE_ERROR(object, expected) \
|
|
79
|
-
rb_raise(rb_eTypeError, "Expecting %s, got %s", expected, rb_obj_classname(object))
|
|
80
|
-
#define
|
|
80
|
+
#define RAISE_TYPE_ERROR(object, name, expected) \
|
|
81
|
+
rb_raise(rb_eTypeError, "Expecting %s for %s, got %s", expected, name, rb_obj_classname(object))
|
|
82
|
+
#define RAISE_SIMPLE_TYPE_ERROR(object, expected) RAISE_TYPE_ERROR(object, #object, expected)
|
|
83
|
+
#define CHECK_TYPE_ERROR(object, name, expected) \
|
|
81
84
|
({\
|
|
82
85
|
if (!RTEST(RUBY_OBJECT_IS_A_qs(object, expected)))\
|
|
83
|
-
RAISE_TYPE_ERROR(object, rb_class2name(expected));\
|
|
86
|
+
RAISE_TYPE_ERROR(object, name, rb_class2name(expected));\
|
|
84
87
|
})
|
|
88
|
+
#define CHECK_SIMPLE_TYPE_ERROR(object, expected) CHECK_TYPE_ERROR(object, #object, expected)
|
|
85
89
|
|
|
86
90
|
// Arguments
|
|
87
91
|
#define VARIABLE_ARGUMENTS_C INT cCount, VALUE* cArguments, VALUE self
|
|
@@ -152,11 +152,11 @@ static VALUE ruby__find_image(VARIABLE_ARGUMENTS_C) {
|
|
|
152
152
|
if (RTEST(RUBY_OBJECT_IS_A_qs(image, rb_cString)) || RTEST(RUBY_OBJECT_IS_A_qs(image, rb_cFile)))
|
|
153
153
|
image = rb_funcall(specialInputDevice_image, rb_intern_const("load"), 1, image);
|
|
154
154
|
else if (!RTEST(RUBY_OBJECT_IS_A_qs(image, specialInputDevice_image)))
|
|
155
|
-
|
|
155
|
+
RAISE_SIMPLE_TYPE_ERROR(image, "String, File or SpecialInputDevice::Image");
|
|
156
156
|
if (*area == Qundef) {
|
|
157
157
|
capture = ruby__capture(0, captureArguments, self);
|
|
158
158
|
} else {
|
|
159
|
-
CHECK_TYPE_ERROR(*area, specialInputDevice_rectangle);
|
|
159
|
+
CHECK_TYPE_ERROR(*area, ":area", specialInputDevice_rectangle);
|
|
160
160
|
x = rb_funcall(*area, rb_intern_const("x"), 0);
|
|
161
161
|
y = rb_funcall(*area, rb_intern_const("y"), 0);
|
|
162
162
|
captureArguments[0] = x;
|
|
@@ -165,9 +165,8 @@ static VALUE ruby__find_image(VARIABLE_ARGUMENTS_C) {
|
|
|
165
165
|
captureArguments[3] = rb_funcall(*area, rb_intern_const("height"), 0);
|
|
166
166
|
capture = ruby__capture(4, captureArguments, self);
|
|
167
167
|
}
|
|
168
|
-
// return capture;
|
|
169
168
|
rb_funcall(capture, rb_intern_const("save"), 1, rb_str_new_cstr("D:/2.bmp"));
|
|
170
|
-
result = rb_funcall(capture, rb_intern_const("find"), 2, image, options);
|
|
169
|
+
result = rb_funcall(capture, rb_intern_const("find"), options == Qnil ? 1 : 2, image, options);
|
|
171
170
|
if (result != Qnil && *area != Qundef)
|
|
172
171
|
result = rb_funcall(result, rb_intern_const("move"), 2, x, y);
|
|
173
172
|
return result;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#include "special_input_device.h"
|
|
2
|
+
#include "interception.h"
|
|
3
|
+
|
|
4
|
+
UINT cDefaultExitKeys[DEFAULT_EXIT_KEY_SIZE] = {VK_CONTROL, VK_LWIN, VK_MENU, (UINT) '6', (UINT) 'Y'};
|
|
5
|
+
static UINT cCustomExitKeys[CUSTOM_EXIT_KEY_SIZE];
|
|
2
6
|
|
|
3
7
|
SID_MODE ruby___special_input_device_get_mode_identifier() {
|
|
4
8
|
PCHAR cModeName = ruby___special_input_device_get_mode_name();
|
|
@@ -14,6 +18,34 @@ PCHAR ruby___special_input_device_get_mode_name() {
|
|
|
14
18
|
return rb_string_value_cstr(&mode);
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
inline UINT *ruby___special_input_device_get_exit_keys() {
|
|
22
|
+
return cCustomExitKeys;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static VALUE ruby__exit_keys_EQ(VALUE self, VALUE value) {
|
|
26
|
+
LONG cSize;
|
|
27
|
+
LONG cT;
|
|
28
|
+
if (RTEST(RUBY_OBJECT_IS_A_qs(value, rb_cFixnum)))
|
|
29
|
+
value = rb_ary_new_from_args(1, value);
|
|
30
|
+
else if (!RTEST(RUBY_OBJECT_IS_A_qs(value, rb_cArray)))
|
|
31
|
+
RAISE_SIMPLE_TYPE_ERROR(value, "Array or Fixnum");
|
|
32
|
+
cSize = rb_array_len(value);
|
|
33
|
+
if (cSize <= 0 || cSize > CUSTOM_EXIT_KEY_SIZE)
|
|
34
|
+
rb_raise(rb_eArgError, "The number of keys for exit must between 1..%d.", CUSTOM_EXIT_KEY_SIZE);
|
|
35
|
+
for (cT = 0; cT < CUSTOM_EXIT_KEY_SIZE; cT++) {
|
|
36
|
+
if (cT < cSize) {
|
|
37
|
+
VALUE element = rb_ary_entry(value, cT);
|
|
38
|
+
CHAR name[20];
|
|
39
|
+
sprintf(name, "value[%li]", cT);
|
|
40
|
+
CHECK_TYPE_ERROR(element, name, rb_cFixnum);
|
|
41
|
+
cCustomExitKeys[cT] = NUM2UINT(element);
|
|
42
|
+
} else
|
|
43
|
+
cCustomExitKeys[cT] = 0;
|
|
44
|
+
}
|
|
45
|
+
ruby___interception_exit_keys_updated();
|
|
46
|
+
return rb_iv_set(self, "@exit_keys", value);
|
|
47
|
+
}
|
|
48
|
+
|
|
17
49
|
VOID Init_special_input_device() {
|
|
18
50
|
specialInputDevice = rb_define_module("SpecialInputDevice");
|
|
19
51
|
|
|
@@ -32,9 +64,12 @@ VOID Init_special_input_device() {
|
|
|
32
64
|
"end\n");
|
|
33
65
|
|
|
34
66
|
Init_image();
|
|
67
|
+
Init_interception();
|
|
35
68
|
Init_keyboard();
|
|
36
69
|
Init_mouse();
|
|
37
70
|
Init_screen();
|
|
38
71
|
Init_window();
|
|
39
|
-
|
|
72
|
+
|
|
73
|
+
rb_define_singleton_method(specialInputDevice, "exit_keys=", ruby__exit_keys_EQ, 1);
|
|
74
|
+
rb_funcall(specialInputDevice, rb_intern_const("exit_keys="), 1, INT2NUM(VK_ESCAPE));
|
|
40
75
|
}
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
#include <ruby/encoding.h>
|
|
8
8
|
#include <windows.h>
|
|
9
9
|
|
|
10
|
+
#define CUSTOM_EXIT_KEY_SIZE 4
|
|
11
|
+
#define DEFAULT_EXIT_KEY_SIZE 5
|
|
12
|
+
|
|
13
|
+
UINT cDefaultExitKeys[DEFAULT_EXIT_KEY_SIZE];
|
|
14
|
+
|
|
10
15
|
typedef enum {
|
|
11
16
|
MODE_INTERCEPTION,
|
|
12
17
|
MODE_WIN_API
|
|
@@ -26,6 +31,8 @@ SID_MODE ruby___special_input_device_get_mode_identifier();
|
|
|
26
31
|
|
|
27
32
|
PCHAR ruby___special_input_device_get_mode_name();
|
|
28
33
|
|
|
34
|
+
inline UINT* ruby___special_input_device_get_exit_keys();
|
|
35
|
+
|
|
29
36
|
VOID Init_special_input_device();
|
|
30
37
|
|
|
31
38
|
VOID Init_image();
|