rs-uinput-kb 0.1.0__tar.gz
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.
- rs_uinput_kb-0.1.0/Cargo.lock +533 -0
- rs_uinput_kb-0.1.0/Cargo.toml +17 -0
- rs_uinput_kb-0.1.0/PKG-INFO +91 -0
- rs_uinput_kb-0.1.0/README.md +81 -0
- rs_uinput_kb-0.1.0/pyproject.toml +18 -0
- rs_uinput_kb-0.1.0/rs_uinput_kb/__init__.py +1 -0
- rs_uinput_kb-0.1.0/rs_uinput_kb/__init__.pyi +25 -0
- rs_uinput_kb-0.1.0/src/lib.rs +328 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "anyhow"
|
|
7
|
+
version = "1.0.102"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "bitflags"
|
|
13
|
+
version = "2.11.1"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "cfg-if"
|
|
19
|
+
version = "1.0.4"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|
22
|
+
|
|
23
|
+
[[package]]
|
|
24
|
+
name = "cfg_aliases"
|
|
25
|
+
version = "0.2.1"
|
|
26
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
27
|
+
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|
28
|
+
|
|
29
|
+
[[package]]
|
|
30
|
+
name = "chacha20"
|
|
31
|
+
version = "0.10.0"
|
|
32
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
33
|
+
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
|
|
34
|
+
dependencies = [
|
|
35
|
+
"cfg-if",
|
|
36
|
+
"cpufeatures",
|
|
37
|
+
"rand_core",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[[package]]
|
|
41
|
+
name = "cpufeatures"
|
|
42
|
+
version = "0.3.0"
|
|
43
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
44
|
+
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
|
45
|
+
dependencies = [
|
|
46
|
+
"libc",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[[package]]
|
|
50
|
+
name = "equivalent"
|
|
51
|
+
version = "1.0.2"
|
|
52
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
53
|
+
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|
54
|
+
|
|
55
|
+
[[package]]
|
|
56
|
+
name = "foldhash"
|
|
57
|
+
version = "0.1.5"
|
|
58
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
59
|
+
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
|
60
|
+
|
|
61
|
+
[[package]]
|
|
62
|
+
name = "getrandom"
|
|
63
|
+
version = "0.4.2"
|
|
64
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
65
|
+
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
|
|
66
|
+
dependencies = [
|
|
67
|
+
"cfg-if",
|
|
68
|
+
"libc",
|
|
69
|
+
"r-efi",
|
|
70
|
+
"rand_core",
|
|
71
|
+
"wasip2",
|
|
72
|
+
"wasip3",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[[package]]
|
|
76
|
+
name = "hashbrown"
|
|
77
|
+
version = "0.15.5"
|
|
78
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
79
|
+
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
|
80
|
+
dependencies = [
|
|
81
|
+
"foldhash",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
[[package]]
|
|
85
|
+
name = "hashbrown"
|
|
86
|
+
version = "0.17.1"
|
|
87
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
88
|
+
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
|
89
|
+
|
|
90
|
+
[[package]]
|
|
91
|
+
name = "heck"
|
|
92
|
+
version = "0.5.0"
|
|
93
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
94
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
95
|
+
|
|
96
|
+
[[package]]
|
|
97
|
+
name = "id-arena"
|
|
98
|
+
version = "2.3.0"
|
|
99
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
100
|
+
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
|
101
|
+
|
|
102
|
+
[[package]]
|
|
103
|
+
name = "indexmap"
|
|
104
|
+
version = "2.14.0"
|
|
105
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
106
|
+
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
|
107
|
+
dependencies = [
|
|
108
|
+
"equivalent",
|
|
109
|
+
"hashbrown 0.17.1",
|
|
110
|
+
"serde",
|
|
111
|
+
"serde_core",
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
[[package]]
|
|
115
|
+
name = "input-linux"
|
|
116
|
+
version = "0.7.1"
|
|
117
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
118
|
+
checksum = "b7e8c4821c88b95582ca69234a1d233f87e44182c42e121f740efb0bec1142e0"
|
|
119
|
+
dependencies = [
|
|
120
|
+
"input-linux-sys",
|
|
121
|
+
"nix",
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
[[package]]
|
|
125
|
+
name = "input-linux-sys"
|
|
126
|
+
version = "0.9.0"
|
|
127
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
128
|
+
checksum = "7b91b2248b0eaf0a576ef5e60b7f2107a749e705a876bc0b9fe952ac8d83a724"
|
|
129
|
+
dependencies = [
|
|
130
|
+
"libc",
|
|
131
|
+
"nix",
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
[[package]]
|
|
135
|
+
name = "itoa"
|
|
136
|
+
version = "1.0.18"
|
|
137
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
138
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
139
|
+
|
|
140
|
+
[[package]]
|
|
141
|
+
name = "leb128fmt"
|
|
142
|
+
version = "0.1.0"
|
|
143
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
144
|
+
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|
145
|
+
|
|
146
|
+
[[package]]
|
|
147
|
+
name = "libc"
|
|
148
|
+
version = "0.2.186"
|
|
149
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
150
|
+
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
151
|
+
|
|
152
|
+
[[package]]
|
|
153
|
+
name = "log"
|
|
154
|
+
version = "0.4.30"
|
|
155
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
156
|
+
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
|
|
157
|
+
|
|
158
|
+
[[package]]
|
|
159
|
+
name = "memchr"
|
|
160
|
+
version = "2.8.1"
|
|
161
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
162
|
+
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
|
|
163
|
+
|
|
164
|
+
[[package]]
|
|
165
|
+
name = "nix"
|
|
166
|
+
version = "0.29.0"
|
|
167
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
168
|
+
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
|
169
|
+
dependencies = [
|
|
170
|
+
"bitflags",
|
|
171
|
+
"cfg-if",
|
|
172
|
+
"cfg_aliases",
|
|
173
|
+
"libc",
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
[[package]]
|
|
177
|
+
name = "once_cell"
|
|
178
|
+
version = "1.21.4"
|
|
179
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
180
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
181
|
+
|
|
182
|
+
[[package]]
|
|
183
|
+
name = "portable-atomic"
|
|
184
|
+
version = "1.13.1"
|
|
185
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
186
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
187
|
+
|
|
188
|
+
[[package]]
|
|
189
|
+
name = "prettyplease"
|
|
190
|
+
version = "0.2.37"
|
|
191
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
192
|
+
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
|
193
|
+
dependencies = [
|
|
194
|
+
"proc-macro2",
|
|
195
|
+
"syn",
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
[[package]]
|
|
199
|
+
name = "proc-macro2"
|
|
200
|
+
version = "1.0.106"
|
|
201
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
202
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
203
|
+
dependencies = [
|
|
204
|
+
"unicode-ident",
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
[[package]]
|
|
208
|
+
name = "pyo3"
|
|
209
|
+
version = "0.28.3"
|
|
210
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
211
|
+
checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12"
|
|
212
|
+
dependencies = [
|
|
213
|
+
"libc",
|
|
214
|
+
"once_cell",
|
|
215
|
+
"portable-atomic",
|
|
216
|
+
"pyo3-build-config",
|
|
217
|
+
"pyo3-ffi",
|
|
218
|
+
"pyo3-macros",
|
|
219
|
+
]
|
|
220
|
+
|
|
221
|
+
[[package]]
|
|
222
|
+
name = "pyo3-build-config"
|
|
223
|
+
version = "0.28.3"
|
|
224
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
225
|
+
checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e"
|
|
226
|
+
dependencies = [
|
|
227
|
+
"target-lexicon",
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
[[package]]
|
|
231
|
+
name = "pyo3-ffi"
|
|
232
|
+
version = "0.28.3"
|
|
233
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
234
|
+
checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e"
|
|
235
|
+
dependencies = [
|
|
236
|
+
"libc",
|
|
237
|
+
"pyo3-build-config",
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
[[package]]
|
|
241
|
+
name = "pyo3-macros"
|
|
242
|
+
version = "0.28.3"
|
|
243
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
244
|
+
checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813"
|
|
245
|
+
dependencies = [
|
|
246
|
+
"proc-macro2",
|
|
247
|
+
"pyo3-macros-backend",
|
|
248
|
+
"quote",
|
|
249
|
+
"syn",
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
[[package]]
|
|
253
|
+
name = "pyo3-macros-backend"
|
|
254
|
+
version = "0.28.3"
|
|
255
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
256
|
+
checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb"
|
|
257
|
+
dependencies = [
|
|
258
|
+
"heck",
|
|
259
|
+
"proc-macro2",
|
|
260
|
+
"pyo3-build-config",
|
|
261
|
+
"quote",
|
|
262
|
+
"syn",
|
|
263
|
+
]
|
|
264
|
+
|
|
265
|
+
[[package]]
|
|
266
|
+
name = "quote"
|
|
267
|
+
version = "1.0.45"
|
|
268
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
269
|
+
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
|
270
|
+
dependencies = [
|
|
271
|
+
"proc-macro2",
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
[[package]]
|
|
275
|
+
name = "r-efi"
|
|
276
|
+
version = "6.0.0"
|
|
277
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
278
|
+
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
|
279
|
+
|
|
280
|
+
[[package]]
|
|
281
|
+
name = "rand"
|
|
282
|
+
version = "0.10.1"
|
|
283
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
284
|
+
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
|
285
|
+
dependencies = [
|
|
286
|
+
"chacha20",
|
|
287
|
+
"getrandom",
|
|
288
|
+
"rand_core",
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
[[package]]
|
|
292
|
+
name = "rand_core"
|
|
293
|
+
version = "0.10.1"
|
|
294
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
295
|
+
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
|
296
|
+
|
|
297
|
+
[[package]]
|
|
298
|
+
name = "rs_uinput_kb"
|
|
299
|
+
version = "0.1.0"
|
|
300
|
+
dependencies = [
|
|
301
|
+
"input-linux",
|
|
302
|
+
"pyo3",
|
|
303
|
+
"rand",
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
[[package]]
|
|
307
|
+
name = "semver"
|
|
308
|
+
version = "1.0.28"
|
|
309
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
310
|
+
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
|
311
|
+
|
|
312
|
+
[[package]]
|
|
313
|
+
name = "serde"
|
|
314
|
+
version = "1.0.228"
|
|
315
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
316
|
+
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
|
317
|
+
dependencies = [
|
|
318
|
+
"serde_core",
|
|
319
|
+
]
|
|
320
|
+
|
|
321
|
+
[[package]]
|
|
322
|
+
name = "serde_core"
|
|
323
|
+
version = "1.0.228"
|
|
324
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
325
|
+
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
|
326
|
+
dependencies = [
|
|
327
|
+
"serde_derive",
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
[[package]]
|
|
331
|
+
name = "serde_derive"
|
|
332
|
+
version = "1.0.228"
|
|
333
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
334
|
+
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|
335
|
+
dependencies = [
|
|
336
|
+
"proc-macro2",
|
|
337
|
+
"quote",
|
|
338
|
+
"syn",
|
|
339
|
+
]
|
|
340
|
+
|
|
341
|
+
[[package]]
|
|
342
|
+
name = "serde_json"
|
|
343
|
+
version = "1.0.150"
|
|
344
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
345
|
+
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
|
346
|
+
dependencies = [
|
|
347
|
+
"itoa",
|
|
348
|
+
"memchr",
|
|
349
|
+
"serde",
|
|
350
|
+
"serde_core",
|
|
351
|
+
"zmij",
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
[[package]]
|
|
355
|
+
name = "syn"
|
|
356
|
+
version = "2.0.117"
|
|
357
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
358
|
+
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
359
|
+
dependencies = [
|
|
360
|
+
"proc-macro2",
|
|
361
|
+
"quote",
|
|
362
|
+
"unicode-ident",
|
|
363
|
+
]
|
|
364
|
+
|
|
365
|
+
[[package]]
|
|
366
|
+
name = "target-lexicon"
|
|
367
|
+
version = "0.13.5"
|
|
368
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
369
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
370
|
+
|
|
371
|
+
[[package]]
|
|
372
|
+
name = "unicode-ident"
|
|
373
|
+
version = "1.0.24"
|
|
374
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
375
|
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
376
|
+
|
|
377
|
+
[[package]]
|
|
378
|
+
name = "unicode-xid"
|
|
379
|
+
version = "0.2.6"
|
|
380
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
381
|
+
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
|
382
|
+
|
|
383
|
+
[[package]]
|
|
384
|
+
name = "wasip2"
|
|
385
|
+
version = "1.0.3+wasi-0.2.9"
|
|
386
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
387
|
+
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
|
388
|
+
dependencies = [
|
|
389
|
+
"wit-bindgen 0.57.1",
|
|
390
|
+
]
|
|
391
|
+
|
|
392
|
+
[[package]]
|
|
393
|
+
name = "wasip3"
|
|
394
|
+
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
|
395
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
396
|
+
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
|
397
|
+
dependencies = [
|
|
398
|
+
"wit-bindgen 0.51.0",
|
|
399
|
+
]
|
|
400
|
+
|
|
401
|
+
[[package]]
|
|
402
|
+
name = "wasm-encoder"
|
|
403
|
+
version = "0.244.0"
|
|
404
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
405
|
+
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
|
406
|
+
dependencies = [
|
|
407
|
+
"leb128fmt",
|
|
408
|
+
"wasmparser",
|
|
409
|
+
]
|
|
410
|
+
|
|
411
|
+
[[package]]
|
|
412
|
+
name = "wasm-metadata"
|
|
413
|
+
version = "0.244.0"
|
|
414
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
415
|
+
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
|
416
|
+
dependencies = [
|
|
417
|
+
"anyhow",
|
|
418
|
+
"indexmap",
|
|
419
|
+
"wasm-encoder",
|
|
420
|
+
"wasmparser",
|
|
421
|
+
]
|
|
422
|
+
|
|
423
|
+
[[package]]
|
|
424
|
+
name = "wasmparser"
|
|
425
|
+
version = "0.244.0"
|
|
426
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
427
|
+
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
|
428
|
+
dependencies = [
|
|
429
|
+
"bitflags",
|
|
430
|
+
"hashbrown 0.15.5",
|
|
431
|
+
"indexmap",
|
|
432
|
+
"semver",
|
|
433
|
+
]
|
|
434
|
+
|
|
435
|
+
[[package]]
|
|
436
|
+
name = "wit-bindgen"
|
|
437
|
+
version = "0.51.0"
|
|
438
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
439
|
+
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
|
440
|
+
dependencies = [
|
|
441
|
+
"wit-bindgen-rust-macro",
|
|
442
|
+
]
|
|
443
|
+
|
|
444
|
+
[[package]]
|
|
445
|
+
name = "wit-bindgen"
|
|
446
|
+
version = "0.57.1"
|
|
447
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
448
|
+
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
449
|
+
|
|
450
|
+
[[package]]
|
|
451
|
+
name = "wit-bindgen-core"
|
|
452
|
+
version = "0.51.0"
|
|
453
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
454
|
+
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
|
455
|
+
dependencies = [
|
|
456
|
+
"anyhow",
|
|
457
|
+
"heck",
|
|
458
|
+
"wit-parser",
|
|
459
|
+
]
|
|
460
|
+
|
|
461
|
+
[[package]]
|
|
462
|
+
name = "wit-bindgen-rust"
|
|
463
|
+
version = "0.51.0"
|
|
464
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
465
|
+
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
|
466
|
+
dependencies = [
|
|
467
|
+
"anyhow",
|
|
468
|
+
"heck",
|
|
469
|
+
"indexmap",
|
|
470
|
+
"prettyplease",
|
|
471
|
+
"syn",
|
|
472
|
+
"wasm-metadata",
|
|
473
|
+
"wit-bindgen-core",
|
|
474
|
+
"wit-component",
|
|
475
|
+
]
|
|
476
|
+
|
|
477
|
+
[[package]]
|
|
478
|
+
name = "wit-bindgen-rust-macro"
|
|
479
|
+
version = "0.51.0"
|
|
480
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
481
|
+
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
|
482
|
+
dependencies = [
|
|
483
|
+
"anyhow",
|
|
484
|
+
"prettyplease",
|
|
485
|
+
"proc-macro2",
|
|
486
|
+
"quote",
|
|
487
|
+
"syn",
|
|
488
|
+
"wit-bindgen-core",
|
|
489
|
+
"wit-bindgen-rust",
|
|
490
|
+
]
|
|
491
|
+
|
|
492
|
+
[[package]]
|
|
493
|
+
name = "wit-component"
|
|
494
|
+
version = "0.244.0"
|
|
495
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
496
|
+
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
|
497
|
+
dependencies = [
|
|
498
|
+
"anyhow",
|
|
499
|
+
"bitflags",
|
|
500
|
+
"indexmap",
|
|
501
|
+
"log",
|
|
502
|
+
"serde",
|
|
503
|
+
"serde_derive",
|
|
504
|
+
"serde_json",
|
|
505
|
+
"wasm-encoder",
|
|
506
|
+
"wasm-metadata",
|
|
507
|
+
"wasmparser",
|
|
508
|
+
"wit-parser",
|
|
509
|
+
]
|
|
510
|
+
|
|
511
|
+
[[package]]
|
|
512
|
+
name = "wit-parser"
|
|
513
|
+
version = "0.244.0"
|
|
514
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
515
|
+
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
|
516
|
+
dependencies = [
|
|
517
|
+
"anyhow",
|
|
518
|
+
"id-arena",
|
|
519
|
+
"indexmap",
|
|
520
|
+
"log",
|
|
521
|
+
"semver",
|
|
522
|
+
"serde",
|
|
523
|
+
"serde_derive",
|
|
524
|
+
"serde_json",
|
|
525
|
+
"unicode-xid",
|
|
526
|
+
"wasmparser",
|
|
527
|
+
]
|
|
528
|
+
|
|
529
|
+
[[package]]
|
|
530
|
+
name = "zmij"
|
|
531
|
+
version = "1.0.21"
|
|
532
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
533
|
+
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "rs_uinput_kb"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "A Python wrapper for Linux /dev/uinput keystroke simulation"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
repository = "https://github.com/Dwarakesh-V/rs_uinput_kb"
|
|
9
|
+
|
|
10
|
+
[lib]
|
|
11
|
+
name = "rs_uinput_kb"
|
|
12
|
+
crate-type = ["cdylib"]
|
|
13
|
+
|
|
14
|
+
[dependencies]
|
|
15
|
+
pyo3 = { version = "0.28.3", features = ["extension-module"] }
|
|
16
|
+
rand = "0.10.1"
|
|
17
|
+
input-linux = "0.7.1"
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rs_uinput_kb
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
7
|
+
Summary: A Python wrapper for Linux /dev/uinput keystroke simulation
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
10
|
+
|
|
11
|
+
# rs_uinput
|
|
12
|
+
|
|
13
|
+
`rs_uinput` is a Python library backed by Rust that types text through Linux's `uinput` subsystem.
|
|
14
|
+
|
|
15
|
+
Instead of injecting keystrokes into a specific application, it creates a virtual keyboard device and sends real keyboard events through the Linux input stack.
|
|
16
|
+
|
|
17
|
+
## Example
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import rs_uinput
|
|
21
|
+
|
|
22
|
+
rs_uinput.type_text(
|
|
23
|
+
text="Hello, world!",
|
|
24
|
+
min_delay=0.05,
|
|
25
|
+
max_delay=0.15
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
1. Python calls the Rust extension through PyO3.
|
|
32
|
+
2. Rust creates a virtual keyboard using `/dev/uinput`.
|
|
33
|
+
3. Each character is converted into the corresponding Linux key code.
|
|
34
|
+
4. Key press and key release events are sent through the kernel.
|
|
35
|
+
5. A random delay is applied between characters.
|
|
36
|
+
|
|
37
|
+
## How It Differs From pynput
|
|
38
|
+
|
|
39
|
+
`pynput` typically relies on higher-level desktop APIs (X11, Wayland compatibility layers, platform-specific event injection APIs, etc.).
|
|
40
|
+
|
|
41
|
+
`rs_uinput` operates at the Linux input-device layer by creating a virtual keyboard device.
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
pynput
|
|
45
|
+
↓
|
|
46
|
+
Desktop API
|
|
47
|
+
↓
|
|
48
|
+
Application
|
|
49
|
+
|
|
50
|
+
rs_uinput
|
|
51
|
+
↓
|
|
52
|
+
Virtual Keyboard Device
|
|
53
|
+
↓
|
|
54
|
+
Linux Input Subsystem
|
|
55
|
+
↓
|
|
56
|
+
Application
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Because it acts as an input device, applications receive the events through the normal Linux input pipeline rather than through a specific GUI automation API.
|
|
60
|
+
|
|
61
|
+
## How It Differs From Selenium
|
|
62
|
+
|
|
63
|
+
Selenium does not generate system-wide keyboard input.
|
|
64
|
+
|
|
65
|
+
Instead, Selenium controls a web browser through the browser's automation interface:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
Selenium
|
|
69
|
+
↓
|
|
70
|
+
Browser Driver
|
|
71
|
+
↓
|
|
72
|
+
Browser
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This means Selenium can only interact with browser content that it controls.
|
|
76
|
+
|
|
77
|
+
`rs_uinput` generates keyboard events at the operating-system level, allowing text to be entered into any focused application that accepts keyboard input.
|
|
78
|
+
|
|
79
|
+
## Use Cases
|
|
80
|
+
|
|
81
|
+
- Desktop automation
|
|
82
|
+
- Automated testing
|
|
83
|
+
- Kiosk systems
|
|
84
|
+
- Accessibility tools
|
|
85
|
+
- Input simulation on Linux
|
|
86
|
+
|
|
87
|
+
## Requirements
|
|
88
|
+
|
|
89
|
+
- Linux
|
|
90
|
+
- Kernel `uinput` support
|
|
91
|
+
- Access to `/dev/uinput`
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# rs_uinput
|
|
2
|
+
|
|
3
|
+
`rs_uinput` is a Python library backed by Rust that types text through Linux's `uinput` subsystem.
|
|
4
|
+
|
|
5
|
+
Instead of injecting keystrokes into a specific application, it creates a virtual keyboard device and sends real keyboard events through the Linux input stack.
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import rs_uinput
|
|
11
|
+
|
|
12
|
+
rs_uinput.type_text(
|
|
13
|
+
text="Hello, world!",
|
|
14
|
+
min_delay=0.05,
|
|
15
|
+
max_delay=0.15
|
|
16
|
+
)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
1. Python calls the Rust extension through PyO3.
|
|
22
|
+
2. Rust creates a virtual keyboard using `/dev/uinput`.
|
|
23
|
+
3. Each character is converted into the corresponding Linux key code.
|
|
24
|
+
4. Key press and key release events are sent through the kernel.
|
|
25
|
+
5. A random delay is applied between characters.
|
|
26
|
+
|
|
27
|
+
## How It Differs From pynput
|
|
28
|
+
|
|
29
|
+
`pynput` typically relies on higher-level desktop APIs (X11, Wayland compatibility layers, platform-specific event injection APIs, etc.).
|
|
30
|
+
|
|
31
|
+
`rs_uinput` operates at the Linux input-device layer by creating a virtual keyboard device.
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
pynput
|
|
35
|
+
↓
|
|
36
|
+
Desktop API
|
|
37
|
+
↓
|
|
38
|
+
Application
|
|
39
|
+
|
|
40
|
+
rs_uinput
|
|
41
|
+
↓
|
|
42
|
+
Virtual Keyboard Device
|
|
43
|
+
↓
|
|
44
|
+
Linux Input Subsystem
|
|
45
|
+
↓
|
|
46
|
+
Application
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Because it acts as an input device, applications receive the events through the normal Linux input pipeline rather than through a specific GUI automation API.
|
|
50
|
+
|
|
51
|
+
## How It Differs From Selenium
|
|
52
|
+
|
|
53
|
+
Selenium does not generate system-wide keyboard input.
|
|
54
|
+
|
|
55
|
+
Instead, Selenium controls a web browser through the browser's automation interface:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
Selenium
|
|
59
|
+
↓
|
|
60
|
+
Browser Driver
|
|
61
|
+
↓
|
|
62
|
+
Browser
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This means Selenium can only interact with browser content that it controls.
|
|
66
|
+
|
|
67
|
+
`rs_uinput` generates keyboard events at the operating-system level, allowing text to be entered into any focused application that accepts keyboard input.
|
|
68
|
+
|
|
69
|
+
## Use Cases
|
|
70
|
+
|
|
71
|
+
- Desktop automation
|
|
72
|
+
- Automated testing
|
|
73
|
+
- Kiosk systems
|
|
74
|
+
- Accessibility tools
|
|
75
|
+
- Input simulation on Linux
|
|
76
|
+
|
|
77
|
+
## Requirements
|
|
78
|
+
|
|
79
|
+
- Linux
|
|
80
|
+
- Kernel `uinput` support
|
|
81
|
+
- Access to `/dev/uinput`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["maturin>=1.0,<2.0"]
|
|
3
|
+
build-backend = "maturin"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rs_uinput_kb"
|
|
7
|
+
description = "A Python wrapper for Linux /dev/uinput keystroke simulation"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Rust",
|
|
12
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
13
|
+
"Operating System :: POSIX :: Linux",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[tool.maturin]
|
|
17
|
+
features = ["pyo3/extension-module"]
|
|
18
|
+
module-name = "rs_uinput_kb.rs_uinput_kb"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .rs_uinput_kb import *
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
def type_text(
|
|
2
|
+
text: str,
|
|
3
|
+
min_char_delay: float = 0.05,
|
|
4
|
+
max_char_delay: float = 0.1,
|
|
5
|
+
min_dwell_time: int = 20,
|
|
6
|
+
max_dwell_time: int = 60,
|
|
7
|
+
min_shift_delay: int = 10,
|
|
8
|
+
max_shift_delay: int = 30
|
|
9
|
+
) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Simulates hardware keystrokes using Linux's /dev/uinput.
|
|
12
|
+
|
|
13
|
+
By default, this uses jittered delays to mimic natural human typing dynamics.
|
|
14
|
+
For instantaneous machine-speed typing, set all delays to 0.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
text (str): The string of characters to type.
|
|
18
|
+
min_char_delay (float): Minimum delay between keystrokes in seconds. Default 0.05.
|
|
19
|
+
max_char_delay (float): Maximum delay between keystrokes in seconds. Default 0.1.
|
|
20
|
+
min_dwell_time (int): Minimum time a key is physically held down in milliseconds. Default 20.
|
|
21
|
+
max_dwell_time (int): Maximum time a key is physically held down in milliseconds. Default 60.
|
|
22
|
+
min_shift_delay (int): Minimum hesitation before/after pressing shift in milliseconds. Default 10.
|
|
23
|
+
max_shift_delay (int): Maximum hesitation before/after pressing shift in milliseconds. Default 30.
|
|
24
|
+
"""
|
|
25
|
+
...
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
use input_linux::{EventKind, Key, UInputHandle};
|
|
2
|
+
use pyo3::prelude::*;
|
|
3
|
+
use rand::RngExt;
|
|
4
|
+
use std::thread::sleep;
|
|
5
|
+
use std::time::Duration;
|
|
6
|
+
|
|
7
|
+
struct TypingDelays {
|
|
8
|
+
min_dwell: u64,
|
|
9
|
+
max_dwell: u64,
|
|
10
|
+
min_shift: u64,
|
|
11
|
+
max_shift: u64,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Safely generate an integer delay (prevents panic if min == max or if min > max)
|
|
15
|
+
fn get_delay(min: u64, max: u64) -> u64 {
|
|
16
|
+
let low = min.min(max);
|
|
17
|
+
let high = min.max(max);
|
|
18
|
+
if high == 0 {
|
|
19
|
+
0
|
|
20
|
+
} else if low == high {
|
|
21
|
+
low
|
|
22
|
+
} else {
|
|
23
|
+
rand::rng().random_range(low..=high)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Safely generate a float delay
|
|
28
|
+
fn get_char_delay(min: f64, max: f64) -> f64 {
|
|
29
|
+
let low = min.min(max);
|
|
30
|
+
let high = min.max(max);
|
|
31
|
+
if high <= 0.0 {
|
|
32
|
+
0.0
|
|
33
|
+
} else if low == high {
|
|
34
|
+
low
|
|
35
|
+
} else {
|
|
36
|
+
rand::rng().random_range(low..=high)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn write_event(
|
|
41
|
+
ui: &UInputHandle<std::fs::File>,
|
|
42
|
+
type_: u16,
|
|
43
|
+
code: u16,
|
|
44
|
+
value: i32,
|
|
45
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
46
|
+
let raw = input_linux::sys::input_event {
|
|
47
|
+
time: input_linux::sys::timeval {
|
|
48
|
+
tv_sec: 0,
|
|
49
|
+
tv_usec: 0,
|
|
50
|
+
},
|
|
51
|
+
type_,
|
|
52
|
+
code,
|
|
53
|
+
value,
|
|
54
|
+
};
|
|
55
|
+
ui.write(&[raw])?;
|
|
56
|
+
Ok(())
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fn write_sync_event(ui: &UInputHandle<std::fs::File>) -> Result<(), Box<dyn std::error::Error>> {
|
|
60
|
+
write_event(
|
|
61
|
+
ui,
|
|
62
|
+
input_linux::sys::EV_SYN as u16,
|
|
63
|
+
input_linux::sys::SYN_REPORT as u16,
|
|
64
|
+
0,
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fn send_key(
|
|
69
|
+
ui: &UInputHandle<std::fs::File>,
|
|
70
|
+
key: Key,
|
|
71
|
+
delays: &TypingDelays,
|
|
72
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
73
|
+
write_event(ui, input_linux::sys::EV_KEY as u16, key.code(), 1)?;
|
|
74
|
+
write_sync_event(ui)?;
|
|
75
|
+
|
|
76
|
+
let dwell_time = get_delay(delays.min_dwell, delays.max_dwell);
|
|
77
|
+
if dwell_time > 0 {
|
|
78
|
+
sleep(Duration::from_millis(dwell_time));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
write_event(ui, input_linux::sys::EV_KEY as u16, key.code(), 0)?;
|
|
82
|
+
write_sync_event(ui)?;
|
|
83
|
+
|
|
84
|
+
Ok(())
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fn send_shifted_key(
|
|
88
|
+
ui: &UInputHandle<std::fs::File>,
|
|
89
|
+
key: Key,
|
|
90
|
+
delays: &TypingDelays,
|
|
91
|
+
) -> Result<(), Box<dyn std::error::Error>> {
|
|
92
|
+
write_event(ui, input_linux::sys::EV_KEY as u16, Key::LeftShift.code(), 1)?;
|
|
93
|
+
write_sync_event(ui)?;
|
|
94
|
+
|
|
95
|
+
let shift_delay = get_delay(delays.min_shift, delays.max_shift);
|
|
96
|
+
if shift_delay > 0 {
|
|
97
|
+
sleep(Duration::from_millis(shift_delay));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
write_event(ui, input_linux::sys::EV_KEY as u16, key.code(), 1)?;
|
|
101
|
+
write_sync_event(ui)?;
|
|
102
|
+
|
|
103
|
+
let dwell_time = get_delay(delays.min_dwell, delays.max_dwell);
|
|
104
|
+
if dwell_time > 0 {
|
|
105
|
+
sleep(Duration::from_millis(dwell_time));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
write_event(ui, input_linux::sys::EV_KEY as u16, key.code(), 0)?;
|
|
109
|
+
write_sync_event(ui)?;
|
|
110
|
+
|
|
111
|
+
let unshift_delay = get_delay(delays.min_shift, delays.max_shift);
|
|
112
|
+
if unshift_delay > 0 {
|
|
113
|
+
sleep(Duration::from_millis(unshift_delay));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
write_event(ui, input_linux::sys::EV_KEY as u16, Key::LeftShift.code(), 0)?;
|
|
117
|
+
write_sync_event(ui)?;
|
|
118
|
+
|
|
119
|
+
Ok(())
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fn char_to_key(c: char) -> Option<(Key, bool)> {
|
|
123
|
+
use Key::*;
|
|
124
|
+
Some(match c {
|
|
125
|
+
'a' => (A, false),
|
|
126
|
+
'b' => (B, false),
|
|
127
|
+
'c' => (C, false),
|
|
128
|
+
'd' => (D, false),
|
|
129
|
+
'e' => (E, false),
|
|
130
|
+
'f' => (F, false),
|
|
131
|
+
'g' => (G, false),
|
|
132
|
+
'h' => (H, false),
|
|
133
|
+
'i' => (I, false),
|
|
134
|
+
'j' => (J, false),
|
|
135
|
+
'k' => (K, false),
|
|
136
|
+
'l' => (L, false),
|
|
137
|
+
'm' => (M, false),
|
|
138
|
+
'n' => (N, false),
|
|
139
|
+
'o' => (O, false),
|
|
140
|
+
'p' => (P, false),
|
|
141
|
+
'q' => (Q, false),
|
|
142
|
+
'r' => (R, false),
|
|
143
|
+
's' => (S, false),
|
|
144
|
+
't' => (T, false),
|
|
145
|
+
'u' => (U, false),
|
|
146
|
+
'v' => (V, false),
|
|
147
|
+
'w' => (W, false),
|
|
148
|
+
'x' => (X, false),
|
|
149
|
+
'y' => (Y, false),
|
|
150
|
+
'z' => (Z, false),
|
|
151
|
+
|
|
152
|
+
'A' => (A, true),
|
|
153
|
+
'B' => (B, true),
|
|
154
|
+
'C' => (C, true),
|
|
155
|
+
'D' => (D, true),
|
|
156
|
+
'E' => (E, true),
|
|
157
|
+
'F' => (F, true),
|
|
158
|
+
'G' => (G, true),
|
|
159
|
+
'H' => (H, true),
|
|
160
|
+
'I' => (I, true),
|
|
161
|
+
'J' => (J, true),
|
|
162
|
+
'K' => (K, true),
|
|
163
|
+
'L' => (L, true),
|
|
164
|
+
'M' => (M, true),
|
|
165
|
+
'N' => (N, true),
|
|
166
|
+
'O' => (O, true),
|
|
167
|
+
'P' => (P, true),
|
|
168
|
+
'Q' => (Q, true),
|
|
169
|
+
'R' => (R, true),
|
|
170
|
+
'S' => (S, true),
|
|
171
|
+
'T' => (T, true),
|
|
172
|
+
'U' => (U, true),
|
|
173
|
+
'V' => (V, true),
|
|
174
|
+
'W' => (W, true),
|
|
175
|
+
'X' => (X, true),
|
|
176
|
+
'Y' => (Y, true),
|
|
177
|
+
'Z' => (Z, true),
|
|
178
|
+
|
|
179
|
+
'0' => (Num0, false),
|
|
180
|
+
'1' => (Num1, false),
|
|
181
|
+
'2' => (Num2, false),
|
|
182
|
+
'3' => (Num3, false),
|
|
183
|
+
'4' => (Num4, false),
|
|
184
|
+
'5' => (Num5, false),
|
|
185
|
+
'6' => (Num6, false),
|
|
186
|
+
'7' => (Num7, false),
|
|
187
|
+
'8' => (Num8, false),
|
|
188
|
+
'9' => (Num9, false),
|
|
189
|
+
|
|
190
|
+
'!' => (Num1, true),
|
|
191
|
+
'@' => (Num2, true),
|
|
192
|
+
'#' => (Num3, true),
|
|
193
|
+
'$' => (Num4, true),
|
|
194
|
+
'%' => (Num5, true),
|
|
195
|
+
'^' => (Num6, true),
|
|
196
|
+
'&' => (Num7, true),
|
|
197
|
+
'*' => (Num8, true),
|
|
198
|
+
'(' => (Num9, true),
|
|
199
|
+
')' => (Num0, true),
|
|
200
|
+
|
|
201
|
+
' ' => (Space, false),
|
|
202
|
+
'-' => (Minus, false),
|
|
203
|
+
'_' => (Minus, true),
|
|
204
|
+
'=' => (Equal, false),
|
|
205
|
+
'+' => (Equal, true),
|
|
206
|
+
|
|
207
|
+
'[' => (LeftBrace, false),
|
|
208
|
+
'{' => (LeftBrace, true),
|
|
209
|
+
']' => (RightBrace, false),
|
|
210
|
+
'}' => (RightBrace, true),
|
|
211
|
+
|
|
212
|
+
';' => (Semicolon, false),
|
|
213
|
+
':' => (Semicolon, true),
|
|
214
|
+
'\'' => (Apostrophe, false),
|
|
215
|
+
'"' => (Apostrophe, true),
|
|
216
|
+
|
|
217
|
+
',' => (Comma, false),
|
|
218
|
+
'<' => (Comma, true),
|
|
219
|
+
'.' => (Dot, false),
|
|
220
|
+
'>' => (Dot, true),
|
|
221
|
+
'/' => (Slash, false),
|
|
222
|
+
'?' => (Slash, true),
|
|
223
|
+
|
|
224
|
+
'\\' => (Backslash, false),
|
|
225
|
+
'|' => (Backslash, true),
|
|
226
|
+
'`' => (Grave, false),
|
|
227
|
+
'~' => (Grave, true),
|
|
228
|
+
|
|
229
|
+
'\n' => (Enter, false),
|
|
230
|
+
|
|
231
|
+
_ => return None,
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/// Simulates hardware keystrokes using Linux's /dev/uinput.
|
|
236
|
+
///
|
|
237
|
+
/// By default, this uses jittered delays to mimic natural human typing dynamics.
|
|
238
|
+
/// For instantaneous machine-speed typing, set all delays to 0.
|
|
239
|
+
///
|
|
240
|
+
/// Args:
|
|
241
|
+
/// text (str): The string of characters to type.
|
|
242
|
+
/// min_char_delay (float): Minimum delay between keystrokes in seconds. Default 0.05.
|
|
243
|
+
/// max_char_delay (float): Maximum delay between keystrokes in seconds. Default 0.1.
|
|
244
|
+
/// min_dwell_time (int): Minimum time a key is physically held down in milliseconds. Default 20.
|
|
245
|
+
/// max_dwell_time (int): Maximum time a key is physically held down in milliseconds. Default 60.
|
|
246
|
+
/// min_shift_delay (int): Minimum hesitation before/after pressing shift in milliseconds. Default 10.
|
|
247
|
+
/// max_shift_delay (int): Maximum hesitation before/after pressing shift in milliseconds. Default 30.
|
|
248
|
+
#[pyfunction]
|
|
249
|
+
#[pyo3(signature = (
|
|
250
|
+
text,
|
|
251
|
+
min_char_delay=0.05,
|
|
252
|
+
max_char_delay=0.1,
|
|
253
|
+
min_dwell_time=20,
|
|
254
|
+
max_dwell_time=60,
|
|
255
|
+
min_shift_delay=10,
|
|
256
|
+
max_shift_delay=30
|
|
257
|
+
))]
|
|
258
|
+
fn type_text(
|
|
259
|
+
text: String,
|
|
260
|
+
min_char_delay: f64,
|
|
261
|
+
max_char_delay: f64,
|
|
262
|
+
min_dwell_time: u64,
|
|
263
|
+
max_dwell_time: u64,
|
|
264
|
+
min_shift_delay: u64,
|
|
265
|
+
max_shift_delay: u64,
|
|
266
|
+
) -> PyResult<()> {
|
|
267
|
+
let file = std::fs::OpenOptions::new()
|
|
268
|
+
.read(true)
|
|
269
|
+
.write(true)
|
|
270
|
+
.open("/dev/uinput")
|
|
271
|
+
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
|
|
272
|
+
|
|
273
|
+
let ui = UInputHandle::new(file);
|
|
274
|
+
|
|
275
|
+
ui.set_evbit(EventKind::Key)
|
|
276
|
+
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
|
|
277
|
+
|
|
278
|
+
for key in Key::iter() {
|
|
279
|
+
let _ = ui.set_keybit(key);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
let input_id_raw = input_linux::sys::input_id {
|
|
283
|
+
bustype: input_linux::sys::BUS_USB as u16,
|
|
284
|
+
vendor: 0x1234,
|
|
285
|
+
product: 0x5678,
|
|
286
|
+
version: 0,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
let input_id: input_linux::InputId = unsafe { std::mem::transmute(input_id_raw) };
|
|
290
|
+
|
|
291
|
+
ui.create(&input_id, b"rs_uinput_kb\0", 0, &[])
|
|
292
|
+
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
|
|
293
|
+
|
|
294
|
+
// The OS needs a fraction of a second to register the virtual device
|
|
295
|
+
sleep(Duration::from_millis(500));
|
|
296
|
+
|
|
297
|
+
let delays = TypingDelays {
|
|
298
|
+
min_dwell: min_dwell_time,
|
|
299
|
+
max_dwell: max_dwell_time,
|
|
300
|
+
min_shift: min_shift_delay,
|
|
301
|
+
max_shift: max_shift_delay,
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
for ch in text.chars() {
|
|
305
|
+
if let Some((key, shifted)) = char_to_key(ch) {
|
|
306
|
+
if shifted {
|
|
307
|
+
send_shifted_key(&ui, key, &delays)
|
|
308
|
+
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
|
|
309
|
+
} else {
|
|
310
|
+
send_key(&ui, key, &delays)
|
|
311
|
+
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
let char_delay = get_char_delay(min_char_delay, max_char_delay);
|
|
315
|
+
if char_delay > 0.0 {
|
|
316
|
+
sleep(Duration::from_secs_f64(char_delay));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
Ok(())
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
#[pymodule]
|
|
325
|
+
fn rs_uinput_kb(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
326
|
+
m.add_function(wrap_pyfunction!(type_text, m)?)?;
|
|
327
|
+
Ok(())
|
|
328
|
+
}
|