├── .gitattributes
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── appveyor.yml
├── appveyor_build.bat
├── build.sh
├── command.h
├── commandlinetoargva.h
├── crc32.h
├── main.h
├── mouse.h
├── sendinput.c
├── sendinput.h
├── sendinput_io.c
├── sendkey.h
└── winmain.h
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.h linguist-language=C
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
54 | # builds
55 | build/*
56 | build_*/*
57 | cmake-build-*/*
58 |
59 | # codeblocks
60 | bin/*
61 | obj/*
62 | *.cbp
63 | *.depend
64 | *.layout
65 |
66 | # JetBrains
67 | .idea/*
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | project(sendinput C)
3 | if (NOT CMAKE_BUILD_TYPE)
4 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release." FORCE)
5 | endif (NOT CMAKE_BUILD_TYPE)
6 | set(CMAKE_C_STANDARD 11)
7 | set(HEADERS crc32.h mouse.h sendkey.h sendinput.h)
8 | add_executable(sendinput_io sendinput_io.c main.h commandlinetoargva.h ${HEADERS})
9 | add_executable(sendinput sendinput.c winmain.h ${HEADERS})
10 |
11 | if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
12 | set(CMAKE_C_FLAGS "-pipe -Wall -Wextra -fmerge-all-constants -Wl,--gc-sections,--build-id=none")
13 | set(CMAKE_C_FLAGS_DEBUG "-g -Og")
14 | set(CMAKE_C_FLAGS_RELEASE "-s -Os")
15 | if (WIN32)
16 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostartfiles -DNO_START_FILES")
17 | set_target_properties(sendinput PROPERTIES
18 | COMPILE_FLAGS "${CMAKE_C_FLAGS} -mwindows"
19 | LINK_FLAGS "${CMAKE_C_FLAGS} -mwindows")
20 | target_link_libraries(sendinput shlwapi)
21 | endif ()
22 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_C_FLAGS}")
23 | endif ()
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sendinput
2 | keyboard and mouse input simulator for windows
3 |
4 | ## Release
5 | [](https://github.com/myfreeer/sendinput/releases/latest)
6 | [](https://github.com/myfreeer/sendinput/releases)
7 |
8 | ## Usage
9 | See [Wiki/Usage](https://github.com/myfreeer/sendinput/wiki/Usage)
10 |
11 | ## Building
12 | ### Prerequisites
13 | * msys2 mingw64
14 | * git
15 | * mingw-w64-x86_64-gcc
16 | * mingw-w64-x86_64-cmake
17 | * mingw-w64-x86_64-ninja
18 |
19 | ### Build script example
20 | ```bash
21 | # Getting source
22 | git clone https://github.com/myfreeer/sendinput
23 | cd sendinput
24 |
25 | # Creating folder for build
26 | mkdir -p build
27 | cd build
28 |
29 | # Running cmake
30 | cmake -GNinja ..
31 |
32 | # Building with ninja
33 | ninja
34 | ```
35 |
36 | ## Credits
37 | *
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.0-{build}
2 | build_script:
3 | - cmd: >-
4 | appveyor_build.bat
5 | on_failure:
6 | - 7z a -mx9 -r fail.7z *.exe *.sln *.txt *.log
7 | - appveyor.exe PushArtifact fail.7z
8 | shallow_clone: true
9 | test: off
10 | artifacts:
11 | - path: sendinput_x64.exe
12 | - path: sendinput_x86.exe
13 | - path: sendinput_io_x64.exe
14 | - path: sendinput_io_x86.exe
15 | - path: sendinput.7z
16 | cache:
17 | - tests
18 | skip_commits:
19 | files:
20 | - 'LICENSE'
21 | - '*.md'
22 | - '.gitingore'
23 | - '.gitattributes'
24 | deploy:
25 | - provider: Environment
26 | name: github
27 | on:
28 | appveyor_repo_tag: true
29 |
--------------------------------------------------------------------------------
/appveyor_build.bat:
--------------------------------------------------------------------------------
1 | echo Syncing msys2 packages...
2 | C:\msys64\usr\bin\pacman -Sq --noconfirm --needed --noprogressbar --ask=20 mingw-w64-x86_64-ninja mingw-w64-i686-ninja
3 | rem C:\msys64\usr\bin\pacman -Scq --noconfirm
4 |
5 | echo Building and testing 64-bit version...
6 | set MSYSTEM=MINGW64
7 | call C:\msys64\usr\bin\bash -lc "cd \"$APPVEYOR_BUILD_FOLDER\" && exec ./build.sh"
8 | move /Y .\build_x86_64-w64-mingw32\sendinput.exe .\sendinput_x64.exe
9 | move /Y .\build_x86_64-w64-mingw32\sendinput_io.exe .\sendinput_io_x64.exe
10 |
11 | echo Building and testing 32-bit version...
12 | set MSYSTEM=MINGW32
13 | call C:\msys64\usr\bin\bash -lc "cd \"$APPVEYOR_BUILD_FOLDER\" && exec ./build.sh"
14 | move /Y .\build_i686-w64-mingw32\sendinput.exe .\sendinput_x86.exe
15 | move /Y .\build_i686-w64-mingw32\sendinput_io.exe .\sendinput_io_x86.exe
16 |
17 | echo Packaging...
18 | 7z a -mx9 sendinput.7z .\sendinput_x64.exe .\sendinput_x86.exe .\sendinput_io_x64.exe .\sendinput_io_x86.exe
19 | echo Done.
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | MACHINE="$(gcc -dumpmachine)"
3 | echo Building...
4 | mkdir -p "build_${MACHINE}"
5 | cd "build_${MACHINE}"
6 | cmake -GNinja ..
7 | ninja
8 | cd ..
9 |
--------------------------------------------------------------------------------
/command.h:
--------------------------------------------------------------------------------
1 | #ifndef WIN32_LEAN_AND_MEAN
2 | #define WIN32_LEAN_AND_MEAN
3 | #endif
4 | #include
5 | #include
6 | #include "mouse.h"
7 | #include "sendkey.h"
8 |
9 | #define COMMAND_MAX_LENGTH 16
10 | static WORD ParseCommand(const uint32_t hash) {
11 | switch (hash) {
12 | case 4213349504U: // BACKSPACE
13 | case 1911832374U: // BS
14 | case 2523624168U: // BKSP
15 | return VK_BACK;
16 | case 3727033226U: // SPACE
17 | return VK_SPACE;
18 | case 3846439302U: // TAB
19 | return VK_TAB;
20 | case 317010870U: // CLEAR
21 | return VK_CLEAR;
22 | case 1310982878U: // ENTER
23 | return VK_RETURN;
24 | case 1382021621U: // SHIFT
25 | return VK_SHIFT;
26 | case 884448462U: // CTRL
27 | return VK_CONTROL;
28 | case 3201542913U: // ALT
29 | return VK_MENU;
30 | case 550391901U: // PAUSE
31 | return VK_PAUSE;
32 | case 2439287330U: // CAPS
33 | case 3274666208U: // CAPSLOCK
34 | return VK_CAPITAL;
35 | case 4149446788U: // ESC
36 | return VK_ESCAPE;
37 | case 82448359U: // PAGEUP
38 | case 859550494U: // PGUP
39 | return VK_PRIOR;
40 | case 1528306972U: // PAGEDOWN
41 | case 2599267693U: // PGDN
42 | return VK_NEXT;
43 | case 2522575163U: // END
44 | return VK_END;
45 | case 1195630948U: // HOME
46 | return VK_HOME;
47 | case 3864525061U: // LEFTARROW
48 | case 1290930908U: // LEFT
49 | return VK_LEFT;
50 | case 156158474U: // UPARROW
51 | case 3984517658U: // UP
52 | return VK_UP;
53 | case 112782023U: // RIGHTARROW
54 | case 1134475172U: // RIGHT
55 | return VK_RIGHT;
56 | case 2947281234U: // DOWNARROW
57 | case 711622031U: // DOWN
58 | return VK_DOWN;
59 | case 3138006342U: // SELECT
60 | return VK_SELECT;
61 | case 3800219350U: // PRINT
62 | return VK_PRINT;
63 | case 3223776964U: // EXECUTE
64 | return VK_EXECUTE;
65 | case 2836567439U: // PRINTSCREEN
66 | case 2328061742U: // PRTSC
67 | return VK_SNAPSHOT;
68 | case 479333784U: // INS
69 | case 892623219U: // INSERT
70 | return VK_INSERT;
71 | case 2058767093U: // DEL
72 | case 3404380929U: // DELETE
73 | return VK_DELETE;
74 | case 1041412376U: // HELP
75 | return VK_HELP;
76 | case 1256517092U: // NUM
77 | case 3844504896U: // NUMLOCK
78 | return VK_NUMLOCK;
79 | case 2251377965U: // SCROLLLOCK
80 | return VK_SCROLL;
81 | case 4067218798U: // LEFTWINDOWS
82 | case 699046007U: // LWIN
83 | return VK_LWIN;
84 | case 2401157523U: // RIGHTWINDOWS
85 | case 2574039259U: // RWIN
86 | return VK_RWIN;
87 | case 1660628960U: // APPLICATIONS
88 | return VK_APPS;
89 | case 1771420896U: // COMPUTERSLEEP
90 | return VK_SLEEP;
91 | case 3615866119U: // MULTIPLY
92 | return VK_MULTIPLY;
93 | case 1807561069U: // ADD
94 | return VK_ADD;
95 | case 3543192423U: // SEPARATOR
96 | return VK_SEPARATOR;
97 | case 3882583749U: // SUBTRACT
98 | return VK_SUBTRACT;
99 | case 1706577289U: // DECIMAL
100 | return VK_DECIMAL;
101 | case 1936067278U: // DIVIDE
102 | return VK_DIVIDE;
103 | case 1408638381U: // NUM0
104 | case 2111931934U: // NUMPAD0
105 | return VK_NUMPAD0;
106 | case 619785531U: // NUM1
107 | case 182892168U: // NUMPAD1
108 | return VK_NUMPAD1;
109 | case 3187178625U: // NUM2
110 | case 2481973042U: // NUMPAD2
111 | return VK_NUMPAD2;
112 | case 3405728791U: // NUM3
113 | case 3840464804U: // NUMPAD3
114 | return VK_NUMPAD3;
115 | case 1419499956U: // NUM4
116 | case 2056012295U: // NUMPAD4
117 | return VK_NUMPAD4;
118 | case 597485858U: // NUM5
119 | case 227242641U: // NUMPAD5
120 | return VK_NUMPAD5;
121 | case 3130374296U: // NUM6
122 | case 2491556651U: // NUMPAD6
123 | return VK_NUMPAD6;
124 | case 3448932366U: // NUM7
125 | case 3817149373U: // NUMPAD7
126 | return VK_NUMPAD7;
127 | case 1563268511U: // NUM8
128 | case 1933184556U: // NUMPAD8
129 | return VK_NUMPAD8;
130 | case 707437833U: // NUM9
131 | case 71122618U: // NUMPAD9
132 | return VK_NUMPAD9;
133 | case 3055876678U: // F1
134 | return VK_F1;
135 | case 791522300U: // F2
136 | return VK_F2;
137 | case 1479187306U: // F3
138 | return VK_F3;
139 | case 3327004361U: // F4
140 | return VK_F4;
141 | case 2974367327U: // F5
142 | return VK_F5;
143 | case 675311589U: // F6
144 | return VK_F6;
145 | case 1598513011U: // F7
146 | return VK_F7;
147 | case 3489153762U: // F8
148 | return VK_F8;
149 | case 3103748724U: // F9
150 | return VK_F9;
151 | case 1808932734U: // F10
152 | return VK_F10;
153 | case 483733480U: // F11
154 | return VK_F11;
155 | case 2245819986U: // F12
156 | return VK_F12;
157 | case 4074458820U: // F13
158 | return VK_F13;
159 | case 1824512871U: // F14
160 | return VK_F14;
161 | case 465103857U: // F15
162 | return VK_F15;
163 | case 2192685643U: // F16
164 | return VK_F16;
165 | case 4122381021U: // F17
166 | return VK_F17;
167 | case 1695127372U: // F18
168 | return VK_F18;
169 | case 302950362U: // F19
170 | return VK_F19;
171 | case 1090473149U: // F20
172 | return VK_F20;
173 | case 939031595U: // F21
174 | return VK_F21;
175 | case 2935041425U: // F22
176 | return VK_F22;
177 | case 3656785159U: // F23
178 | return VK_F23;
179 | case 1200785572U: // F24
180 | return VK_F24;
181 | case 2607492222U: // LEFTSHIFT
182 | case 1562731868U: // LSHIFT
183 | return VK_LSHIFT;
184 | case 2072264636U: // RIGHTSHIFT
185 | case 1694041783U: // RSHIFT
186 | return VK_RSHIFT;
187 | case 4233133246U: // LEFTCONTROL
188 | case 1322385799U: // LCTRL
189 | return VK_LCONTROL;
190 | case 2166515779U: // RIGHTCONTROL
191 | case 2432837732U: // RCTRL
192 | return VK_RCONTROL;
193 | case 1936054868U: // LEFTMENU
194 | case 838158958U: // LMENU
195 | case 2970897034U: // LALT
196 | return VK_LMENU;
197 | case 1235158622U: // RIGHTMENU
198 | case 3995427725U: // RMENU
199 | case 30566950U: // RALT
200 | return VK_RMENU;
201 | case 3954267447U: // IMEPROCESS
202 | return VK_PROCESSKEY;
203 | case 1710951019U: // LBUTTON
204 | return VK_LBUTTON;
205 | case 1377496568U: // RBUTTON
206 | return VK_RBUTTON;
207 | case 2800616180U: // CANCEL
208 | return VK_CANCEL;
209 | case 3280732639U: // MBUTTON
210 | return VK_MBUTTON;
211 | case 2703791036U: // XBUTTON1
212 | return VK_XBUTTON1;
213 | case 941736454U: // XBUTTON2
214 | return VK_XBUTTON2;
215 | case 1945007743U: // BROWSERBACK
216 | return VK_BROWSER_BACK;
217 | case 2673191389U: // BROWSERFORWARD
218 | return VK_BROWSER_FORWARD;
219 | case 407185056U: // BROWSERREFRESH
220 | return VK_BROWSER_REFRESH;
221 | case 2809569790U: // BROWSERSTOP
222 | return VK_BROWSER_STOP;
223 | case 2009014991U: // BROWSERSEARCH
224 | return VK_BROWSER_SEARCH;
225 | case 387432145U: // BROWSERFAVORITES
226 | return VK_BROWSER_FAVORITES;
227 | case 1878440856U: // BROWSERHOME
228 | return VK_BROWSER_HOME;
229 | case 2714356834U: // VOLUMEMUTE
230 | case 4197228264U: // MUTE
231 | return VK_VOLUME_MUTE;
232 | case 1905209093U: // VOLUMEDOWN
233 | case 2053074917U: // VDOWN
234 | return VK_VOLUME_DOWN;
235 | case 2143919418U: // VOLUMEUP
236 | case 1003975669U: // VUP
237 | return VK_VOLUME_UP;
238 | case 2145333128U: // MEDIANEXTTRACK
239 | return VK_MEDIA_NEXT_TRACK;
240 | case 644010588U: // MEDIAPREVTRACK
241 | return VK_MEDIA_PREV_TRACK;
242 | case 4222509918U: // MEDIASTOP
243 | case 3368439803U: // MSTOP
244 | return VK_MEDIA_STOP;
245 | case 1261637064U: // MEDIAPLAYPAUSE
246 | case 790202359U: // MPLAY
247 | return VK_MEDIA_PLAY_PAUSE;
248 | case 11509296U: // LAUNCHMAIL
249 | return VK_LAUNCH_MAIL;
250 | case 3101998649U: // LAUNCHMEDIASELECT
251 | return VK_LAUNCH_MEDIA_SELECT;
252 | default:break;
253 | }
254 | return FALSE;
255 | }
256 |
257 | static BOOL ParseCommandWithParams(const uint32_t hash, const int params[],
258 | const unsigned char paramCount) {
259 | if (paramCount == 1) {
260 | switch (hash) {
261 | case 4167499804U: // SLEEP
262 | case 1266380369U: // WAIT
263 | Sleep((DWORD) params[0]);
264 | return TRUE;
265 | case 2439287330U: // CAPS
266 | case 3274666208U: // CAPSLOCK
267 | SetKeyState((BOOL) params[0], VK_CAPITAL);
268 | return TRUE;
269 | case 1256517092U: // NUM
270 | case 3844504896U: // NUMLOCK
271 | SetKeyState((BOOL) params[0], VK_NUMLOCK);
272 | return TRUE;
273 | case 2251377965U: // SCROLLLOCK
274 | SetKeyState((BOOL) params[0], VK_SCROLL);
275 | return TRUE;
276 | default:break;
277 | }
278 | } else if (paramCount == 2) {
279 | switch (hash) {
280 | case 1302462608U: // CLICK
281 | case 1121492025U: // LCLICK
282 | case 2224477467U: // LEFTCLICK
283 | MouseClick((const unsigned int) params[0], (const unsigned int) params[1], 0);
284 | return TRUE;
285 | case 2063925202U: // RCLICK
286 | case 1685702361U: // RIGHTCLICK
287 | MouseClick((const unsigned int) params[0], (const unsigned int) params[1], 1);
288 | return TRUE;
289 | case 2307149724U: // MCLICK
290 | case 1843602477U: // MIDDLECLICK
291 | MouseClick((const unsigned int) params[0], (const unsigned int) params[1], 2);
292 | return TRUE;
293 | case 2858569247U: // MOUSEMOVE
294 | SetCursorPos(params[0], params[1]);
295 | return TRUE;
296 | default:break;
297 | }
298 | }
299 | return FALSE;
300 | }
301 |
302 |
303 | BOOL ParseKeyCombination(const char param[][COMMAND_MAX_LENGTH],
304 | const WORD paramLength[],
305 | const unsigned char paramCount) {
306 | WORD keyCode[paramCount];
307 | uint32_t hash[paramCount];
308 | for (unsigned char i = 0; i < paramCount; i++) {
309 | hash[i] = crc32(param[i], paramLength[i]);
310 | keyCode[i] = ParseCommand(hash[i]);
311 | if (!keyCode[i] && paramLength[i] == 1) {
312 | SHORT vKeyCode = VkKeyScan(param[i][0]);
313 | if (vKeyCode >> 8 == 0 || vKeyCode >> 8 == 1)
314 | keyCode[i] = (WORD) (vKeyCode & 0xFF);
315 | }
316 | if (!keyCode[i])
317 | return FALSE;
318 | }
319 | SendMultipleKey(keyCode, paramCount);
320 | return TRUE;
321 | }
322 |
--------------------------------------------------------------------------------
/commandlinetoargva.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #ifndef COMMANDLINETOARGVA_H
3 | #define COMMANDLINETOARGVA_H
4 |
5 | #include
6 | #include
7 | // https://github.com/wine-mirror/wine/blob/5946973021285dd6ecb8df224956fea4817f8fed/dlls/shell32/shell32_main.c
8 | // https://github.com/futurist/CommandLineToArgvA/blob/09765ffef215f0a066d6b0ea5c1edda88b6739af/CommandLineToArgvA.c
9 | /*************************************************************************
10 | * CommandLineToArgvA [SHELL32.@]
11 | *
12 | * We must interpret the quotes in the command line to rebuild the argv
13 | * array correctly:
14 | * - arguments are separated by spaces or tabs
15 | * - quotes serve as optional argument delimiters
16 | * '"a b"' -> 'a b'
17 | * - escaped quotes must be converted back to '"'
18 | * '\"' -> '"'
19 | * - consecutive backslashes preceding a quote see their number halved with
20 | * the remainder escaping the quote:
21 | * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
22 | * 2n+1 backslashes + quote -> n backslashes + literal quote
23 | * - backslashes that are not followed by a quote are copied literally:
24 | * 'a\b' -> 'a\b'
25 | * 'a\\b' -> 'a\\b'
26 | * - in quoted strings, consecutive quotes see their number divided by three
27 | * with the remainder modulo 3 deciding whether to close the string or not.
28 | * Note that the opening quote must be counted in the consecutive quotes,
29 | * that's the (1+) below:
30 | * (1+) 3n quotes -> n quotes
31 | * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
32 | * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
33 | * - in unquoted strings, the first quote opens the quoted string and the
34 | * remaining consecutive quotes follow the above rule.
35 | */
36 | LPSTR WINAPI *CommandLineToArgvA(LPCSTR lpCmdline, int *numargs) {
37 | DWORD argc;
38 | LPSTR *argv;
39 | LPCSTR s;
40 | LPSTR d;
41 | LPSTR cmdline;
42 | int qcount, bcount;
43 |
44 | if (!numargs) {
45 | SetLastError(ERROR_INVALID_PARAMETER);
46 | return NULL;
47 | }
48 |
49 | if (lpCmdline == NULL || *lpCmdline == 0) {
50 | /* Return the path to the executable */
51 | DWORD len, deslen = MAX_PATH, size;
52 |
53 | size = sizeof(LPSTR) * 2 + deslen * sizeof(char);
54 | for (;;) {
55 | if (!(argv = LocalAlloc(LMEM_FIXED, size)))
56 | return NULL;
57 | len = GetModuleFileNameA(0, (LPSTR)(argv + 2), deslen);
58 | if (!len) {
59 | LocalFree(argv);
60 | return NULL;
61 | }
62 | if (len < deslen)
63 | break;
64 | deslen *= 2;
65 | size = sizeof(LPSTR) * 2 + deslen * sizeof(char);
66 | LocalFree(argv);
67 | }
68 | argv[0] = (LPSTR)(argv + 2);
69 | argv[1] = NULL;
70 | *numargs = 1;
71 |
72 | return argv;
73 | }
74 |
75 | /* --- First count the arguments */
76 | argc = 1;
77 | s = lpCmdline;
78 | /* The first argument, the executable path, follows special rules */
79 | if (*s == '"') {
80 | /* The executable path ends at the next quote, no matter what */
81 | s++;
82 | while (*s)
83 | if (*s++ == '"')
84 | break;
85 | } else {
86 | /* The executable path ends at the next space, no matter what */
87 | while (*s && *s != ' ' && *s != '\t')
88 | s++;
89 | }
90 | /* skip to the first argument, if any */
91 | while (*s == ' ' || *s == '\t')
92 | s++;
93 | if (*s)
94 | argc++;
95 |
96 | /* Analyze the remaining arguments */
97 | qcount = bcount = 0;
98 | while (*s) {
99 | if ((*s == ' ' || *s == '\t') && qcount == 0) {
100 | /* skip to the next argument and count it if any */
101 | while (*s == ' ' || *s == '\t')
102 | s++;
103 | if (*s)
104 | argc++;
105 | bcount = 0;
106 | } else if (*s == '\\') {
107 | /* '\', count them */
108 | bcount++;
109 | s++;
110 | } else if (*s == '"') {
111 | /* '"' */
112 | if ((bcount & 1) == 0)
113 | qcount++; /* unescaped '"' */
114 | s++;
115 | bcount = 0;
116 | /* consecutive quotes, see comment in copying code below */
117 | while (*s == '"') {
118 | qcount++;
119 | s++;
120 | }
121 | qcount = qcount % 3;
122 | if (qcount == 2)
123 | qcount = 0;
124 | } else {
125 | /* a regular character */
126 | bcount = 0;
127 | s++;
128 | }
129 | }
130 |
131 | /* Allocate in a single lump, the string array, and the strings that go
132 | * with it. This way the caller can make a single LocalFree() call to free
133 | * both, as per MSDN.
134 | */
135 | argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(LPSTR) +
136 | (strlen(lpCmdline) + 1) * sizeof(char));
137 | if (!argv)
138 | return NULL;
139 | cmdline = (LPSTR)(argv + argc + 1);
140 | strcpy(cmdline, lpCmdline);
141 |
142 | /* --- Then split and copy the arguments */
143 | argv[0] = d = cmdline;
144 | argc = 1;
145 | /* The first argument, the executable path, follows special rules */
146 | if (*d == '"') {
147 | /* The executable path ends at the next quote, no matter what */
148 | s = d + 1;
149 | while (*s) {
150 | if (*s == '"') {
151 | s++;
152 | break;
153 | }
154 | *d++ = *s++;
155 | }
156 | } else {
157 | /* The executable path ends at the next space, no matter what */
158 | while (*d && *d != ' ' && *d != '\t')
159 | d++;
160 | s = d;
161 | if (*s)
162 | s++;
163 | }
164 | /* close the executable path */
165 | *d++ = 0;
166 | /* skip to the first argument and initialize it if any */
167 | while (*s == ' ' || *s == '\t')
168 | s++;
169 | if (!*s) {
170 | /* There are no parameters so we are all done */
171 | argv[argc] = NULL;
172 | *numargs = argc;
173 | return argv;
174 | }
175 |
176 | /* Split and copy the remaining arguments */
177 | argv[argc++] = d;
178 | qcount = bcount = 0;
179 | while (*s) {
180 | if ((*s == ' ' || *s == '\t') && qcount == 0) {
181 | /* close the argument */
182 | *d++ = 0;
183 | bcount = 0;
184 |
185 | /* skip to the next one and initialize it if any */
186 | do {
187 | s++;
188 | } while (*s == ' ' || *s == '\t');
189 | if (*s)
190 | argv[argc++] = d;
191 | } else if (*s == '\\') {
192 | *d++ = *s++;
193 | bcount++;
194 | } else if (*s == '"') {
195 | if ((bcount & 1) == 0) {
196 | /* Preceded by an even number of '\', this is half that
197 | * number of '\', plus a quote which we erase.
198 | */
199 | d -= bcount / 2;
200 | qcount++;
201 | } else {
202 | /* Preceded by an odd number of '\', this is half that
203 | * number of '\' followed by a '"'
204 | */
205 | d = d - bcount / 2 - 1;
206 | *d++ = '"';
207 | }
208 | s++;
209 | bcount = 0;
210 | /* Now count the number of consecutive quotes. Note that qcount
211 | * already takes into account the opening quote if any, as well as
212 | * the quote that lead us here.
213 | */
214 | while (*s == '"') {
215 | if (++qcount == 3) {
216 | *d++ = '"';
217 | qcount = 0;
218 | }
219 | s++;
220 | }
221 | if (qcount == 2)
222 | qcount = 0;
223 | } else {
224 | /* a regular character */
225 | *d++ = *s++;
226 | bcount = 0;
227 | }
228 | }
229 | *d = '\0';
230 | argv[argc] = NULL;
231 | *numargs = argc;
232 |
233 | return argv;
234 | }
235 | #endif
236 |
--------------------------------------------------------------------------------
/crc32.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | static const uint32_t crc32tab[256] = {
4 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
5 | 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
6 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
7 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
8 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
9 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
10 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
11 | 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
12 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
13 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
14 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
15 | 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
16 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
17 | 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
18 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
19 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
20 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
21 | 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
22 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
23 | 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
24 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
25 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
26 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
27 | 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
28 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
29 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
30 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
31 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
32 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
33 | 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
34 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
35 | 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
36 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
37 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
38 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
39 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
40 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
41 | 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
42 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
43 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
44 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
45 | 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
46 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
47 | 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
48 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
49 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
50 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
51 | 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
52 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
53 | 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
54 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
55 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
56 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
57 | 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
58 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
59 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
60 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
61 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
62 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
63 | 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
64 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
65 | 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
66 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
67 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
68 | };
69 |
70 | uint32_t crc32(const char * buf, size_t size) {
71 | uint32_t crc = 0xFFFFFFFF;
72 | for (size_t i = 0; i < size; i++)
73 | crc = crc32tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
74 | return crc ^ 0xFFFFFFFF;
75 | }
--------------------------------------------------------------------------------
/main.h:
--------------------------------------------------------------------------------
1 | // Small alternative startfile for main()
2 | // Build with gcc perms:
3 | // -nostartfiles
4 | #pragma once
5 | #ifndef STARTFILE_MAIN_H
6 | #define STARTFILE_MAIN_H
7 | #include
8 |
9 | #ifdef UNICODE
10 | #define wmain(argc, argv) _wmain(argc, argv)
11 | int wmain(int argc, wchar_t *argv[]);
12 | #else
13 | #include "commandlinetoargva.h"
14 | // workaround undefined reference to `_pei386_runtime_relocator'
15 | #define main(argc, argv) _main(argc, argv)
16 | int main(int argc, char *argv[]);
17 | #endif
18 | int __cdecl mainCRTStartup() {
19 | int __arg_c;
20 | #ifdef UNICODE
21 | wchar_t **__arg_v = CommandLineToArgvW(GetCommandLineW(), &__arg_c);
22 | const int exitCode = wmain(__arg_c, __arg_v);
23 | #else
24 | char **__arg_v = CommandLineToArgvA(GetCommandLineA(), &__arg_c);
25 | const int exitCode = main(__arg_c, __arg_v);
26 | #endif
27 | LocalFree(__arg_v);
28 | ExitProcess(exitCode);
29 | return exitCode;
30 | }
31 | #endif
32 |
--------------------------------------------------------------------------------
/mouse.h:
--------------------------------------------------------------------------------
1 | #ifndef WIN32_LEAN_AND_MEAN
2 | #define WIN32_LEAN_AND_MEAN
3 | #endif
4 | #include
5 |
6 | static void MouseClick(const unsigned int x, const unsigned int y,
7 | const unsigned char type) {
8 | SetCursorPos(x, y);
9 | INPUT input;
10 | ZeroMemory(&input, sizeof(input));
11 | input.type = INPUT_MOUSE;
12 | switch (type) {
13 | case 1:
14 | input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
15 | SendInput(1, &input, sizeof(input));
16 | input.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
17 | break;
18 | case 2:
19 | input.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
20 | SendInput(1, &input, sizeof(input));
21 | input.mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
22 | break;
23 | default:
24 | input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
25 | SendInput(1, &input, sizeof(input));
26 | input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
27 | }
28 | SendInput(1, &input, sizeof(input));
29 | }
--------------------------------------------------------------------------------
/sendinput.c:
--------------------------------------------------------------------------------
1 | #include "sendinput.h"
2 | #ifdef NO_START_FILES
3 | #include "winmain.h"
4 | #endif
5 | #ifndef __GNUC__
6 | #define UNUSED
7 | #else // __GNUC__
8 | #define UNUSED __attribute__((unused))
9 | #endif // __GNUC__
10 |
11 | void EmitError(const unsigned short errorCode) {
12 | MessageBox(NULL, ErrorInfo[errorCode], NULL,
13 | MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
14 | }
15 |
16 | // main entry
17 | int WINAPI WinMain(HINSTANCE UNUSED hInstance, HINSTANCE UNUSED hPrevInstance,
18 | LPSTR lpCmdLine, int UNUSED nShowCmd) {
19 | unsigned int cmdLineLength = (unsigned int) lstrlen(lpCmdLine);
20 | if (cmdLineLength == 0) {
21 | return 1;
22 | }
23 | ParseSendKeys(lpCmdLine, cmdLineLength);
24 | return 0;
25 | }
--------------------------------------------------------------------------------
/sendinput.h:
--------------------------------------------------------------------------------
1 | #ifndef SENDINPUT_H
2 | #define SENDINPUT_H
3 |
4 | #ifndef WIN32_LEAN_AND_MEAN
5 | #define WIN32_LEAN_AND_MEAN
6 | #endif
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "crc32.h"
14 | #include "command.h"
15 |
16 | extern void EmitError(unsigned short);
17 | const LPSTR ErrorInfo[] = {
18 | "no error",
19 | "keyCodeCombine == -1, VkKeyScan fails",
20 | "unknown high-order byte of VkKeyScan's return value",
21 | "cannot get high-order byte from VkKeyScan"
22 | };
23 | static const unsigned char vkeyCodeCombine[3] = {
24 | VK_SHIFT, // shift
25 | VK_CONTROL, // ctrl
26 | VK_MENU // alt
27 | };
28 |
29 | void ParseSendKeys(const char *keyString, size_t length) {
30 | if (length < 1)
31 | return;
32 | for (size_t index = 0; index < length;) {
33 | if (index & 0x200)
34 | Sleep(1); // workaround: preventing mistype by waiting for a while
35 | if (keyString[index] == '\r' && keyString[index + 1] == '\n') {
36 | // skip cr-lf line endings
37 | ++index;
38 | }
39 | if (length - index > 4 && keyString[index] == '$' && keyString[index + 1] == '{') {
40 | char param[3][COMMAND_MAX_LENGTH] = {{0}};
41 | if (sscanf(keyString + index, "${%15[A-Z0-9]}", param[0]) == 1) {
42 | const size_t offset = 3 + strnlen(param[0], COMMAND_MAX_LENGTH);
43 | if (keyString[index + offset - 1] == '}') {
44 | const uint32_t hash = crc32(param[0], offset - 3);
45 | if (hash == 1005452284) { // DOLLAR
46 | ParseSendKeys("$", 1);
47 | index += offset;
48 | continue;
49 | } else {
50 | const WORD keyCode = ParseCommand(hash);
51 | if (keyCode) {
52 | SendSingleKey(keyCode);
53 | index += offset;
54 | continue;
55 | }
56 | }
57 | }
58 | }
59 | if (sscanf(keyString + index, "${%15[A-Z] %9[0-9]}", param[0], param[1]) == 2) {
60 | const size_t offset = 4 + strnlen(param[0], COMMAND_MAX_LENGTH) +
61 | strnlen(param[1], COMMAND_MAX_LENGTH);
62 | if (keyString[index + offset - 1] == '}') {
63 | const int paramInt = atoi(param[1]);
64 | if (ParseCommandWithParams(
65 | crc32(param[0], strnlen(param[0], COMMAND_MAX_LENGTH)),
66 | ¶mInt, 1)) {
67 |
68 | index += offset;
69 | continue;
70 | }
71 | }
72 | }
73 | if (sscanf(keyString + index, "${%15[A-Z]+%15[0-9A-Za-z]}", param[0], param[1]) == 2) {
74 | WORD paramLength[2];
75 | for (unsigned char i = 0; i < 2; i++)
76 | paramLength[i] = (WORD) strnlen(param[i], COMMAND_MAX_LENGTH);
77 | const size_t offset = 4 + paramLength[0] + paramLength[1];
78 | if (keyString[index + offset - 1] == '}') {
79 | if (ParseKeyCombination(param, paramLength, 2)) {
80 |
81 | index += offset;
82 | continue;
83 | }
84 | }
85 | }
86 | if (sscanf(keyString + index, "${%15[A-Z] %9[0-9] %9[0-9]}", param[0], param[1],
87 | param[2]) == 3) {
88 | const size_t offset = 5 + strnlen(param[0], COMMAND_MAX_LENGTH) +
89 | strnlen(param[1], COMMAND_MAX_LENGTH) +
90 | strnlen(param[2], COMMAND_MAX_LENGTH);
91 | if (keyString[offset + index - 1] == '}') {
92 | int paramInt[2];
93 | paramInt[0] = atoi(param[1]);
94 | paramInt[1] = atoi(param[2]);
95 | if (ParseCommandWithParams(
96 | crc32(param[0], strnlen(param[0], COMMAND_MAX_LENGTH)),
97 | paramInt, 2)) {
98 |
99 | index += offset;
100 | continue;
101 | }
102 | }
103 | }
104 | if (sscanf(keyString + index, "${%15[A-Z]+%15[0-9A-Za-z]+%15[0-9A-Za-z]}",
105 | param[0], param[1], param[2]) == 3) {
106 | WORD paramLength[3];
107 | for (unsigned char i = 0; i < 3; i++) {
108 | paramLength[i] = (WORD) strnlen(param[i], COMMAND_MAX_LENGTH);
109 | };
110 | const size_t offset =
111 | 5 + paramLength[0] + paramLength[1] + paramLength[2];
112 | if (keyString[offset + index - 1] == '}') {
113 | if (ParseKeyCombination(param, paramLength, 3)) {
114 |
115 | index += offset;
116 | continue;
117 | }
118 | }
119 | }
120 | }
121 |
122 | // const SHORT vKeyCode = VkKeyScanEx(keyString[0],GetKeyboardLayout(0));
123 | const SHORT vKeyCode = VkKeyScan(keyString[index]);
124 |
125 | WORD keyCode[3] = {0};
126 | keyCode[0] = (WORD) (vKeyCode & 0xFF);
127 | const WORD keyCodeCombine = (const WORD) (vKeyCode >> 8);
128 | if (vKeyCode == -1) {
129 | EmitError(1); // VkKeyScan fails
130 | ++index;
131 | continue;
132 | }
133 | if (keyCodeCombine == 0) {
134 | SendSingleKey(keyCode[0]);
135 | ++index;
136 | continue;
137 | }
138 | unsigned char keyCount = 0;
139 | for (unsigned char i = 0; i < 3; i++) {
140 | if (((keyCodeCombine >> i) & 0x1) == 1) {
141 | keyCode[keyCount + 1] = keyCode[keyCount];
142 | keyCode[keyCount] = vkeyCodeCombine[i];
143 | keyCount++;
144 | }
145 | }
146 | if (keyCount > 0)
147 | SendMultipleKey(keyCode, (const unsigned short) (keyCount + 1));
148 | else {
149 | if (keyCodeCombine > 4)
150 | EmitError(2); // unknown high-order byte of VkKeyScan's return value
151 | else
152 | EmitError(3); // cannot get high-order byte from VkKeyScan
153 | SendSingleKey(keyCode[0]);
154 | }
155 | ++index;
156 | }
157 | }
158 |
159 | #endif //SENDINPUT_H
160 |
--------------------------------------------------------------------------------
/sendinput_io.c:
--------------------------------------------------------------------------------
1 | #include "sendinput.h"
2 | #ifdef NO_START_FILES
3 | #include "main.h"
4 | #endif
5 | #define BLOCK_SIZE 4096
6 |
7 | char *readStdIn(size_t *size) {
8 | int c = 0;
9 | char *buf = malloc(sizeof(char) * BLOCK_SIZE);
10 | size_t bufSize = BLOCK_SIZE, currSize = 0;
11 | while ((c = getchar()) != EOF) {
12 | if (currSize + 1 > bufSize) {
13 | if (!(buf = realloc(buf, bufSize + BLOCK_SIZE))) {
14 | return NULL;
15 | }
16 | bufSize += BLOCK_SIZE;
17 | }
18 | buf[currSize++] = (char) c;
19 | }
20 | buf[currSize] = '\0';
21 | *size = currSize;
22 | return buf;
23 | }
24 |
25 | char *readFile(const char *fileName, size_t *size) {
26 | /* declare a file pointer */
27 | FILE *filePtr = fopen(fileName, "rb");
28 | /* quit if the file does not exist */
29 | if (filePtr == NULL)
30 | return NULL;
31 |
32 | /* Get the number of bytes */
33 | fseek(filePtr, 0, SEEK_END);
34 | size_t fileSize = (size_t) ftell(filePtr);
35 |
36 | /* reset the file position indicator to
37 | the beginning of the file */
38 | fseek(filePtr, 0, SEEK_SET);
39 |
40 | /* grab sufficient memory for the
41 | buffer to hold the text */
42 | char *buffer = calloc(fileSize + 1, sizeof(char));
43 |
44 | /* memory error */
45 | if (buffer == NULL)
46 | return NULL;
47 |
48 | /* copy all the text into the buffer */
49 | *size = fread(buffer, sizeof(char), fileSize, filePtr);
50 | fclose(filePtr);
51 | buffer[fileSize + 1] = '\0';
52 | return buffer;
53 | }
54 |
55 | void EmitError(const unsigned short errorCode) {
56 | fputs(ErrorInfo[errorCode], stderr);
57 | }
58 |
59 | #define HELP_TEXT "Sendinput utility\n" \
60 | "Usage: sendinput_io [-|]\n" \
61 | "Parses sendinput command from stdin or file and exec it."
62 |
63 | int main(int argc, char *argv[]) {
64 | size_t size = 0;
65 | char *command = NULL;
66 | if (argc > 1) {
67 | char *filePath = argv[1];
68 | if (filePath[0] == '-' && filePath[1] == '\0') {
69 | command = readStdIn(&size);
70 | } else {
71 | command = readFile(filePath, &size);
72 | }
73 | if (command) {
74 | ParseSendKeys(command, size);
75 | free(command);
76 | return 0;
77 | }
78 | }
79 | puts(HELP_TEXT);
80 | return 1;
81 | }
--------------------------------------------------------------------------------
/sendkey.h:
--------------------------------------------------------------------------------
1 | #ifndef WIN32_LEAN_AND_MEAN
2 | #define WIN32_LEAN_AND_MEAN
3 | #endif
4 | #include
5 |
6 | static void SetKeyState(const BOOL bState, const WORD keyCode) {
7 | BYTE keyState[256];
8 | INPUT input;
9 | ZeroMemory(&input, sizeof(input));
10 |
11 | GetKeyboardState((LPBYTE)&keyState);
12 | if ((bState && !(keyState[keyCode] & 1)) ||
13 | (!bState && (keyState[keyCode] & 1))) {
14 | input.type = INPUT_KEYBOARD;
15 | input.ki.wVk = keyCode;
16 | SendInput(1, &input, sizeof(input));
17 |
18 | input.ki.dwFlags = KEYEVENTF_KEYUP;
19 | SendInput(1, &input, sizeof(input));
20 | }
21 | }
22 |
23 | static void SendSingleKey(const WORD keyCode) {
24 | INPUT input;
25 | ZeroMemory(&input, sizeof(input));
26 | input.type = INPUT_KEYBOARD;
27 | input.ki.wVk = keyCode;
28 | input.ki.dwFlags = 0;
29 | SendInput(1, &input, sizeof(input));
30 |
31 | input.ki.dwFlags = KEYEVENTF_KEYUP;
32 | SendInput(1, &input, sizeof(input));
33 | }
34 |
35 | static void SendMultipleKey(const WORD keyCode[], const unsigned short count) {
36 | INPUT input;
37 | ZeroMemory(&input, sizeof(input));
38 | input.type = INPUT_KEYBOARD;
39 | input.ki.dwFlags = 0;
40 | for (unsigned short i = 0; i < count; i++) {
41 | input.ki.wVk = keyCode[i];
42 | SendInput(1, &input, sizeof(input));
43 | }
44 | input.ki.dwFlags = KEYEVENTF_KEYUP;
45 | for (unsigned short i = count; i-- > 0;) {
46 | input.ki.wVk = keyCode[i];
47 | SendInput(1, &input, sizeof(input));
48 | }
49 | }
--------------------------------------------------------------------------------
/winmain.h:
--------------------------------------------------------------------------------
1 | // Small alternative startfile for WinMain()
2 | // Build with gcc perms:
3 | // -nostartfiles -mwindows -lshlwapi
4 | #pragma once
5 | #ifndef STARTFILE_WINMAIN_H
6 | #define STARTFILE_WINMAIN_H
7 | #include
8 | #include
9 |
10 | #ifdef UNICODE
11 | int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
12 | PWSTR lpCmdLine, int nCmdShow);
13 | #else
14 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
15 | LPSTR lpCmdLine, int nCmdShow);
16 | #endif
17 | int __cdecl WinMainCRTStartup() {
18 | STARTUPINFO startupInfo;
19 | ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
20 | GetStartupInfo(&startupInfo);
21 | DWORD __nShowCmd = SW_SHOWDEFAULT;
22 | __nShowCmd = startupInfo.dwFlags & STARTF_USESHOWWINDOW
23 | ? startupInfo.wShowWindow
24 | : SW_SHOWDEFAULT;
25 | const int exitCode =
26 | #ifdef UNICODE
27 | wWinMain(GetModuleHandleW(NULL), NULL, PathGetArgsW(GetCommandLineW()), __nShowCmd);
28 | #else
29 | WinMain(GetModuleHandleA(NULL), NULL, PathGetArgsA(GetCommandLineA()), __nShowCmd);
30 | #endif
31 | ExitProcess(exitCode);
32 | return exitCode;
33 | }
34 | #endif
35 |
--------------------------------------------------------------------------------