special_input_device 0.1.0 → 0.2.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/_mouse.c +22 -0
- data/ext/special_input_device/_mouse.h +12 -0
- data/ext/special_input_device/_vendor__interception.c +1 -1
- data/ext/special_input_device/_vendor__interception.h +1 -1
- data/ext/special_input_device/image.c +1 -1
- data/ext/special_input_device/interception.c +11 -9
- data/ext/special_input_device/keyboard.c +109 -119
- data/ext/special_input_device/mouse.c +273 -852
- data/ext/special_input_device/window.c +228 -352
- data/lib/special_input_device/color.rb +1 -1
- data/lib/special_input_device/point.rb +61 -0
- data/lib/special_input_device/rectangle.rb +16 -7
- data/lib/yard/attribute_handler.rb +17 -0
- data/lib/yard/init_handler.rb +22 -0
- data/lib/yard/templates/default/layout/html/setup.rb +3 -0
- data/lib/yard/yard.rb +2 -0
- metadata +12 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a121ec84d3ab7c53e8e10c86efe86ff24d25ce07
|
|
4
|
+
data.tar.gz: e36b09142e83769a40bba02da6fb92de44f9cf62
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4987339ea7d2ff4648c3141c631ad79d774727c430059fd16619670b5e8c1acaf0994f6c2fd37980f52421ec20792ea42a163e8048c0c5522f5ea43bd5ffee96
|
|
7
|
+
data.tar.gz: 8dfdf490278e48264878633ccd2c27349e0b3c9d73fcffb8e02a212d638696aba9490ba106f1a39ea4df684195922ba74e13ca7bf8b9b5fe2718836346507110
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#include <windows.h>
|
|
2
|
+
#include "_screen.h"
|
|
3
|
+
|
|
4
|
+
LONG getCursorPrimaryX() {
|
|
5
|
+
POINT cPoint;
|
|
6
|
+
GetCursorPos(&cPoint);
|
|
7
|
+
return cPoint.x;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
LONG getCursorPrimaryY() {
|
|
11
|
+
POINT cPoint;
|
|
12
|
+
GetCursorPos(&cPoint);
|
|
13
|
+
return cPoint.y;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
LONG getCursorVirtualX() {
|
|
17
|
+
return getCursorPrimaryX() - getVirtualScreenX();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
LONG getCursorVirtualY() {
|
|
21
|
+
return getCursorPrimaryY() - getVirtualScreenY();
|
|
22
|
+
}
|
|
@@ -180,7 +180,7 @@ InterceptionDevice interceptionWaitWithTimeout(InterceptionContext context, ULON
|
|
|
180
180
|
return 0;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
INT interceptionSend(InterceptionContext context, InterceptionDevice device,
|
|
183
|
+
INT interceptionSend(InterceptionContext context, InterceptionDevice device, InterceptionStroke *strokeValue,
|
|
184
184
|
UINT strokeCount) {
|
|
185
185
|
InterceptionDeviceArray deviceArray = (InterceptionDeviceArray) context;
|
|
186
186
|
DWORD strokesWritten = 0;
|
|
@@ -172,7 +172,7 @@ InterceptionDevice INTERCEPTION_API interceptionWait(InterceptionContext context
|
|
|
172
172
|
InterceptionDevice INTERCEPTION_API interceptionWaitWithTimeout(InterceptionContext context, ULONG milliseconds);
|
|
173
173
|
|
|
174
174
|
INT INTERCEPTION_API
|
|
175
|
-
interceptionSend(InterceptionContext context, InterceptionDevice device,
|
|
175
|
+
interceptionSend(InterceptionContext context, InterceptionDevice device, InterceptionStroke *strokeValue,
|
|
176
176
|
UINT strokeCount);
|
|
177
177
|
|
|
178
178
|
INT INTERCEPTION_API
|
|
@@ -228,7 +228,7 @@ static VALUE ruby__load(VALUE self, VALUE path) {
|
|
|
228
228
|
UINT cMaxColorTableSize = (UINT) (1 << cDIBHeader.v1.biBitCount);
|
|
229
229
|
if (cColorTableSize > cMaxColorTableSize)
|
|
230
230
|
rb_raise(rb_eArgError, "The bitmap file has been damaged. (clrUsed too large)");
|
|
231
|
-
if (cColorTableSize
|
|
231
|
+
if (!cColorTableSize)
|
|
232
232
|
cColorTableSize = cMaxColorTableSize;
|
|
233
233
|
cColorTable = ALLOC_N(RGBQUAD, cColorTableSize);
|
|
234
234
|
ReadFile(cFile, cColorTable, sizeof(RGBQUAD) * cColorTableSize, &cByteRead, NULL);
|
|
@@ -69,7 +69,7 @@ static VALUE ruby__alloc(VALUE self) {
|
|
|
69
69
|
return NEW_DATA_OBJECT(self, SID_INTERCEPTION_DATA, NULL, callback_interception_free);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
static VALUE ruby_initialize_thread() {
|
|
72
|
+
static VALUE ruby_initialize_thread(VALUE *self) {
|
|
73
73
|
InterceptionStroke cStroke;
|
|
74
74
|
InterceptionDevice cDevice;
|
|
75
75
|
UINT *cCustomExitKeys;
|
|
@@ -77,9 +77,11 @@ static VALUE ruby_initialize_thread() {
|
|
|
77
77
|
interceptionSetFilter(cData->context, interceptionIsKeyboard, INTERCEPTION_FILTER_KEY_ALL);
|
|
78
78
|
interceptionSetFilter(cData->context, interceptionIsMouse, INTERCEPTION_FILTER_MOUSE_ALL);
|
|
79
79
|
while (TRUE) {
|
|
80
|
-
cDevice =
|
|
81
|
-
if (!interceptionReceive(cData->context, cDevice, &cStroke, 1))
|
|
82
|
-
|
|
80
|
+
cDevice = interceptionWaitWithTimeout(cData->context, 10);
|
|
81
|
+
if (!cDevice || !interceptionReceive(cData->context, cDevice, &cStroke, 1)) {
|
|
82
|
+
rb_thread_schedule();
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
83
85
|
cCustomExitKeys = ruby___special_input_device_get_exit_keys();
|
|
84
86
|
if (interceptionIsMouse(cDevice)) {
|
|
85
87
|
InterceptionMouseStroke *cMouseStroke = (InterceptionMouseStroke *) &cStroke;
|
|
@@ -156,10 +158,10 @@ static VALUE ruby_initialize_thread() {
|
|
|
156
158
|
if (cT == CUSTOM_EXIT_KEY_SIZE)
|
|
157
159
|
rb_raise(rb_eSystemExit, "Exit keys pressed.");
|
|
158
160
|
if (!ruby___mouse_is_locked())
|
|
159
|
-
interceptionSend(cData->context, cDevice,
|
|
161
|
+
interceptionSend(cData->context, cDevice, &cStroke, 1);
|
|
160
162
|
}
|
|
161
163
|
if (interceptionIsKeyboard(cDevice)) {
|
|
162
|
-
InterceptionKeyStroke *cKeyStroke = (InterceptionKeyStroke *)
|
|
164
|
+
InterceptionKeyStroke *cKeyStroke = (InterceptionKeyStroke *) &cStroke;
|
|
163
165
|
for (cT = 0; cT < DEFAULT_EXIT_KEY_SIZE; cT++) {
|
|
164
166
|
if (cKeyStroke->code == MapVirtualKeyA(cDefaultExitKeys[cT], MAPVK_VK_TO_VSC))
|
|
165
167
|
cDefaultExitKeysDown[cT] = !(cKeyStroke->state & INTERCEPTION_KEY_UP);
|
|
@@ -170,7 +172,7 @@ static VALUE ruby_initialize_thread() {
|
|
|
170
172
|
}
|
|
171
173
|
if (cT == DEFAULT_EXIT_KEY_SIZE)
|
|
172
174
|
rb_raise(rb_eSystemExit, "Exit keys pressed.");
|
|
173
|
-
for (cT
|
|
175
|
+
for (cT = 0; cT < CUSTOM_EXIT_KEY_SIZE; cT++) {
|
|
174
176
|
if (cKeyStroke->code == MapVirtualKeyA(cCustomExitKeys[cT], MAPVK_VK_TO_VSC))
|
|
175
177
|
cCustomExitKeysDown[cT] = !(cKeyStroke->state & INTERCEPTION_KEY_UP);
|
|
176
178
|
}
|
|
@@ -181,7 +183,7 @@ static VALUE ruby_initialize_thread() {
|
|
|
181
183
|
if (cT == CUSTOM_EXIT_KEY_SIZE)
|
|
182
184
|
rb_raise(rb_eSystemExit, "Exit keys pressed.");
|
|
183
185
|
if (!ruby___keyboard_is_locked())
|
|
184
|
-
interceptionSend(cData->context, cDevice,
|
|
186
|
+
interceptionSend(cData->context, cDevice, &cStroke, 1);
|
|
185
187
|
}
|
|
186
188
|
}
|
|
187
189
|
return Qnil;
|
|
@@ -197,7 +199,7 @@ static VALUE ruby_initialize(VALUE self) {
|
|
|
197
199
|
cData->keyboard = 0;
|
|
198
200
|
cData->lockMouse = FALSE;
|
|
199
201
|
cData->lockKeyboard = FALSE;
|
|
200
|
-
rb_thread_create(ruby_initialize_thread,
|
|
202
|
+
rb_thread_create(ruby_initialize_thread, &self);
|
|
201
203
|
return Qnil;
|
|
202
204
|
}
|
|
203
205
|
|
|
@@ -7,23 +7,26 @@ inline BOOL ruby___keyboard_is_locked() {
|
|
|
7
7
|
return cLocked;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
#define RUBY___LOCK(flag) \
|
|
11
|
+
cLocked = flag;\
|
|
12
|
+
switch (ruby___special_input_device_get_mode_identifier()) {\
|
|
13
|
+
case MODE_INTERCEPTION:\
|
|
14
|
+
break;\
|
|
15
|
+
case MODE_WIN_API:\
|
|
16
|
+
rb_raise(rb_eRuntimeError, "WinAPI mode does not support lock mouse function.");\
|
|
17
|
+
default: {\
|
|
18
|
+
PCHAR cModeName = ruby___special_input_device_get_mode_name();\
|
|
19
|
+
rb_raise(rb_eRuntimeError, "Undefined mode '%s'.", cModeName);\
|
|
20
|
+
}\
|
|
21
|
+
}\
|
|
22
|
+
return self;
|
|
23
|
+
|
|
10
24
|
/*
|
|
11
25
|
* Lock the keyboard.
|
|
12
26
|
* @return [Module] self
|
|
13
27
|
*/
|
|
14
28
|
static VALUE ruby__lock(VALUE self) {
|
|
15
|
-
|
|
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;
|
|
29
|
+
RUBY___LOCK(TRUE)
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
/*
|
|
@@ -31,102 +34,114 @@ static VALUE ruby__lock(VALUE self) {
|
|
|
31
34
|
* @return [Module] self
|
|
32
35
|
*/
|
|
33
36
|
static VALUE ruby__unlock(VALUE self) {
|
|
34
|
-
|
|
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;
|
|
37
|
+
RUBY___LOCK(FALSE)
|
|
46
38
|
}
|
|
47
39
|
|
|
40
|
+
//region key
|
|
41
|
+
|
|
42
|
+
#define RUBY___GET_KEY_CODE() \
|
|
43
|
+
WORD cKeyCodes[cCount];\
|
|
44
|
+
UINT cScanCodes[cCount];\
|
|
45
|
+
INT cT;\
|
|
46
|
+
SCAN_ARGUMENTS("1*", NULL, NULL);\
|
|
47
|
+
for (cT = 0; cT < cCount; cT++) {\
|
|
48
|
+
cKeyCodes[cT] = NUM2USHORT(cArguments[cT]);\
|
|
49
|
+
cScanCodes[cT] = MapVirtualKeyA(cKeyCodes[cT], MAPVK_VK_TO_VSC);\
|
|
50
|
+
}\
|
|
51
|
+
|
|
52
|
+
#define RUBY___HOLD_RELEASE(interceptionState, winAPIFlag) \
|
|
53
|
+
RUBY___GET_KEY_CODE();\
|
|
54
|
+
switch (ruby___special_input_device_get_mode_identifier()) {\
|
|
55
|
+
case MODE_INTERCEPTION: {\
|
|
56
|
+
InterceptionContext cContext = ruby___interception_get_context();\
|
|
57
|
+
InterceptionDevice cDevice = ruby___interception_find_keyboard();\
|
|
58
|
+
InterceptionKeyStroke cStroke[cCount];\
|
|
59
|
+
for (cT = 0; cT < cCount; cT++) {\
|
|
60
|
+
cStroke[cT].code = (USHORT) cScanCodes[cT];\
|
|
61
|
+
cStroke[cT].information = 0;\
|
|
62
|
+
cStroke[cT].state = interceptionState;\
|
|
63
|
+
}\
|
|
64
|
+
interceptionSend(cContext, cDevice, (InterceptionStroke *) cStroke, (UINT) cCount);\
|
|
65
|
+
break;\
|
|
66
|
+
}\
|
|
67
|
+
case MODE_WIN_API: {\
|
|
68
|
+
INPUT cInput[cCount];\
|
|
69
|
+
for (cT = 0; cT < cCount; cT++) {\
|
|
70
|
+
cInput[cT].type = INPUT_KEYBOARD;\
|
|
71
|
+
cInput[cT].ki.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();\
|
|
72
|
+
cInput[cT].ki.dwFlags = winAPIFlag;\
|
|
73
|
+
cInput[cT].ki.time = 0;\
|
|
74
|
+
cInput[cT].ki.wScan = (WORD) cScanCodes[cT];\
|
|
75
|
+
cInput[cT].ki.wVk = cKeyCodes[cT];\
|
|
76
|
+
}\
|
|
77
|
+
if (!SendInput((UINT) cCount, cInput, sizeof(INPUT)))\
|
|
78
|
+
RAISE_WIN32_ERROR();\
|
|
79
|
+
break;\
|
|
80
|
+
}\
|
|
81
|
+
default: {\
|
|
82
|
+
PCHAR cModeName = ruby___special_input_device_get_mode_name();\
|
|
83
|
+
rb_raise(rb_eRuntimeError, "Undefined mode '%s'.", cModeName);\
|
|
84
|
+
}\
|
|
85
|
+
}\
|
|
86
|
+
return self;
|
|
87
|
+
|
|
48
88
|
/*
|
|
49
|
-
* @overload hold(key_code)
|
|
89
|
+
* @overload hold(key_code, *more)
|
|
50
90
|
* Simulate holding the specified key down.
|
|
51
91
|
* @param [Integer] key_code virtual key code. Use a value of constant in {SpecialInputDevice::KeyCode}.
|
|
92
|
+
* @param [Array[Integer]] more more key codes
|
|
52
93
|
* @return [Module] self
|
|
53
94
|
* @see SpecialInputDevice::Window#key_hold
|
|
54
95
|
* @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx Windows Dev Center - SendInput function
|
|
55
96
|
*/
|
|
56
|
-
static VALUE ruby__hold(
|
|
57
|
-
|
|
58
|
-
UINT cScanCode = MapVirtualKeyA(cKeyCode, MAPVK_VK_TO_VSC);
|
|
59
|
-
switch (ruby___special_input_device_get_mode_identifier()) {
|
|
60
|
-
case MODE_INTERCEPTION: {
|
|
61
|
-
InterceptionContext cContext = ruby___interception_get_context();
|
|
62
|
-
InterceptionDevice cDevice = ruby___interception_find_keyboard();
|
|
63
|
-
InterceptionKeyStroke cStroke;
|
|
64
|
-
cStroke.code = (USHORT) cScanCode;
|
|
65
|
-
cStroke.information = 0;
|
|
66
|
-
cStroke.state = INTERCEPTION_KEY_DOWN;
|
|
67
|
-
interceptionSend(cContext, cDevice, (InterceptionStroke const *) &cStroke, 1);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
case MODE_WIN_API: {
|
|
71
|
-
INPUT cInput;
|
|
72
|
-
cInput.type = INPUT_KEYBOARD;
|
|
73
|
-
cInput.ki.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();
|
|
74
|
-
cInput.ki.dwFlags = 0;
|
|
75
|
-
cInput.ki.time = 0;
|
|
76
|
-
cInput.ki.wScan = (WORD) cScanCode;
|
|
77
|
-
cInput.ki.wVk = cKeyCode;
|
|
78
|
-
if (SendInput(1, &cInput, sizeof(INPUT)) == 0)
|
|
79
|
-
RAISE_WIN32_ERROR();
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
default: {
|
|
83
|
-
PCHAR cModeName = ruby___special_input_device_get_mode_name();
|
|
84
|
-
rb_raise(rb_eRuntimeError, "Undefined mode '%s'.", cModeName);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return self;
|
|
97
|
+
static VALUE ruby__hold(VARIABLE_ARGUMENTS_C) {
|
|
98
|
+
RUBY___HOLD_RELEASE(INTERCEPTION_KEY_DOWN, 0)
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
/*
|
|
91
|
-
* @overload press(key_code)
|
|
102
|
+
* @overload press(key_code, *more)
|
|
92
103
|
* Simulate pressing the specified key.
|
|
93
104
|
* @param [Integer] key_code virtual key code. Use a value of constant in {SpecialInputDevice::KeyCode}.
|
|
105
|
+
* @param [Array[Integer]] more more key codes
|
|
94
106
|
* @return [Module] self
|
|
95
107
|
* @see SpecialInputDevice::Window#key_press
|
|
96
108
|
* @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx Windows Dev Center - SendInput function
|
|
97
109
|
*/
|
|
98
|
-
static VALUE ruby__press(
|
|
99
|
-
|
|
100
|
-
UINT cScanCode = MapVirtualKeyA(cKeyCode, MAPVK_VK_TO_VSC);
|
|
110
|
+
static VALUE ruby__press(VARIABLE_ARGUMENTS_C) {
|
|
111
|
+
RUBY___GET_KEY_CODE()
|
|
101
112
|
switch (ruby___special_input_device_get_mode_identifier()) {
|
|
102
113
|
case MODE_INTERCEPTION: {
|
|
103
114
|
InterceptionContext cContext = ruby___interception_get_context();
|
|
104
115
|
InterceptionDevice cDevice = ruby___interception_find_keyboard();
|
|
105
|
-
InterceptionKeyStroke cStroke[2];
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
InterceptionKeyStroke cStroke[cCount * 2];
|
|
117
|
+
for (cT = 0; cT < cCount; cT++) {
|
|
118
|
+
cStroke[cT * 2 + 0].code = (USHORT) cScanCodes[cT];
|
|
119
|
+
cStroke[cT * 2 + 0].information = 0;
|
|
120
|
+
cStroke[cT * 2 + 0].state = INTERCEPTION_KEY_DOWN;
|
|
121
|
+
cStroke[cT * 2 + 1].code = (USHORT) cScanCodes[cT];
|
|
122
|
+
cStroke[cT * 2 + 1].information = 0;
|
|
123
|
+
cStroke[cT * 2 + 1].state = INTERCEPTION_KEY_UP;
|
|
124
|
+
}
|
|
125
|
+
interceptionSend(cContext, cDevice, (InterceptionStroke *) cStroke, (UINT) cCount * 2);
|
|
113
126
|
break;
|
|
114
127
|
}
|
|
115
128
|
case MODE_WIN_API: {
|
|
116
|
-
INPUT cInput[2];
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
INPUT cInput[cCount * 2];
|
|
130
|
+
for (cT = 0; cT < cCount; cT++) {
|
|
131
|
+
cInput[cT * 2 + 0].type = INPUT_KEYBOARD;
|
|
132
|
+
cInput[cT * 2 + 0].ki.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();
|
|
133
|
+
cInput[cT * 2 + 0].ki.dwFlags = 0;
|
|
134
|
+
cInput[cT * 2 + 0].ki.time = 0;
|
|
135
|
+
cInput[cT * 2 + 0].ki.wScan = (WORD) cScanCodes[cT];
|
|
136
|
+
cInput[cT * 2 + 0].ki.wVk = cKeyCodes[cT];
|
|
137
|
+
cInput[cT * 2 + 1].type = INPUT_KEYBOARD;
|
|
138
|
+
cInput[cT * 2 + 1].ki.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();
|
|
139
|
+
cInput[cT * 2 + 1].ki.dwFlags = KEYEVENTF_KEYUP;
|
|
140
|
+
cInput[cT * 2 + 1].ki.time = 0;
|
|
141
|
+
cInput[cT * 2 + 1].ki.wScan = (WORD) cScanCodes[cT];
|
|
142
|
+
cInput[cT * 2 + 1].ki.wVk = cKeyCodes[cT];
|
|
143
|
+
}
|
|
144
|
+
if (!SendInput((UINT) cCount * 2, cInput, sizeof(INPUT)))
|
|
130
145
|
RAISE_WIN32_ERROR();
|
|
131
146
|
break;
|
|
132
147
|
}
|
|
@@ -139,47 +154,20 @@ static VALUE ruby__press(VALUE self, VALUE keyCode) {
|
|
|
139
154
|
}
|
|
140
155
|
|
|
141
156
|
/*
|
|
142
|
-
* @overload release(key_code)
|
|
157
|
+
* @overload release(key_code, *more)
|
|
143
158
|
* Simulate releasing the specified key.
|
|
144
159
|
* @param [Integer] key_code virtual key code. Use a value of constant in {SpecialInputDevice::KeyCode}.
|
|
160
|
+
* @param [Array[Integer]] more more key codes
|
|
145
161
|
* @return [Module] self
|
|
146
162
|
* @see SpecialInputDevice::Window#key_release
|
|
147
163
|
* @see https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310.aspx Windows Dev Center - SendInput function
|
|
148
164
|
*/
|
|
149
|
-
static VALUE ruby__release(
|
|
150
|
-
|
|
151
|
-
UINT cScanCode = MapVirtualKeyA(cKeyCode, MAPVK_VK_TO_VSC);
|
|
152
|
-
switch (ruby___special_input_device_get_mode_identifier()) {
|
|
153
|
-
case MODE_INTERCEPTION: {
|
|
154
|
-
InterceptionContext cContext = ruby___interception_get_context();
|
|
155
|
-
InterceptionDevice cDevice = ruby___interception_find_keyboard();
|
|
156
|
-
InterceptionKeyStroke cStroke;
|
|
157
|
-
cStroke.code = (USHORT) cScanCode;
|
|
158
|
-
cStroke.information = 0;
|
|
159
|
-
cStroke.state = INTERCEPTION_KEY_UP;
|
|
160
|
-
interceptionSend(cContext, cDevice, (InterceptionStroke const *) &cStroke, 2);
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
case MODE_WIN_API: {
|
|
164
|
-
INPUT cInput;
|
|
165
|
-
cInput.type = INPUT_KEYBOARD;
|
|
166
|
-
cInput.ki.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();
|
|
167
|
-
cInput.ki.dwFlags = KEYEVENTF_KEYUP;
|
|
168
|
-
cInput.ki.time = 0;
|
|
169
|
-
cInput.ki.wScan = (WORD) cScanCode;
|
|
170
|
-
cInput.ki.wVk = cKeyCode;
|
|
171
|
-
if (SendInput(1, &cInput, sizeof(INPUT)) == 0)
|
|
172
|
-
RAISE_WIN32_ERROR();
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
default: {
|
|
176
|
-
PCHAR cModeName = ruby___special_input_device_get_mode_name();
|
|
177
|
-
rb_raise(rb_eRuntimeError, "Undefined mode '%s'.", cModeName);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return self;
|
|
165
|
+
static VALUE ruby__release(VARIABLE_ARGUMENTS_C) {
|
|
166
|
+
RUBY___HOLD_RELEASE(INTERCEPTION_KEY_UP, KEYEVENTF_KEYUP)
|
|
181
167
|
}
|
|
182
168
|
|
|
169
|
+
//endregion key
|
|
170
|
+
|
|
183
171
|
VOID Init_keyboard() {
|
|
184
172
|
#ifdef YARD
|
|
185
173
|
specialInputDevice = rb_define_module("SpecialInputDevice");
|
|
@@ -190,7 +178,9 @@ VOID Init_keyboard() {
|
|
|
190
178
|
* The <code>Keyboard</code> module provides an interface to simulate the signal form keyboard.
|
|
191
179
|
*/
|
|
192
180
|
VALUE specialInputDevice_keyboard = rb_define_module_under(specialInputDevice, "Keyboard");
|
|
193
|
-
rb_define_singleton_method(specialInputDevice_keyboard, "
|
|
194
|
-
rb_define_singleton_method(specialInputDevice_keyboard, "
|
|
195
|
-
rb_define_singleton_method(specialInputDevice_keyboard, "
|
|
181
|
+
rb_define_singleton_method(specialInputDevice_keyboard, "lock", ruby__lock, 0);
|
|
182
|
+
rb_define_singleton_method(specialInputDevice_keyboard, "unlock", ruby__unlock, 0);
|
|
183
|
+
rb_define_singleton_method(specialInputDevice_keyboard, "hold", ruby__hold, -1);
|
|
184
|
+
rb_define_singleton_method(specialInputDevice_keyboard, "press", ruby__press, -1);
|
|
185
|
+
rb_define_singleton_method(specialInputDevice_keyboard, "release", ruby__release, -1);
|
|
196
186
|
}
|