Simulate input/Keyboard: Difference between revisions
BrianFennell (talk | contribs) No edit summary |
m →{{header|Wren}}: Added compilation hint for C program. |
||
(50 intermediate revisions by 22 users not shown) | |||
Line 1: | Line 1: | ||
{{task|GUI}}[[Category:Testing]] |
{{task|GUI}}[[Category:Testing]] |
||
{{omit from|ACL2}} |
|||
Send simulated keystrokes to a GUI window. You should specify whether the target may be externally created (i.e., if the keystrokes are going to an application other than the application that is creating them). |
|||
{{omit from|Batch File}} |
|||
{{omit from|Brainf***}} |
|||
{{omit from|Maxima}} |
|||
{{Omit From|Modula-3}} |
|||
{{omit from|PARI/GP}} |
|||
{{omit from|PHP}} |
|||
{{omit from|PostScript}} |
|||
{{omit from|R}} |
|||
{{omit from|Retro}} |
|||
{{omit from|SmileBASIC}} |
|||
{{omit from|TI-83 BASIC}} |
|||
{{omit from|TI-89 BASIC}} |
|||
{{omit from|zkl}} |
|||
;Task: |
|||
Send simulated keystrokes to a GUI window, or terminal. |
|||
You should specify whether the target may be externally created |
|||
(i.e., if the keystrokes are going to an application |
|||
other than the application that is creating them). |
|||
<br><br> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
Target may be externally created. |
Target may be externally created. |
||
< |
<syntaxhighlight lang="autohotkey">run, cmd /k |
||
WinWait, ahk_class ConsoleWindowClass |
WinWait, ahk_class ConsoleWindowClass |
||
controlsend, ,hello console, ahk_class ConsoleWindowClass</ |
controlsend, ,hello console, ahk_class ConsoleWindowClass</syntaxhighlight> |
||
=={{header|AutoIt}}== |
=={{header|AutoIt}}== |
||
Code assumes you're working on a windows box. Run() can use any program, and WinWaitActive() requires the title of the program as it will be when it opens. |
Code assumes you're working on a windows box. Run() can use any program, and WinWaitActive() requires the title of the program as it will be when it opens. |
||
< |
<syntaxhighlight lang="autoit">Run("notepad") |
||
WinWaitActive("Untitled - Notepad") |
WinWaitActive("Untitled - Notepad") |
||
Send("The answer is 42")</ |
Send("The answer is 42")</syntaxhighlight> |
||
It takes user input in variable using "input box" |
It takes user input in variable using "input box" |
||
and displays that in "message box" |
|||
<lang AutoIt>$name="type your name here" |
|||
<syntaxhighlight lang="autoit">$name="type your name here" |
|||
$name = InputBox("Name","Your name please ?",$name) |
$name = InputBox("Name","Your name please ?",$name) |
||
MsgBox(0,"Name","Your name is: "&$name)</ |
MsgBox(0,"Name","Your name is: "&$name)</syntaxhighlight> |
||
=={{header|BASIC}}== |
|||
==={{header|Applesoft BASIC}}=== |
|||
EXEC KB executes the text file KB from disk as if you had typed everything that is in the KB text file. MON I will MONitor Input from disk. |
|||
<syntaxhighlight lang="basic"> 100 REM SIMULATE KEYBORD INPUT |
|||
110 GOSUB 170"OPEN&WRITE KB |
|||
120 PRINT "HOME:RUN140"M$"MARK |
|||
130 PRINT D$C$A$"EXEC"F$: END |
|||
140 INPUT "NAME? ";N$ |
|||
150 PRINT "HELLO, "N$"!" |
|||
160 END |
|||
170 D$ = CHR$ (4):C$ = "CLOSE" |
|||
180 M$ = CHR$ (13):O$ = "OPEN" |
|||
190 F$ = "KB":A$ = F$ + M$ + D$ |
|||
200 PRINT D$"MON I"M$D$O$; |
|||
210 PRINT A$C$A$"DELETE"A$O$; |
|||
220 PRINT A$"WRITE"F$: RETURN </syntaxhighlight> |
|||
{{Out}} |
|||
<pre>NAME? MARK |
|||
HELLO, MARK! |
|||
]</pre> |
|||
==={{header|Commodore BASIC}}=== |
|||
Most of the logic here is dedicated to detecting which Commodore model the program is being run on, in order to use the correct addresses for the keyboard input buffer. |
|||
<syntaxhighlight lang="basic">100 : REM SIMULATE KEYBORD INPUT |
|||
110 GOSUB 170:REM DETERMINE MODEL/LOCATIONS |
|||
120 PRINT CHR$(147);"NAME? MARK";CHR$(19); |
|||
130 POKE KB,13:POKE NC,1:REM PUT A RETURN IN BUFFER |
|||
140 INPUT "NAME"; N$ |
|||
150 PRINT "HELLO, "N$"!" |
|||
160 END |
|||
170 : REM DETECT MODEL |
|||
180 V=40:GOSUB 260:IF B=58 THEN NC=158:KB=624:RETURN:REM PET |
|||
190 V=43:GOSUB 260:IF B<>58 THEN 240 |
|||
200 IF A=1025 OR A=2049 OR A=4609 THEN NC=198:KB=631:RETURN:REM VIC-20 OR C64 |
|||
210 IF A<>4097 THEN 240 |
|||
220 IF PEEK(65305)=238 THEN NC=239:KB=1319:RETURN:REM C-16 OR PLUS/4 |
|||
230 IF PEEK(36879)=27 THEN NC=198:KB=631:RETURN:REM UNEXPANDED VIC-20 |
|||
240 V=45:GOSUB 260:IF B=58 THEN NC=208:KB=842:RETURN:REM C-128 |
|||
250 PRINT "UNKNOWN MODEL!":END |
|||
260 A=PEEK(V)+256*PEEK(V+1):B=PEEK(A+4):RETURN</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>NAME? MARK |
|||
HELLO, MARK! |
|||
READY.</pre> |
|||
=={{header|C}}== |
=={{header|C}}== |
||
Line 28: | Line 102: | ||
gcc -o simkeypress -L/usr/X11R6/lib -lX11 simkeypress.c |
gcc -o simkeypress -L/usr/X11R6/lib -lX11 simkeypress.c |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <X11/Xlib.h> |
#include <X11/Xlib.h> |
||
Line 141: | Line 215: | ||
XCloseDisplay(dpy); |
XCloseDisplay(dpy); |
||
return 1; |
return 1; |
||
}</ |
}</syntaxhighlight> |
||
{{libheader|Gadget}} |
|||
<p>Compile with ./ccpre.sh siminput . -c for testing with VALGRIND</p> |
|||
<p>Then, execute ./siminput</p> |
|||
<syntaxhighlight lang="c"> |
|||
#include <gadget/gadget.h> |
|||
LIB_GADGET_START |
|||
Main |
|||
Enable_raw_mode(); |
|||
int tecla=0; |
|||
int t=0; |
|||
while (tecla!=27 ){ |
|||
while ( Kbhit() ){ |
|||
tecla = Getch(); |
|||
Disable_raw_mode(); |
|||
/* para algunas teclas, imprimirá el código interno que maneja |
|||
Gadget para estos eventos, código que no es estándar */ |
|||
printf("TECLA = %d\n",tecla); |
|||
Enable_raw_mode(); |
|||
} |
|||
usleep(100); |
|||
++t; |
|||
if ( t==10000 ){ |
|||
system("xdotool key Return"); |
|||
}else if( t==11000 ){ |
|||
// Mi teclado actual es del MacBook Pro. |
|||
// En otro tipo de teclado, el código puede cambiar. |
|||
// consulte X11/keysymdef.h para más informacion. |
|||
Key_put(KEYP_ENTER); //0xff8d); |
|||
}else if( t==12000 ){ |
|||
Key_put(KEYP_LEFT); |
|||
}else if( t==13000 ){ |
|||
Key_put(KEYP_RIGHT); |
|||
}else if( t==14000 ){ |
|||
Key_put(KEYP_UP); |
|||
}else if( t==15000 ){ |
|||
Key_put(KEYP_DOWN); |
|||
}else if( t==16000 ){ |
|||
Key_put(KEYP_PAGEUP); |
|||
}else if( t==17000 ){ |
|||
Key_put(KEYP_PAGEDOWN); |
|||
}else if( t==18000 ){ |
|||
Key_put(KEYP_HOME); |
|||
}else if( t==19000 ){ |
|||
Key_put(KEYP_END); |
|||
}else if( t==20000 ){ |
|||
Key_put(' '); |
|||
}else if( t==21000 ){ |
|||
Key_put(KEYP_BACKSP); |
|||
}else if( t==22000 ){ |
|||
Key_put(KEYP_TAB); |
|||
}else if( t==23000 ){ |
|||
Key_put(KEYP_DELETE); |
|||
}else if( t==24000 ){ |
|||
Key_put_ctrl('a'); |
|||
}else if( t==24100 ){ |
|||
Key_put_ctrl('b'); |
|||
}else if( t==24200 ){ |
|||
Key_put_ctrl('w'); |
|||
}else if( t==24300 ){ |
|||
Key_put_shift('a'); |
|||
}else if( t==24400 ){ |
|||
Key_put_alt('j'); // esto no funciona en mi teclado |
|||
}else if( t>=25000 ){ |
|||
Key_put(KEYP_ESCAPE); |
|||
} |
|||
} |
|||
// Put_kbd_text() reconoce estos caracteres: otros caracteres, el |
|||
// resultado puede ser indefinido. |
|||
Put_kbd_text("Hola mundo[](){},.:;-_=?$%&/#@! \t<cruel>\n Año 2023"); |
|||
String read; |
|||
// si no se ha puesto nada en el buffer de entrada con Put_kbd_text(), |
|||
// read será NULL: |
|||
read = Read_typed_string(); |
|||
Disable_raw_mode(); |
|||
if ( read){ |
|||
printf("\nTEXTO = %s\nChar = %d\n",read, read[strlen(read)-1]); |
|||
} |
|||
free(read); |
|||
End |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
$ ./siminput |
|||
TECLA = 13 |
|||
TECLA = 13 |
|||
TECLA = 1000 |
|||
TECLA = 1001 |
|||
TECLA = 1002 |
|||
TECLA = 1003 |
|||
TECLA = 1007 |
|||
TECLA = 1008 |
|||
TECLA = 1005 |
|||
TECLA = 1006 |
|||
TECLA = 32 |
|||
TECLA = 127 |
|||
TECLA = 9 |
|||
TECLA = 1004 |
|||
TECLA = 1 |
|||
TECLA = 2 |
|||
TECLA = 23 |
|||
TECLA = 65 |
|||
TECLA = 27 |
|||
TEXTO = Hola mundo[](){},.:;-_=?$%&/#@! <cruel> |
|||
Año 2023 |
|||
Char = 51 |
|||
</pre> |
|||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
{{trans|Java}} |
{{trans|Java}} |
||
< |
<syntaxhighlight lang="clojure">(import java.awt.Robot) |
||
(import java.awt.KeyEvent) |
(import java.awt.event.KeyEvent) |
||
(defn keytype [str] |
(defn keytype [str] |
||
(let [robot (new Robot)] |
(let [robot (new Robot)] |
||
Line 159: | Line 360: | ||
(doto robot |
(doto robot |
||
(.keyPress (int upCh)) |
(.keyPress (int upCh)) |
||
(.keyRelease (int upCh))))))))</ |
(.keyRelease (int upCh))))))))</syntaxhighlight> |
||
=={{header|Go}}== |
|||
{{libheader|keybd_event}} |
|||
{{works with|Ubuntu 16.04}} |
|||
Should also work on Windows 10 though I haven't tested it. |
|||
The program runs a directory listing by sending the keys 'd', 'i', 'r', 'enter' to the terminal. |
|||
N.B. You may need to execute: 'sudo chmod +0666 /dev/uinput' first if running on Linux. |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"github.com/micmonay/keybd_event" |
|||
"log" |
|||
"runtime" |
|||
"time" |
|||
) |
|||
func main() { |
|||
kb, err := keybd_event.NewKeyBonding() |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
// For linux, need to wait 2 seconds |
|||
if runtime.GOOS == "linux" { |
|||
time.Sleep(2 * time.Second) |
|||
} |
|||
//set keys |
|||
kb.SetKeys(keybd_event.VK_D, keybd_event.VK_I, keybd_event.VK_R, keybd_event.VK_ENTER) |
|||
//launch |
|||
err = kb.Launching() |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|GUISS}}== |
=={{header|GUISS}}== |
||
< |
<syntaxhighlight lang="guiss">Start,Programs,Accessories,Notepad,Textbox,Type:Hello World[pling]</syntaxhighlight> |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
Line 171: | Line 410: | ||
Keystrokes when this function is executed will go to whatever application has focus at the time. Special cases may need to be made for certain symbols, but most of the VK values in KeyEvent map to the ASCII values of characters. |
Keystrokes when this function is executed will go to whatever application has focus at the time. Special cases may need to be made for certain symbols, but most of the VK values in KeyEvent map to the ASCII values of characters. |
||
< |
<syntaxhighlight lang="java5">import java.awt.Robot |
||
public static void type(String str){ |
public static void type(String str){ |
||
Robot robot = new Robot(); |
Robot robot = new Robot(); |
||
Line 186: | Line 425: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Kotlin}}== |
|||
<syntaxhighlight lang="scala">// version 1.1.2 |
|||
import java.awt.Robot |
|||
import java.awt.event.KeyEvent |
|||
fun sendChars(s: String, pressReturn: Boolean = true) { |
|||
val r = Robot() |
|||
for (c in s) { |
|||
val ci = c.toUpperCase().toInt() |
|||
r.keyPress(ci) |
|||
r.keyRelease(ci) |
|||
} |
|||
if (pressReturn) { |
|||
r.keyPress(KeyEvent.VK_ENTER) |
|||
r.keyRelease(KeyEvent.VK_ENTER) |
|||
} |
|||
} |
|||
fun main(args: Array<String>) { |
|||
sendChars("dir") // runs 'dir' command |
|||
}</syntaxhighlight> |
|||
=={{header|LabVIEW}}== |
=={{header|LabVIEW}}== |
||
Uses .NET for simplicity. Run it with Highlight Execution on, to give notepad time to open. {{VI solution|LabVIEW_Simulate_input_Keyboard.png}} |
Uses .NET for simplicity. Run it with Highlight Execution on, to give notepad time to open. {{VI solution|LabVIEW_Simulate_input_Keyboard.png}} |
||
=={{header|Nim}}== |
|||
This example implements limited capability of simulating input/Keyboard on Windows using standard library only. For better Windows support we can use [https://github.com/khchen/winim Winim] and [https://github.com/juancarlospaco/nim-xdo xdo] for Linux. |
|||
Current example will simulate keyboard input of typing Hello world to the current focused window. |
|||
<syntaxhighlight lang="nim">when defined(windows): |
|||
import winlean |
|||
else: |
|||
{.error: "not supported os".} |
|||
type |
|||
InputType = enum |
|||
itMouse itKeyboard itHardware |
|||
KeyEvent = enum |
|||
keExtendedKey = 0x0001 |
|||
keKeyUp = 0x0002 |
|||
keUnicode = 0x0004 |
|||
keScanCode = 0x0008 |
|||
MouseInput {.importc: "MOUSEINPUT".} = object |
|||
dx, dy: clong |
|||
mouseData, dwFlags, time: culong |
|||
dwExtraInfo: int # ULONG_PTR |
|||
KeybdInput {.importc: "KEYBDINPUT".} = object |
|||
wVk, wScan: cint |
|||
dwFlags, time: culong |
|||
dwExtraInfo: int |
|||
HardwareInput {.importc: "HARDWAREINPUT".} = object |
|||
uMsg: clong |
|||
wParamL, wParamH: cint |
|||
InputUnion {.union.} = object |
|||
hi: HardwareInput |
|||
mi: MouseInput |
|||
ki: KeybdInput |
|||
Input = object |
|||
`type`: clong |
|||
hwin: InputUnion |
|||
proc sendInput(total: cint, inp: ptr Input, size: cint) {.importc: "SendInput", header: "<windows.h>".} |
|||
proc initKey(keycode: int): Input = |
|||
result = Input(`type`: itKeyboard.clong) |
|||
var keybd = KeybdInput(wVk: keycode.cint, wScan: 0, time: 0, |
|||
dwExtraInfo: 0, dwFlags: 0) |
|||
result.hwin = InputUnion(ki: keybd) |
|||
proc pressKey(input: var Input) = |
|||
input.hwin.ki.dwFlags = keExtendedKey.culong |
|||
sendInput(cint 1, addr input, sizeof(Input).cint) |
|||
proc releaseKey(input: var Input) = |
|||
input.hwin.ki.dwFlags = keExtendedKey.culong or keKeyUp.culong |
|||
sendInput(cint 1, addr input, sizeof(Input).cint) |
|||
proc pressRelease(input: var Input) = |
|||
input.pressKey |
|||
input.releaseKey |
|||
proc pressReleaseKeycode(input: var Input, code: int) = |
|||
input.hwin.ki.wVk = code.cint |
|||
input.pressRelease |
|||
proc main = |
|||
var |
|||
shift = initKey 0xa0 # VK_LSHIFT |
|||
key = initKey 0x48 |
|||
pressKey shift |
|||
pressRelease key |
|||
releaseKey shift |
|||
key.pressReleaseKeycode 0x45 # e key |
|||
key.pressReleaseKeycode 0x4c # l key |
|||
key.pressReleaseKeycode 0x4c # l key |
|||
key.pressReleaseKeycode 0x4f # o key |
|||
key.pressReleaseKeycode 0x20 # VK_SPACE |
|||
key.pressReleaseKeycode 0x57 # w key |
|||
key.pressReleaseKeycode 0x4f # o key |
|||
key.pressReleaseKeycode 0x52 # r key |
|||
key.pressReleaseKeycode 0x4c # l key |
|||
key.pressReleaseKeycode 0x44 # d key |
|||
main() |
|||
</syntaxhighlight> |
|||
Compile and run it by (assuming we have GNU C compiler): |
|||
<pre>nim c -r ourfile.nim</pre> |
|||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
Line 200: | Line 550: | ||
ocaml -I +Xlib Xlib.cma keysym.cma send_event.ml |
ocaml -I +Xlib Xlib.cma keysym.cma send_event.ml |
||
< |
<syntaxhighlight lang="ocaml">open Xlib |
||
let () = |
let () = |
||
Line 304: | Line 654: | ||
(* close connection to server *) |
(* close connection to server *) |
||
xCloseDisplay d; |
xCloseDisplay d; |
||
;;</ |
;;</syntaxhighlight> |
||
=={{header|Oz}}== |
=={{header|Oz}}== |
||
Line 310: | Line 660: | ||
Oz' default GUI toolkit is based on Tk. So we can do the same thing as in Tcl: |
Oz' default GUI toolkit is based on Tk. So we can do the same thing as in Tcl: |
||
< |
<syntaxhighlight lang="oz">declare |
||
[QTk] = {Module.link ['x-oz://system/wp/QTk.ozf']} |
[QTk] = {Module.link ['x-oz://system/wp/QTk.ozf']} |
||
Entry |
Entry |
||
Line 323: | Line 673: | ||
{Delay 100} |
{Delay 100} |
||
{Tk.send event(generate Entry Key)} |
{Tk.send event(generate Entry Key)} |
||
end</ |
end</syntaxhighlight> |
||
This only works with internal windows. |
This only works with internal windows. |
||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
Perl on linux can do this for PseudoTerminals (ptys) and Terminals (ttys) using [http://www.kernel.org/doc/man-pages/online/pages/man4/tty_ioctl.4.html IOCTL TIOCSTI]. The same can be done with C or any other language that can use IOCTL either natively or via [http://en.wikipedia.org/wiki/Foreign_function_interface FFI] such as [http://en.wikipedia.org/wiki/Java_Native_Interface JNI] or [http://en.wikipedia.org/wiki/Java_Native_Access JNA]. |
Perl on linux can do this for PseudoTerminals (ptys) and Terminals (ttys) using [http://www.kernel.org/doc/man-pages/online/pages/man4/tty_ioctl.4.html IOCTL TIOCSTI]. The same can be done with C or any other language that can use IOCTL either natively or via [http://en.wikipedia.org/wiki/Foreign_function_interface FFI] such as [http://en.wikipedia.org/wiki/Java_Native_Interface JNI] or [http://en.wikipedia.org/wiki/Java_Native_Access JNA]. |
||
Target may be externally created, but process must be able to open tty/pty for writing. |
|||
<lang perl>$target = "/dev/pts/51"; |
|||
$TIOCSTI = 0x5412 ; open(TTY,">$target") or die "cannot open $target" ; |
|||
<syntaxhighlight lang="perl">$target = "/dev/pts/51"; |
|||
### How to get the correct value for $TIOCSTI is discussed here : http://www.perlmonks.org/?node_id=10920 |
|||
$TIOCSTI = 0x5412 ; |
|||
open(TTY,">$target") or die "cannot open $target" ; |
|||
$b="sleep 99334 &\015"; |
$b="sleep 99334 &\015"; |
||
@c=split("",$b); |
@c=split("",$b); |
||
sleep(2); |
sleep(2); |
||
foreach $a ( @c ) { ioctl(TTY,$TIOCSTI,$a); select(undef,undef,undef,0.1);} ; |
foreach $a ( @c ) { ioctl(TTY,$TIOCSTI,$a); select(undef,undef,undef,0.1);} ; |
||
print "DONE\n";</ |
print "DONE\n";</syntaxhighlight> |
||
Perl on X11 can do this using [http://search.cpan.org/%7ectrondlp/X11-GUITest-0.25/GUITest.pm X11::GUITest] |
|||
Perl on Windows can do this using [http://search.cpan.org/%7ekarasik/Win32-GuiTest-1.58/lib/Win32/GuiTest.pm Win32::GUITest] |
|||
Perl on X11 can do this using the SendKeys function from [http://search.cpan.org/%7ectrondlp/X11-GUITest/GUITest.pm X11::GUITest] |
|||
Perl on Windows can do this using the SendKeys function from [http://search.cpan.org/%7ekarasik/Win32-GuiTest/lib/Win32/GuiTest.pm Win32::GUITest] |
|||
Target may be externally created. |
|||
<syntaxhighlight lang="perl">SendKeys("Hello, how are you?\n");</syntaxhighlight> |
|||
=={{header|Phix}}== |
|||
{{libheader|Phix/pGUI}} |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- demo\rosetta\Simulate_keyboard_input.exw |
|||
--</span> |
|||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- you'd better hope this sort of thing ain't possible in a browser!</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">hw</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Look ma no hands! "</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hw</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">IupSetGlobalInt</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"KEY"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">hw</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #000000;">hw</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">hw</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"RUN"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CONTINUE</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">txt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"SIZE=170x10"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="Simulate input", CHILDOFFSET=10x40, SIZE=200x80`</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">hTimer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">250</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
Line 354: | Line 744: | ||
in the following example. Keyboard input is simulated with the function 'enter' |
in the following example. Keyboard input is simulated with the function 'enter' |
||
to fill the login form's name and password fields. |
to fill the login form's name and password fields. |
||
< |
<syntaxhighlight lang="picolisp">(load "@lib/http.l" "@lib/scrape.l") |
||
# Connect to the demo app at http://7fach.de/8080 |
# Connect to the demo app at http://7fach.de/8080 |
||
Line 368: | Line 758: | ||
(click "Spare Part") # Click on "Spare Part" article |
(click "Spare Part") # Click on "Spare Part" article |
||
(prinl (value 8)) # Print the price (12.50) |
(prinl (value 8)) # Print the price (12.50) |
||
(click "logout") # Log out</ |
(click "logout") # Log out</syntaxhighlight> |
||
{{out}} |
|||
Output: |
|||
<pre>12.50</pre> |
<pre>12.50</pre> |
||
The same example is used in the related task [[Simulate input/Mouse#PicoLisp]]. |
The same example is used in the related task [[Simulate input/Mouse#PicoLisp]]. |
||
=={{header|PowerShell}}== |
|||
The Start-Sleep CmdLet must be used because no application loads instantaneously. The -Milliseconds parameter should be |
|||
adjusted accordingly for every application. |
|||
<syntaxhighlight lang="powershell"> |
|||
Add-Type -AssemblyName Microsoft.VisualBasic |
|||
Add-Type -AssemblyName System.Windows.Forms |
|||
calc.exe |
|||
Start-Sleep -Milliseconds 300 |
|||
[Microsoft.VisualBasic.Interaction]::AppActivate(“Calc”) |
|||
[System.Windows.Forms.SendKeys]::SendWait(“2{ADD}2=”) |
|||
</syntaxhighlight> |
|||
=={{header|PureBasic}}== |
=={{header|PureBasic}}== |
||
{{libheader|AutoWin}} |
{{libheader|AutoWin}} |
||
< |
<syntaxhighlight lang="purebasic">If AW_WinActivate("Calc") |
||
AW_SendKeys("123+3=") |
AW_SendKeys("123+3=") |
||
EndIf</ |
EndIf</syntaxhighlight> |
||
=={{header|Python}}== |
|||
{{works with|Python|2.7+}} |
|||
{{works with|Python|3.5+}} |
|||
{{libheader|AutoPy}} |
|||
<syntaxhighlight lang="python">import autopy |
|||
autopy.key.type_string("Hello, world!") # Prints out "Hello, world!" as quickly as OS will allow. |
|||
autopy.key.type_string("Hello, world!", wpm=60) # Prints out "Hello, world!" at 60 WPM. |
|||
autopy.key.tap(autopy.key.Code.RETURN) |
|||
autopy.key.tap(autopy.key.Code.F1) |
|||
autopy.key.tap(autopy.key.Code.LEFT_ARROW)</syntaxhighlight> |
|||
{{works with|Python|2.5+}} |
|||
{{works with|Python|3.1+}} |
|||
{{libheader|PyAutoGUI}} |
|||
Target may be externally created. |
|||
<syntaxhighlight lang="python">>>> import pyautogui |
|||
>>> pyautogui.typewrite('Hello world!') # prints out "Hello world!" instantly |
|||
>>> pyautogui.typewrite('Hello world!', interval=0.25) # prints out "Hello world!" with a quarter second delay after each character |
|||
>>> pyautogui.press('enter') # press the Enter key |
|||
>>> pyautogui.press('f1') # press the F1 key |
|||
>>> pyautogui.press('left') # press the left arrow key |
|||
>>> pyautogui.keyDown('shift') # hold down the shift key |
|||
>>> pyautogui.press('left') # press the left arrow key |
|||
>>> pyautogui.keyUp('shift') # release the shift key |
|||
>>> pyautogui.hotkey('ctrl', 'shift', 'esc')</syntaxhighlight> |
|||
=={{header|Racket}}== |
|||
<syntaxhighlight lang="racket">#lang racket/gui |
|||
(define frame (new frame% |
|||
(label "Example") |
|||
(width 300) |
|||
(height 300))) ; Defines an instance of a frame to put the canvas in |
|||
(define simulate-key-canvas% |
|||
(class canvas% |
|||
(define/public (simulate-key key) |
|||
(send this on-char key)) ; Creates a class that inherits from the standard canvas class, that can receive simulated key presses |
|||
(define/override (on-char key) |
|||
(displayln (send key get-key-code))) ; Changes the method that receives key presses to show some output |
|||
(super-new))) |
|||
(define canvas |
|||
(new simulate-key-canvas% |
|||
(parent frame))) ; Defines an instance of the newly created class |
|||
(send frame show #t) ; Shows the frame with a white canvas inside |
|||
(send canvas simulate-key (new key-event% (key-code #\k))) ; Sends the simulated key press (with a key-event% instance) |
|||
;outputs k</syntaxhighlight> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2018.12}} |
|||
Use libxdo bindings to send text / keystrokes to any application that will accept keystrokes from X11. |
|||
<syntaxhighlight lang="raku" line>use X11::libxdo; |
|||
my $xdo = Xdo.new; |
|||
my $active = $xdo.get-active-window; |
|||
my $command = $*VM.config<os> eq 'darwin' ?? 'open' !! 'xdg-open'; |
|||
shell "$command https://www.google.com"; |
|||
sleep 1; |
|||
my $match = rx[^'Google ']; |
|||
say my $w = $xdo.search(:name($match))<ID>; |
|||
sleep .25; |
|||
if $w { |
|||
$xdo.activate-window($w); |
|||
say "Window name: ", $xdo.get-window-name( $w ); |
|||
$xdo.type($w, 'Raku language'); |
|||
sleep .25; |
|||
$xdo.send-sequence($w, 'Tab'); |
|||
sleep .5; |
|||
$xdo.send-sequence($w, 'Tab'); |
|||
sleep .5; |
|||
$xdo.send-sequence($w, 'Tab'); |
|||
sleep .5; |
|||
$xdo.send-sequence($w, 'Return'); |
|||
}</syntaxhighlight> |
|||
=={{header|REXX}}== |
|||
{{works with|PC/REXX}} |
|||
{{works with|Personal REXX}} |
|||
Note: this REXX program ''only'' works with the above two REXXes. |
|||
<syntaxhighlight lang="rexx">/*REXX pgm shows how to use the REXX/PC PRESS cmd to simulate keyboard input.*/ |
|||
call press 'This text will be put into a buffer as if it came from the keyboard' |
|||
/* [↑] text will be available for any program to use (including DOS).*/ |
|||
/*stick a fork in it, we're all done. */</syntaxhighlight><br><br> |
|||
=={{header|Rust}}== |
|||
{{works with|Rust|1.25+}} |
|||
{{libheader|AutoPilot}} |
|||
<syntaxhighlight lang="rust">extern crate autopilot; |
|||
fn main() { |
|||
autopilot::key::type_string("Hello, world!", None, None, &[]); |
|||
}</syntaxhighlight> |
|||
=={{header|Scala}}== |
|||
{{libheader|Scala}} |
|||
<syntaxhighlight lang="scala">import java.awt.Robot |
|||
import java.awt.event.KeyEvent |
|||
/** Keystrokes when this function is executed will go to whatever application has focus at the time. |
|||
* Special cases may need to be made for certain symbols, but most of |
|||
* the VK values in KeyEvent map to the ASCII values of characters. |
|||
*/ |
|||
object Keystrokes extends App { |
|||
def keystroke(str: String) { |
|||
val robot = new Robot() |
|||
for (ch <- str) { |
|||
if (Character.isUpperCase(ch)) { |
|||
robot.keyPress(KeyEvent.VK_SHIFT) |
|||
robot.keyPress(ch) |
|||
robot.keyRelease(ch) |
|||
robot.keyRelease(KeyEvent.VK_SHIFT) |
|||
} else { |
|||
val upCh = Character.toUpperCase(ch) |
|||
robot.keyPress(upCh) |
|||
robot.keyRelease(upCh) |
|||
} |
|||
} |
|||
} |
|||
keystroke(args(0)) |
|||
}</syntaxhighlight> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
{{libheader|Tk}} |
{{libheader|Tk}} |
||
This only works with windows created by Tk; |
This only works with windows created by Tk; |
||
it sends a single key "x" to the given window. |
|||
<lang tcl>set key "x" |
|||
<syntaxhighlight lang="tcl">set key "x" |
|||
event generate $target <Key-$key></lang> |
|||
event generate $target <Key-$key></syntaxhighlight> |
|||
To send multiple keys, call repeatedly in order. |
To send multiple keys, call repeatedly in order. |
||
Alphabetic keys can be used directly as events, " " has to be mapped to "<space>". |
Alphabetic keys can be used directly as events, " " has to be mapped to "<space>". |
||
< |
<syntaxhighlight lang="tcl">package require Tk |
||
pack [text .t] |
pack [text .t] |
||
focus -force .t |
focus -force .t |
||
foreach c [split "hello world" ""] { |
foreach c [split "hello world" ""] { |
||
event generate .t [expr {$c eq " "?"<space>": $c}] |
event generate .t [expr {$c eq " "?"<space>": $c}] |
||
}</ |
}</syntaxhighlight> |
||
Note also that the task on [[Keyboard macros#Tcl|keyboard macros]] |
Note also that the task on [[Keyboard macros#Tcl|keyboard macros]] |
||
illustrates a very closely related method. |
|||
On Windows simulate pressing the Escape, Backspace etc keys |
|||
<syntaxhighlight lang="tcl">package require twapi |
|||
twapi::send_keys ({Esc})</syntaxhighlight> |
|||
=={{header|VBScript}}== |
=={{header|VBScript}}== |
||
The keystrokes are sent to the active window. |
The keystrokes are sent to the active window. |
||
< |
<syntaxhighlight lang="vbscript">Dim WshShell |
||
Set WshShell = WScript.CreateObject("WScript.Shell") |
Set WshShell = WScript.CreateObject("WScript.Shell") |
||
WshShell.SendKeys "{Down}{F2}" |
WshShell.SendKeys "{Down}{F2}" |
||
WScript.Sleep 1000 ' one-second delay |
WScript.Sleep 1000 ' one-second delay |
||
WshShell.SendKeys "{Left}{Left}{BkSp}{BkSp}Some text here.~" ' ~ -> Enter</ |
WshShell.SendKeys "{Left}{Left}{BkSp}{BkSp}Some text here.~" ' ~ -> Enter</syntaxhighlight> |
||
=={{header|Wren}}== |
|||
{{omit from|Batch File}} |
|||
{{ |
{{trans|C}} |
||
{{ |
{{libheader|Xlib}} |
||
<br> |
|||
{{omit from|PARI/GP}} |
|||
As it's not currently possible for Wren-cli to access Xlib directly, we embed a Wren script in a C application to complete this task. |
|||
{{omit from|PHP}} |
|||
<syntaxhighlight lang="wren">/* Simulate_input_Keyboard.wren */ |
|||
{{omit from|PostScript}} |
|||
{{omit from|Retro}} |
|||
import "random" for Random |
|||
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} |
|||
var KeyPressMask = 1 << 0 |
|||
var ShiftMask = 1 << 0 |
|||
var ButtonPressMask = 1 << 2 |
|||
var ExposureMask = 1 << 15 |
|||
var KeyPress = 2 |
|||
var ButtonPress = 4 |
|||
var Expose = 12 |
|||
var ClientMessage = 33 |
|||
var XK_q = 0x0071 |
|||
var XK_Escape = 0xff1b |
|||
foreign class XGC { |
|||
construct default(display, screenNumber) {} |
|||
} |
|||
// XEvent is a C union, not a struct, so we amalgamate the properties |
|||
foreign class XEvent { |
|||
construct new() {} // creates the union and returns a pointer to it |
|||
foreign eventType // gets type field, common to all union members |
|||
foreign eventType=(et) // sets type field |
|||
foreign state=(st) // sets xkey.state |
|||
foreign keycode // gets xkey.keycode |
|||
foreign keycode=(kc) // sets xkey.keycode |
|||
foreign sameScreen=(ss) // sets xkey.same_screen |
|||
foreign dataL // gets xclient.data.l (data is a union) |
|||
} |
|||
foreign class XDisplay { |
|||
construct openDisplay(displayName) {} |
|||
foreign defaultScreen() |
|||
foreign rootWindow(screenNumber) |
|||
foreign blackPixel(screenNumber) |
|||
foreign whitePixel(screenNumber) |
|||
foreign selectInput(w, eventMask) |
|||
foreign mapWindow(w) |
|||
foreign closeDisplay() |
|||
foreign nextEvent(eventReturn) |
|||
foreign createSimpleWindow(parent, x, y, width, height, borderWidth, border, background) |
|||
foreign drawString(d, gc, x, y, string, length) |
|||
foreign storeName(w, windowName) |
|||
foreign flush() |
|||
foreign internAtom(atomName, onlyIfExists) |
|||
foreign setWMProtocols(w, protocols, count) |
|||
foreign sendEvent(w, propogate, eventMask, eventSend) |
|||
foreign destroyWindow(w) |
|||
} |
|||
class X { |
|||
foreign static lookupKeysym(keyEvent, index) |
|||
foreign static lookupString(eventStruct, bufferReturn, bytesBuffer, keysymReturn, statusInOut) |
|||
} |
|||
/* open connection with the server */ |
|||
var xd = XDisplay.openDisplay("") |
|||
if (xd == 0) { |
|||
System.print("Cannot open display.") |
|||
return |
|||
} |
|||
var s = xd.defaultScreen() |
|||
/* create window */ |
|||
var w = xd.createSimpleWindow(xd.rootWindow(s), 10, 10, 350, 250, 1, xd.blackPixel(s), xd.whitePixel(s)) |
|||
xd.storeName(w, "Simulate keystrokes") |
|||
/* select kind of events we are interested in */ |
|||
xd.selectInput(w, ExposureMask | KeyPressMask | ButtonPressMask) |
|||
/* map (show) the window */ |
|||
xd.mapWindow(w) |
|||
xd.flush() |
|||
/* default graphics context */ |
|||
var gc = XGC.default(xd, s) |
|||
/* connect the close button in the window handle */ |
|||
var wmDeleteWindow = xd.internAtom("WM_DELETE_WINDOW", true) |
|||
xd.setWMProtocols(w, [wmDeleteWindow], 1) |
|||
/* event loop */ |
|||
var e = XEvent.new() |
|||
var rand = Random.new() |
|||
while (true) { |
|||
xd.nextEvent(e) |
|||
var et = e.eventType |
|||
if (et == Expose) { |
|||
/* draw or redraw the window */ |
|||
var msg1 = "Click in the window to generate" |
|||
var msg2 = "a random key press event" |
|||
xd.drawString(w, gc, 10, 20, msg1, msg1.count) |
|||
xd.drawString(w, gc, 10, 35, msg2, msg2.count) |
|||
} else if (et == ButtonPress) { |
|||
System.print("\nButtonPress event received") |
|||
/* manufacture a KeyPress event and send it to the window */ |
|||
var e2 = XEvent.new() |
|||
e2.eventType = KeyPress |
|||
e2.state = ShiftMask |
|||
e2.keycode = 24 + rand.int(33) |
|||
e2.sameScreen = true |
|||
xd.sendEvent(w, true, KeyPressMask, e2) |
|||
} else if (et == ClientMessage) { |
|||
/* delete window event */ |
|||
if (e.dataL[0] == wmDeleteWindow) break |
|||
} else if (et == KeyPress) { |
|||
/* handle key press */ |
|||
System.print("\nKeyPress event received") |
|||
System.print("> Keycode: %(e.keycode)") |
|||
/* exit if q or escape are pressed */ |
|||
var keysym = X.lookupKeysym(e, 0) |
|||
if (keysym == XK_q || keysym == XK_Escape) { |
|||
break |
|||
} else { |
|||
var buffer = List.filled(2, 0) |
|||
var nchars = X.lookupString(e, buffer, 2, 0, 0) // don't need the last 2 parameters |
|||
if (nchars == 1) { |
|||
var b = buffer[0] |
|||
if (b < 0) b = 256 + b |
|||
System.print("> Latin-1: %(b)") |
|||
if (b < 32 || (b >= 127 && b < 160)) { |
|||
System.print("> Key 'control character' pressed") |
|||
} else { |
|||
System.print("> Key '%(String.fromByte(b))' pressed") |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
xd.destroyWindow(w) |
|||
/* close connection to server */ |
|||
xd.closeDisplay()</syntaxhighlight> |
|||
<br> |
|||
We now embed this Wren script in the following C program, compile and run it. |
|||
<syntaxhighlight lang="c">/* gcc Simulate_input_Keyboard.c -o Simulate_input_Keyboard -lX11 -lwren -lm */ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <X11/Xlib.h> |
|||
#include <X11/Xutil.h> |
|||
#include "wren.h" |
|||
/* C <=> Wren interface functions */ |
|||
void C_displayAllocate(WrenVM* vm) { |
|||
Display** pdisplay = (Display**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(Display*)); |
|||
const char *displayName = wrenGetSlotString(vm, 1); |
|||
if (displayName == "") { |
|||
*pdisplay = XOpenDisplay(NULL); |
|||
} else { |
|||
*pdisplay = XOpenDisplay(displayName); |
|||
} |
|||
} |
|||
void C_gcAllocate(WrenVM* vm) { |
|||
GC *pgc = (GC *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(GC)); |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 1); |
|||
int s = (int)wrenGetSlotDouble(vm, 2); |
|||
*pgc = DefaultGC(display, s); |
|||
} |
|||
void C_eventAllocate(WrenVM* vm) { |
|||
wrenSetSlotNewForeign(vm, 0, 0, sizeof(XEvent)); |
|||
} |
|||
void C_eventType(WrenVM* vm) { |
|||
XEvent e = *(XEvent *)wrenGetSlotForeign(vm, 0); |
|||
wrenSetSlotDouble(vm, 0, (double)e.type); |
|||
} |
|||
void C_setEventType(WrenVM* vm) { |
|||
XEvent *e = (XEvent *)wrenGetSlotForeign(vm, 0); |
|||
int type = (int)wrenGetSlotDouble(vm, 1); |
|||
e->type = type; |
|||
} |
|||
void C_setState(WrenVM* vm) { |
|||
XKeyEvent *ke = (XKeyEvent *)wrenGetSlotForeign(vm, 0); |
|||
unsigned int state = (unsigned int)wrenGetSlotDouble(vm, 1); |
|||
ke->state = state; |
|||
} |
|||
void C_keycode(WrenVM* vm) { |
|||
XKeyEvent ke = *(XKeyEvent *)wrenGetSlotForeign(vm, 0); |
|||
wrenSetSlotDouble(vm, 0, (double)ke.keycode); |
|||
} |
|||
void C_setKeycode(WrenVM* vm) { |
|||
XKeyEvent *ke = (XKeyEvent *)wrenGetSlotForeign(vm, 0); |
|||
unsigned int keycode = (unsigned int)wrenGetSlotDouble(vm, 1); |
|||
ke->keycode = keycode; |
|||
} |
|||
void C_setSameScreen(WrenVM* vm) { |
|||
XKeyEvent *ke = (XKeyEvent *)wrenGetSlotForeign(vm, 0); |
|||
Bool sameScreen = (Bool)wrenGetSlotBool(vm, 1); |
|||
ke->same_screen = sameScreen; |
|||
} |
|||
void C_dataL(WrenVM* vm) { |
|||
XClientMessageEvent cme = *(XClientMessageEvent *)wrenGetSlotForeign(vm, 0); |
|||
wrenEnsureSlots(vm, 2); |
|||
wrenSetSlotNewList(vm, 0); |
|||
int i; |
|||
for (i = 0; i < 5; ++i) { |
|||
wrenSetSlotDouble(vm, 1, (double)cme.data.l[i]); |
|||
wrenInsertInList(vm, 0, i, 1); |
|||
} |
|||
} |
|||
void C_defaultScreen(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
int screenNumber = DefaultScreen(display); |
|||
wrenSetSlotDouble(vm, 0, (double)screenNumber); |
|||
} |
|||
void C_rootWindow(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
int screenNumber = (int)wrenGetSlotDouble(vm, 1); |
|||
Window w = RootWindow(display, screenNumber); |
|||
wrenSetSlotDouble(vm, 0, (double)w); |
|||
} |
|||
void C_blackPixel(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
int screenNumber = (int)wrenGetSlotDouble(vm, 1); |
|||
unsigned long p = BlackPixel(display, screenNumber); |
|||
wrenSetSlotDouble(vm, 0, (double)p); |
|||
} |
|||
void C_whitePixel(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
int screenNumber = (int)wrenGetSlotDouble(vm, 1); |
|||
unsigned long p = WhitePixel(display, screenNumber); |
|||
wrenSetSlotDouble(vm, 0, (double)p); |
|||
} |
|||
void C_selectInput(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Window w = (Window)wrenGetSlotDouble(vm, 1); |
|||
long eventMask = (long)wrenGetSlotDouble(vm, 2); |
|||
XSelectInput(display, w, eventMask); |
|||
} |
|||
void C_mapWindow(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Window w = (Window)wrenGetSlotDouble(vm, 1); |
|||
XMapWindow(display, w); |
|||
} |
|||
void C_closeDisplay(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
XCloseDisplay(display); |
|||
} |
|||
void C_nextEvent(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
XEvent* pe = (XEvent*)wrenGetSlotForeign(vm, 1); |
|||
XNextEvent(display, pe); |
|||
} |
|||
void C_storeName(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Window w = (Window)wrenGetSlotDouble(vm, 1); |
|||
char *windowName = (char *)wrenGetSlotString(vm, 2); |
|||
XStoreName(display, w, windowName); |
|||
} |
|||
void C_flush(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
XFlush(display); |
|||
} |
|||
void C_internAtom(WrenVM* vm) { |
|||
Display* display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
char *atomName = (char *)wrenGetSlotString(vm, 1); |
|||
Bool onlyIfExists = (Bool)wrenGetSlotBool(vm, 2); |
|||
Atom atom = XInternAtom(display, atomName, onlyIfExists); |
|||
wrenSetSlotDouble(vm, 0, (double)atom); |
|||
} |
|||
void C_setWMProtocols(WrenVM* vm) { |
|||
Display *display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Window w = (Window)wrenGetSlotDouble(vm, 1); |
|||
int count = (int)wrenGetSlotDouble(vm, 3); |
|||
Atom protocols[count]; |
|||
int i; |
|||
for (i = 0; i < count; ++i) { |
|||
wrenGetListElement(vm, 2, i, 1); |
|||
protocols[i] = (Atom)wrenGetSlotDouble(vm, 1); |
|||
} |
|||
XSetWMProtocols(display, w, protocols, count); |
|||
} |
|||
void C_sendEvent(WrenVM* vm) { |
|||
Display *display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Window w = (Window)wrenGetSlotDouble(vm, 1); |
|||
Bool propogate = (Bool)wrenGetSlotBool(vm, 2); |
|||
long eventMask = (long)wrenGetSlotDouble(vm, 3); |
|||
XEvent* pe = (XEvent*)wrenGetSlotForeign(vm, 4); |
|||
XSendEvent(display, w, propogate, eventMask, pe); |
|||
} |
|||
void C_destroyWindow(WrenVM* vm) { |
|||
Display *display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Window w = (Window)wrenGetSlotDouble(vm, 1); |
|||
XDestroyWindow(display, w); |
|||
} |
|||
void C_createSimpleWindow(WrenVM* vm) { |
|||
Display *display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Window parent = (Window)wrenGetSlotDouble(vm, 1); |
|||
int x = (int)wrenGetSlotDouble(vm, 2); |
|||
int y = (int)wrenGetSlotDouble(vm, 3); |
|||
unsigned int width = (unsigned int)wrenGetSlotDouble(vm, 4); |
|||
unsigned int height = (unsigned int)wrenGetSlotDouble(vm, 5); |
|||
unsigned int borderWidth = (unsigned int)wrenGetSlotDouble(vm, 6); |
|||
unsigned long border = (unsigned long)wrenGetSlotDouble(vm, 7); |
|||
unsigned long background = (unsigned long)wrenGetSlotDouble(vm, 8); |
|||
Window w = XCreateSimpleWindow(display, parent, x, y, width, height, borderWidth, border, background); |
|||
wrenSetSlotDouble(vm, 0, (double)w); |
|||
} |
|||
void C_drawString(WrenVM* vm) { |
|||
Display *display = *(Display**)wrenGetSlotForeign(vm, 0); |
|||
Drawable d = (Drawable)wrenGetSlotDouble(vm, 1); |
|||
GC gc = *(GC *)wrenGetSlotForeign(vm, 2); |
|||
int x = (int)wrenGetSlotDouble(vm, 3); |
|||
int y = (int)wrenGetSlotDouble(vm, 4); |
|||
const char *string = wrenGetSlotString(vm, 5); |
|||
int length = (int)wrenGetSlotDouble(vm, 6); |
|||
XDrawString(display, d, gc, x, y, string, length); |
|||
} |
|||
void C_lookupKeysym(WrenVM* vm) { |
|||
XKeyEvent *pke = (XKeyEvent*)wrenGetSlotForeign(vm, 1); |
|||
int index = (int)wrenGetSlotDouble(vm, 2); |
|||
KeySym k = XLookupKeysym(pke, index); |
|||
wrenSetSlotDouble(vm, 0, (double)k); |
|||
} |
|||
void C_lookupString(WrenVM* vm) { |
|||
XKeyEvent *pke = (XKeyEvent*)wrenGetSlotForeign(vm, 1); |
|||
int bytesBuffer = (int)wrenGetSlotDouble(vm, 3); |
|||
char bufferReturn[bytesBuffer]; |
|||
int i; |
|||
for (i = 0; i < bytesBuffer; ++i) { |
|||
wrenGetListElement(vm, 2, i, 3); |
|||
bufferReturn[i] = (char)wrenGetSlotDouble(vm, 3); |
|||
} |
|||
int count = XLookupString(pke, bufferReturn, bytesBuffer, NULL, NULL); |
|||
for (i = 0; i < 2; ++i) { |
|||
wrenSetSlotDouble(vm, 3, (double)bufferReturn[i]); |
|||
wrenSetListElement(vm, 2, i, 3); |
|||
} |
|||
wrenSetSlotDouble(vm, 0, (double)count); |
|||
} |
|||
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) { |
|||
WrenForeignClassMethods methods; |
|||
methods.finalize = NULL; |
|||
if (strcmp(className, "XDisplay") == 0) { |
|||
methods.allocate = C_displayAllocate; |
|||
} else if (strcmp(className, "XGC") == 0) { |
|||
methods.allocate = C_gcAllocate; |
|||
} else if (strcmp(className, "XEvent") == 0) { |
|||
methods.allocate = C_eventAllocate; |
|||
} else { |
|||
methods.allocate = NULL; |
|||
} |
|||
return methods; |
|||
} |
|||
WrenForeignMethodFn bindForeignMethod( |
|||
WrenVM* vm, |
|||
const char* module, |
|||
const char* className, |
|||
bool isStatic, |
|||
const char* signature) { |
|||
if (strcmp(module, "main") == 0) { |
|||
if (strcmp(className, "XEvent") == 0) { |
|||
if (!isStatic && strcmp(signature, "eventType") == 0) return C_eventType; |
|||
if (!isStatic && strcmp(signature, "eventType=(_)") == 0) return C_setEventType; |
|||
if (!isStatic && strcmp(signature, "state=(_)") == 0) return C_setState; |
|||
if (!isStatic && strcmp(signature, "keycode") == 0) return C_keycode; |
|||
if (!isStatic && strcmp(signature, "keycode=(_)") == 0) return C_setKeycode; |
|||
if (!isStatic && strcmp(signature, "sameScreen=(_)") == 0) return C_setSameScreen; |
|||
if (!isStatic && strcmp(signature, "dataL") == 0) return C_dataL; |
|||
} else if (strcmp(className, "XDisplay") == 0) { |
|||
if (!isStatic && strcmp(signature, "defaultScreen()") == 0) return C_defaultScreen; |
|||
if (!isStatic && strcmp(signature, "rootWindow(_)") == 0) return C_rootWindow; |
|||
if (!isStatic && strcmp(signature, "blackPixel(_)") == 0) return C_blackPixel; |
|||
if (!isStatic && strcmp(signature, "whitePixel(_)") == 0) return C_whitePixel; |
|||
if (!isStatic && strcmp(signature, "selectInput(_,_)") == 0) return C_selectInput; |
|||
if (!isStatic && strcmp(signature, "mapWindow(_)") == 0) return C_mapWindow; |
|||
if (!isStatic && strcmp(signature, "closeDisplay()") == 0) return C_closeDisplay; |
|||
if (!isStatic && strcmp(signature, "nextEvent(_)") == 0) return C_nextEvent; |
|||
if (!isStatic && strcmp(signature, "storeName(_,_)") == 0) return C_storeName; |
|||
if (!isStatic && strcmp(signature, "flush()") == 0) return C_flush; |
|||
if (!isStatic && strcmp(signature, "internAtom(_,_)") == 0) return C_internAtom; |
|||
if (!isStatic && strcmp(signature, "setWMProtocols(_,_,_)") == 0) return C_setWMProtocols; |
|||
if (!isStatic && strcmp(signature, "sendEvent(_,_,_,_)") == 0) return C_sendEvent; |
|||
if (!isStatic && strcmp(signature, "destroyWindow(_)") == 0) return C_destroyWindow; |
|||
if (!isStatic && strcmp(signature, "createSimpleWindow(_,_,_,_,_,_,_,_)") == 0) return C_createSimpleWindow; |
|||
if (!isStatic && strcmp(signature, "drawString(_,_,_,_,_,_)") == 0) return C_drawString; |
|||
} else if (strcmp(className, "X") == 0) { |
|||
if (isStatic && strcmp(signature, "lookupKeysym(_,_)") == 0) return C_lookupKeysym; |
|||
if (isStatic && strcmp(signature, "lookupString(_,_,_,_,_)") == 0) return C_lookupString; |
|||
} |
|||
} |
|||
return NULL; |
|||
} |
|||
static void writeFn(WrenVM* vm, const char* text) { |
|||
printf("%s", text); |
|||
} |
|||
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) { |
|||
switch (errorType) { |
|||
case WREN_ERROR_COMPILE: |
|||
printf("[%s line %d] [Error] %s\n", module, line, msg); |
|||
break; |
|||
case WREN_ERROR_STACK_TRACE: |
|||
printf("[%s line %d] in %s\n", module, line, msg); |
|||
break; |
|||
case WREN_ERROR_RUNTIME: |
|||
printf("[Runtime Error] %s\n", msg); |
|||
break; |
|||
} |
|||
} |
|||
char *readFile(const char *fileName) { |
|||
FILE *f = fopen(fileName, "r"); |
|||
fseek(f, 0, SEEK_END); |
|||
long fsize = ftell(f); |
|||
rewind(f); |
|||
char *script = malloc(fsize + 1); |
|||
fread(script, 1, fsize, f); |
|||
fclose(f); |
|||
script[fsize] = 0; |
|||
return script; |
|||
} |
|||
int main(int argc, char **argv) { |
|||
WrenConfiguration config; |
|||
wrenInitConfiguration(&config); |
|||
config.writeFn = &writeFn; |
|||
config.errorFn = &errorFn; |
|||
config.bindForeignClassFn = &bindForeignClass; |
|||
config.bindForeignMethodFn = &bindForeignMethod; |
|||
WrenVM* vm = wrenNewVM(&config); |
|||
const char* module = "main"; |
|||
const char* fileName = "Simulate_input_Keyboard.wren"; |
|||
char *script = readFile(fileName); |
|||
WrenInterpretResult result = wrenInterpret(vm, module, script); |
|||
switch (result) { |
|||
case WREN_RESULT_COMPILE_ERROR: |
|||
printf("Compile Error!\n"); |
|||
break; |
|||
case WREN_RESULT_RUNTIME_ERROR: |
|||
printf("Runtime Error!\n"); |
|||
break; |
|||
case WREN_RESULT_SUCCESS: |
|||
break; |
|||
} |
|||
wrenFreeVM(vm); |
|||
free(script); |
|||
return 0; |
|||
}</syntaxhighlight> |
Latest revision as of 11:12, 6 February 2024
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Send simulated keystrokes to a GUI window, or terminal.
You should specify whether the target may be externally created
(i.e., if the keystrokes are going to an application
other than the application that is creating them).
AutoHotkey
Target may be externally created.
run, cmd /k
WinWait, ahk_class ConsoleWindowClass
controlsend, ,hello console, ahk_class ConsoleWindowClass
AutoIt
Code assumes you're working on a windows box. Run() can use any program, and WinWaitActive() requires the title of the program as it will be when it opens.
Run("notepad")
WinWaitActive("Untitled - Notepad")
Send("The answer is 42")
It takes user input in variable using "input box" and displays that in "message box"
$name="type your name here"
$name = InputBox("Name","Your name please ?",$name)
MsgBox(0,"Name","Your name is: "&$name)
BASIC
Applesoft BASIC
EXEC KB executes the text file KB from disk as if you had typed everything that is in the KB text file. MON I will MONitor Input from disk.
100 REM SIMULATE KEYBORD INPUT
110 GOSUB 170"OPEN&WRITE KB
120 PRINT "HOME:RUN140"M$"MARK
130 PRINT D$C$A$"EXEC"F$: END
140 INPUT "NAME? ";N$
150 PRINT "HELLO, "N$"!"
160 END
170 D$ = CHR$ (4):C$ = "CLOSE"
180 M$ = CHR$ (13):O$ = "OPEN"
190 F$ = "KB":A$ = F$ + M$ + D$
200 PRINT D$"MON I"M$D$O$;
210 PRINT A$C$A$"DELETE"A$O$;
220 PRINT A$"WRITE"F$: RETURN
- Output:
NAME? MARK HELLO, MARK! ]
Commodore BASIC
Most of the logic here is dedicated to detecting which Commodore model the program is being run on, in order to use the correct addresses for the keyboard input buffer.
100 : REM SIMULATE KEYBORD INPUT
110 GOSUB 170:REM DETERMINE MODEL/LOCATIONS
120 PRINT CHR$(147);"NAME? MARK";CHR$(19);
130 POKE KB,13:POKE NC,1:REM PUT A RETURN IN BUFFER
140 INPUT "NAME"; N$
150 PRINT "HELLO, "N$"!"
160 END
170 : REM DETECT MODEL
180 V=40:GOSUB 260:IF B=58 THEN NC=158:KB=624:RETURN:REM PET
190 V=43:GOSUB 260:IF B<>58 THEN 240
200 IF A=1025 OR A=2049 OR A=4609 THEN NC=198:KB=631:RETURN:REM VIC-20 OR C64
210 IF A<>4097 THEN 240
220 IF PEEK(65305)=238 THEN NC=239:KB=1319:RETURN:REM C-16 OR PLUS/4
230 IF PEEK(36879)=27 THEN NC=198:KB=631:RETURN:REM UNEXPANDED VIC-20
240 V=45:GOSUB 260:IF B=58 THEN NC=208:KB=842:RETURN:REM C-128
250 PRINT "UNKNOWN MODEL!":END
260 A=PEEK(V)+256*PEEK(V+1):B=PEEK(A+4):RETURN
- Output:
NAME? MARK HELLO, MARK! READY.
C
Compile with:
gcc -o simkeypress -L/usr/X11R6/lib -lX11 simkeypress.c
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int main(int argc, char *argv[])
{
Display *dpy;
Window win;
GC gc;
int scr;
Atom WM_DELETE_WINDOW;
XEvent ev;
XEvent ev2;
KeySym keysym;
int loop;
/* open connection with the server */
dpy = XOpenDisplay(NULL);
if (dpy == NULL) {
fputs("Cannot open display", stderr);
exit(1);
}
scr = XDefaultScreen(dpy);
/* create window */
win = XCreateSimpleWindow(dpy,
XRootWindow(dpy, scr),
/* x, y, width, height, border_width */
10, 10, 300, 200, 1,
/* border, background */
XBlackPixel(dpy, scr), XWhitePixel(dpy, scr));
/* set window name */
XStoreName(dpy, win, argv[0]);
/* select kind of events we are interested in */
XSelectInput(dpy, win, ExposureMask | KeyPressMask | ButtonPressMask);
/* map (show) the window */
XMapWindow(dpy, win);
XFlush(dpy);
/* default graphics context */
gc = XDefaultGC(dpy, scr);
/* connect the close button in the window handle */
WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
XSetWMProtocols(dpy, win, &WM_DELETE_WINDOW, 1);
/* event loop */
loop = 1;
while (loop) {
XNextEvent(dpy, &ev);
switch (ev.type)
{
case Expose:
/* draw or redraw the window */
{
char msg1[] = "Clic in the window to generate";
char msg2[] = "a key press event";
XDrawString(dpy, win, gc, 10, 20, msg1, sizeof(msg1)-1);
XDrawString(dpy, win, gc, 10, 35, msg2, sizeof(msg2)-1);
}
break;
case ButtonPress:
puts("ButtonPress event received");
/*
printf("> button (x,y) : %d %d\n",
ev.xbutton.x,
ev.xbutton.y);
*/
ev2.type = KeyPress;
ev2.xkey.state = ShiftMask;
ev2.xkey.keycode = 24 + (rand() % 33);
ev2.xkey.same_screen = True;
XSendEvent(dpy, win, True/*propagate*/, KeyPressMask, &ev2);
break;
case ClientMessage:
/* delete window event */
if (ev.xclient.data.l[0] == WM_DELETE_WINDOW)
loop = 0;
break;
case KeyPress:
/* handle key press */
puts("KeyPress event received");
printf("> keycode: %d\n", ev.xkey.keycode);
/* exit if q or escape are pressed */
keysym = XLookupKeysym(&(ev.xkey), 0);
if (keysym == XK_q ||
keysym == XK_Escape) {
loop = 0;
} else {
char buffer[] = " ";
int nchars = XLookupString(
&(ev.xkey),
buffer,
2, /* buffer size */
&keysym,
NULL );
if (nchars == 1)
printf("> Key '%c' pressed\n", buffer[0]);
}
break;
}
}
XDestroyWindow(dpy, win);
/* close connection to server */
XCloseDisplay(dpy);
return 1;
}
Compile with ./ccpre.sh siminput . -c for testing with VALGRIND
Then, execute ./siminput
#include <gadget/gadget.h>
LIB_GADGET_START
Main
Enable_raw_mode();
int tecla=0;
int t=0;
while (tecla!=27 ){
while ( Kbhit() ){
tecla = Getch();
Disable_raw_mode();
/* para algunas teclas, imprimirá el código interno que maneja
Gadget para estos eventos, código que no es estándar */
printf("TECLA = %d\n",tecla);
Enable_raw_mode();
}
usleep(100);
++t;
if ( t==10000 ){
system("xdotool key Return");
}else if( t==11000 ){
// Mi teclado actual es del MacBook Pro.
// En otro tipo de teclado, el código puede cambiar.
// consulte X11/keysymdef.h para más informacion.
Key_put(KEYP_ENTER); //0xff8d);
}else if( t==12000 ){
Key_put(KEYP_LEFT);
}else if( t==13000 ){
Key_put(KEYP_RIGHT);
}else if( t==14000 ){
Key_put(KEYP_UP);
}else if( t==15000 ){
Key_put(KEYP_DOWN);
}else if( t==16000 ){
Key_put(KEYP_PAGEUP);
}else if( t==17000 ){
Key_put(KEYP_PAGEDOWN);
}else if( t==18000 ){
Key_put(KEYP_HOME);
}else if( t==19000 ){
Key_put(KEYP_END);
}else if( t==20000 ){
Key_put(' ');
}else if( t==21000 ){
Key_put(KEYP_BACKSP);
}else if( t==22000 ){
Key_put(KEYP_TAB);
}else if( t==23000 ){
Key_put(KEYP_DELETE);
}else if( t==24000 ){
Key_put_ctrl('a');
}else if( t==24100 ){
Key_put_ctrl('b');
}else if( t==24200 ){
Key_put_ctrl('w');
}else if( t==24300 ){
Key_put_shift('a');
}else if( t==24400 ){
Key_put_alt('j'); // esto no funciona en mi teclado
}else if( t>=25000 ){
Key_put(KEYP_ESCAPE);
}
}
// Put_kbd_text() reconoce estos caracteres: otros caracteres, el
// resultado puede ser indefinido.
Put_kbd_text("Hola mundo[](){},.:;-_=?$%&/#@! \t<cruel>\n Año 2023");
String read;
// si no se ha puesto nada en el buffer de entrada con Put_kbd_text(),
// read será NULL:
read = Read_typed_string();
Disable_raw_mode();
if ( read){
printf("\nTEXTO = %s\nChar = %d\n",read, read[strlen(read)-1]);
}
free(read);
End
- Output:
$ ./siminput TECLA = 13 TECLA = 13 TECLA = 1000 TECLA = 1001 TECLA = 1002 TECLA = 1003 TECLA = 1007 TECLA = 1008 TECLA = 1005 TECLA = 1006 TECLA = 32 TECLA = 127 TECLA = 9 TECLA = 1004 TECLA = 1 TECLA = 2 TECLA = 23 TECLA = 65 TECLA = 27 TEXTO = Hola mundo[](){},.:;-_=?$%&/#@! <cruel> Año 2023 Char = 51
Clojure
(import java.awt.Robot)
(import java.awt.event.KeyEvent)
(defn keytype [str]
(let [robot (new Robot)]
(doseq [ch str]
(if (Character/isUpperCase ch)
(doto robot
(.keyPress (. KeyEvent VK_SHIFT))
(.keyPress (int ch))
(.keyRelease (int ch))
(.keyRelease (. KeyEvent VK_SHIFT)))
(let [upCh (Character/toUpperCase ch)]
(doto robot
(.keyPress (int upCh))
(.keyRelease (int upCh))))))))
Go
Should also work on Windows 10 though I haven't tested it.
The program runs a directory listing by sending the keys 'd', 'i', 'r', 'enter' to the terminal.
N.B. You may need to execute: 'sudo chmod +0666 /dev/uinput' first if running on Linux.
package main
import (
"github.com/micmonay/keybd_event"
"log"
"runtime"
"time"
)
func main() {
kb, err := keybd_event.NewKeyBonding()
if err != nil {
log.Fatal(err)
}
// For linux, need to wait 2 seconds
if runtime.GOOS == "linux" {
time.Sleep(2 * time.Second)
}
//set keys
kb.SetKeys(keybd_event.VK_D, keybd_event.VK_I, keybd_event.VK_R, keybd_event.VK_ENTER)
//launch
err = kb.Launching()
if err != nil {
log.Fatal(err)
}
}
GUISS
Start,Programs,Accessories,Notepad,Textbox,Type:Hello World[pling]
Java
Keystrokes when this function is executed will go to whatever application has focus at the time. Special cases may need to be made for certain symbols, but most of the VK values in KeyEvent map to the ASCII values of characters.
import java.awt.Robot
public static void type(String str){
Robot robot = new Robot();
for(char ch:str.toCharArray()){
if(Character.isUpperCase(ch)){
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress((int)ch);
robot.keyRelease((int)ch);
robot.keyRelease(KeyEvent.VK_SHIFT);
}else{
char upCh = Character.toUpperCase(ch);
robot.keyPress((int)upCh);
robot.keyRelease((int)upCh);
}
}
}
Kotlin
// version 1.1.2
import java.awt.Robot
import java.awt.event.KeyEvent
fun sendChars(s: String, pressReturn: Boolean = true) {
val r = Robot()
for (c in s) {
val ci = c.toUpperCase().toInt()
r.keyPress(ci)
r.keyRelease(ci)
}
if (pressReturn) {
r.keyPress(KeyEvent.VK_ENTER)
r.keyRelease(KeyEvent.VK_ENTER)
}
}
fun main(args: Array<String>) {
sendChars("dir") // runs 'dir' command
}
LabVIEW
Uses .NET for simplicity. Run it with Highlight Execution on, to give notepad time to open. This image is a VI Snippet, an executable image of LabVIEW code. The LabVIEW version is shown on the top-right hand corner. You can download it, then drag-and-drop it onto the LabVIEW block diagram from a file browser, and it will appear as runnable, editable code.
Nim
This example implements limited capability of simulating input/Keyboard on Windows using standard library only. For better Windows support we can use Winim and xdo for Linux. Current example will simulate keyboard input of typing Hello world to the current focused window.
when defined(windows):
import winlean
else:
{.error: "not supported os".}
type
InputType = enum
itMouse itKeyboard itHardware
KeyEvent = enum
keExtendedKey = 0x0001
keKeyUp = 0x0002
keUnicode = 0x0004
keScanCode = 0x0008
MouseInput {.importc: "MOUSEINPUT".} = object
dx, dy: clong
mouseData, dwFlags, time: culong
dwExtraInfo: int # ULONG_PTR
KeybdInput {.importc: "KEYBDINPUT".} = object
wVk, wScan: cint
dwFlags, time: culong
dwExtraInfo: int
HardwareInput {.importc: "HARDWAREINPUT".} = object
uMsg: clong
wParamL, wParamH: cint
InputUnion {.union.} = object
hi: HardwareInput
mi: MouseInput
ki: KeybdInput
Input = object
`type`: clong
hwin: InputUnion
proc sendInput(total: cint, inp: ptr Input, size: cint) {.importc: "SendInput", header: "<windows.h>".}
proc initKey(keycode: int): Input =
result = Input(`type`: itKeyboard.clong)
var keybd = KeybdInput(wVk: keycode.cint, wScan: 0, time: 0,
dwExtraInfo: 0, dwFlags: 0)
result.hwin = InputUnion(ki: keybd)
proc pressKey(input: var Input) =
input.hwin.ki.dwFlags = keExtendedKey.culong
sendInput(cint 1, addr input, sizeof(Input).cint)
proc releaseKey(input: var Input) =
input.hwin.ki.dwFlags = keExtendedKey.culong or keKeyUp.culong
sendInput(cint 1, addr input, sizeof(Input).cint)
proc pressRelease(input: var Input) =
input.pressKey
input.releaseKey
proc pressReleaseKeycode(input: var Input, code: int) =
input.hwin.ki.wVk = code.cint
input.pressRelease
proc main =
var
shift = initKey 0xa0 # VK_LSHIFT
key = initKey 0x48
pressKey shift
pressRelease key
releaseKey shift
key.pressReleaseKeycode 0x45 # e key
key.pressReleaseKeycode 0x4c # l key
key.pressReleaseKeycode 0x4c # l key
key.pressReleaseKeycode 0x4f # o key
key.pressReleaseKeycode 0x20 # VK_SPACE
key.pressReleaseKeycode 0x57 # w key
key.pressReleaseKeycode 0x4f # o key
key.pressReleaseKeycode 0x52 # r key
key.pressReleaseKeycode 0x4c # l key
key.pressReleaseKeycode 0x44 # d key
main()
Compile and run it by (assuming we have GNU C compiler):
nim c -r ourfile.nim
OCaml
This example uses the Xlib to create a window, then when the user clics in this window an XKeyPressedEvent
is sent with the function xSendEvent
.
run with:
ocaml -I +Xlib Xlib.cma keysym.cma send_event.ml
open Xlib
let () =
(* open connection with the server *)
let d = xOpenDisplay "" in
let s = xDefaultScreen d in
Random.self_init();
(* create window *)
let w = xCreateSimpleWindow d (xRootWindow d s) 10 10 300 200 1
(xBlackPixel d s) (xWhitePixel d s) in
(* set window name *)
xStoreName d w Sys.argv.(0);
(* select kind of events we are interested in *)
xSelectInput d w [ExposureMask; KeyPressMask; ButtonPressMask];
(* map (show) the window *)
xMapWindow d w;
xFlush d;
let dbl = w in
let gc = xDefaultGC d s in
(* connect the close button in the window handle *)
let wm_delete_window = xInternAtom d "WM_DELETE_WINDOW" true in
xSetWMProtocols d w wm_delete_window 1;
(* event loop *)
let e = new_xEvent() in
try while true do
xNextEvent d e;
(* draw or redraw the window *)
match xEventKind e with
| XExposeEvent _ ->
xDrawString d dbl gc 10 20 "Clic in the window to generate";
xDrawString d dbl gc 10 35 "a key press event";
| XButtonPressedEvent event ->
let dat = xButtonEvent_datas event in
(*
Printf.printf "button x,y : %d %d\n%!"
dat.button_x
dat.button_y;
*)
let xKeyEvent_contents = {
key_serial = dat.button_serial;
key_send_event = dat.button_send_event;
key_display = dat.button_display;
key_window = dat.button_window;
key_root = dat.button_root;
key_subwindow = dat.button_subwindow;
key_time = dat.button_time;
key_x = dat.button_x;
key_y = dat.button_y;
key_x_root = dat.button_x_root;
key_y_root = dat.button_y_root;
key_state = [ShiftMask];
key_keycode = (24 + Random.int 33);
key_same_screen = true;
} in
let propagate = true in
let event_mask = KeyPressMask in
xSendEvent d w propagate event_mask (XKeyPressedEvCnt xKeyEvent_contents);
(* delete window event *)
| XClientMessageEvent xclient ->
let atom = xEvent_xclient_data xclient in
if atom = wm_delete_window then
raise Exit
(* handle key press *)
| XKeyPressedEvent event ->
print_endline "Key Pressed Event";
begin
let d = xKeyEvent_datas event in
Printf.printf "keycode: %d\n%!" d.key_keycode;
end;
(* exit if q or escape are pressed *)
let keysym = xLookupKeysym event 0 in
if keysym = Keysym.xK_q ||
keysym = Keysym.xK_Escape then
raise Exit
else
let printable, c =
let buf = " " in
let n, _ = xLookupString event buf in
if (n = 1)
then (true, buf.[0])
else (false, '\000')
in
if printable then
Printf.printf "Key '%c' pressed\n%!" c;
| _ -> ()
done with
| Exit ->
xDestroyWindow d w;
(* close connection to server *)
xCloseDisplay d;
;;
Oz
Oz' default GUI toolkit is based on Tk. So we can do the same thing as in Tcl:
declare
[QTk] = {Module.link ['x-oz://system/wp/QTk.ozf']}
Entry
Window = {QTk.build td(entry(handle:Entry))}
in
{Window show}
{Entry getFocus(force:true)}
for C in "Hello, world!" do
Key = if C == 32 then "<space>" else [C] end
in
{Delay 100}
{Tk.send event(generate Entry Key)}
end
This only works with internal windows.
Perl
Perl on linux can do this for PseudoTerminals (ptys) and Terminals (ttys) using IOCTL TIOCSTI. The same can be done with C or any other language that can use IOCTL either natively or via FFI such as JNI or JNA.
Target may be externally created, but process must be able to open tty/pty for writing.
$target = "/dev/pts/51";
### How to get the correct value for $TIOCSTI is discussed here : http://www.perlmonks.org/?node_id=10920
$TIOCSTI = 0x5412 ;
open(TTY,">$target") or die "cannot open $target" ;
$b="sleep 99334 &\015";
@c=split("",$b);
sleep(2);
foreach $a ( @c ) { ioctl(TTY,$TIOCSTI,$a); select(undef,undef,undef,0.1);} ;
print "DONE\n";
Perl on X11 can do this using the SendKeys function from X11::GUITest
Perl on Windows can do this using the SendKeys function from Win32::GUITest
Target may be externally created.
SendKeys("Hello, how are you?\n");
Phix
-- -- demo\rosetta\Simulate_keyboard_input.exw -- without js -- you'd better hope this sort of thing ain't possible in a browser! include pGUI.e string hw = "Look ma no hands! " function timer_cb(Ihandle ih) if length(hw) then IupSetGlobalInt("KEY",hw[1]) hw = hw[2..$] else IupSetInt(ih,"RUN",false) end if return IUP_CONTINUE end function IupOpen() Ihandle txt = IupText("SIZE=170x10") Ihandle dlg = IupDialog(txt,`TITLE="Simulate input", CHILDOFFSET=10x40, SIZE=200x80`) IupShow(dlg) Ihandle hTimer = IupTimer(Icallback("timer_cb"), 250) if platform()!=JS then IupMainLoop() IupClose() end if
PicoLisp
PicoLisp comes with a dedicated browser GUI. A library based on web scraping (in "lib/scrape.l") can be used to drive that GUI under program control. It allows to read GUI pages, click on HTML links, enter text into forms, and press submit buttons. In that way one application can control another application.
The documented demo application, which is also available online at app.7fach.de, is used in the following example. Keyboard input is simulated with the function 'enter' to fill the login form's name and password fields.
(load "@lib/http.l" "@lib/scrape.l")
# Connect to the demo app at http://7fach.de/8080
(scrape "7fach.de" 80 "8080")
# Log in
(expect "'admin' logged in"
(enter 3 "admin") # Enter user name into 3rd field
(enter 4 "admin") # Enter password into 4th field
(press "login") ) # Press the "login" button
(click "Items") # Open "Items" dialog
(click "Spare Part") # Click on "Spare Part" article
(prinl (value 8)) # Print the price (12.50)
(click "logout") # Log out
- Output:
12.50
The same example is used in the related task Simulate input/Mouse#PicoLisp.
PowerShell
The Start-Sleep CmdLet must be used because no application loads instantaneously. The -Milliseconds parameter should be adjusted accordingly for every application.
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName System.Windows.Forms
calc.exe
Start-Sleep -Milliseconds 300
[Microsoft.VisualBasic.Interaction]::AppActivate(“Calc”)
[System.Windows.Forms.SendKeys]::SendWait(“2{ADD}2=”)
PureBasic
If AW_WinActivate("Calc")
AW_SendKeys("123+3=")
EndIf
Python
import autopy
autopy.key.type_string("Hello, world!") # Prints out "Hello, world!" as quickly as OS will allow.
autopy.key.type_string("Hello, world!", wpm=60) # Prints out "Hello, world!" at 60 WPM.
autopy.key.tap(autopy.key.Code.RETURN)
autopy.key.tap(autopy.key.Code.F1)
autopy.key.tap(autopy.key.Code.LEFT_ARROW)
Target may be externally created.
>>> import pyautogui
>>> pyautogui.typewrite('Hello world!') # prints out "Hello world!" instantly
>>> pyautogui.typewrite('Hello world!', interval=0.25) # prints out "Hello world!" with a quarter second delay after each character
>>> pyautogui.press('enter') # press the Enter key
>>> pyautogui.press('f1') # press the F1 key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.keyDown('shift') # hold down the shift key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.keyUp('shift') # release the shift key
>>> pyautogui.hotkey('ctrl', 'shift', 'esc')
Racket
#lang racket/gui
(define frame (new frame%
(label "Example")
(width 300)
(height 300))) ; Defines an instance of a frame to put the canvas in
(define simulate-key-canvas%
(class canvas%
(define/public (simulate-key key)
(send this on-char key)) ; Creates a class that inherits from the standard canvas class, that can receive simulated key presses
(define/override (on-char key)
(displayln (send key get-key-code))) ; Changes the method that receives key presses to show some output
(super-new)))
(define canvas
(new simulate-key-canvas%
(parent frame))) ; Defines an instance of the newly created class
(send frame show #t) ; Shows the frame with a white canvas inside
(send canvas simulate-key (new key-event% (key-code #\k))) ; Sends the simulated key press (with a key-event% instance)
;outputs k
Raku
(formerly Perl 6)
Use libxdo bindings to send text / keystrokes to any application that will accept keystrokes from X11.
use X11::libxdo;
my $xdo = Xdo.new;
my $active = $xdo.get-active-window;
my $command = $*VM.config<os> eq 'darwin' ?? 'open' !! 'xdg-open';
shell "$command https://www.google.com";
sleep 1;
my $match = rx[^'Google '];
say my $w = $xdo.search(:name($match))<ID>;
sleep .25;
if $w {
$xdo.activate-window($w);
say "Window name: ", $xdo.get-window-name( $w );
$xdo.type($w, 'Raku language');
sleep .25;
$xdo.send-sequence($w, 'Tab');
sleep .5;
$xdo.send-sequence($w, 'Tab');
sleep .5;
$xdo.send-sequence($w, 'Tab');
sleep .5;
$xdo.send-sequence($w, 'Return');
}
REXX
Note: this REXX program only works with the above two REXXes.
/*REXX pgm shows how to use the REXX/PC PRESS cmd to simulate keyboard input.*/
call press 'This text will be put into a buffer as if it came from the keyboard'
/* [↑] text will be available for any program to use (including DOS).*/
/*stick a fork in it, we're all done. */
Rust
extern crate autopilot;
fn main() {
autopilot::key::type_string("Hello, world!", None, None, &[]);
}
Scala
import java.awt.Robot
import java.awt.event.KeyEvent
/** Keystrokes when this function is executed will go to whatever application has focus at the time.
* Special cases may need to be made for certain symbols, but most of
* the VK values in KeyEvent map to the ASCII values of characters.
*/
object Keystrokes extends App {
def keystroke(str: String) {
val robot = new Robot()
for (ch <- str) {
if (Character.isUpperCase(ch)) {
robot.keyPress(KeyEvent.VK_SHIFT)
robot.keyPress(ch)
robot.keyRelease(ch)
robot.keyRelease(KeyEvent.VK_SHIFT)
} else {
val upCh = Character.toUpperCase(ch)
robot.keyPress(upCh)
robot.keyRelease(upCh)
}
}
}
keystroke(args(0))
}
Tcl
This only works with windows created by Tk; it sends a single key "x" to the given window.
set key "x"
event generate $target <Key-$key>
To send multiple keys, call repeatedly in order. Alphabetic keys can be used directly as events, " " has to be mapped to "<space>".
package require Tk
pack [text .t]
focus -force .t
foreach c [split "hello world" ""] {
event generate .t [expr {$c eq " "?"<space>": $c}]
}
Note also that the task on keyboard macros illustrates a very closely related method.
On Windows simulate pressing the Escape, Backspace etc keys
package require twapi
twapi::send_keys ({Esc})
VBScript
The keystrokes are sent to the active window.
Dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.SendKeys "{Down}{F2}"
WScript.Sleep 1000 ' one-second delay
WshShell.SendKeys "{Left}{Left}{BkSp}{BkSp}Some text here.~" ' ~ -> Enter
Wren
As it's not currently possible for Wren-cli to access Xlib directly, we embed a Wren script in a C application to complete this task.
/* Simulate_input_Keyboard.wren */
import "random" for Random
var KeyPressMask = 1 << 0
var ShiftMask = 1 << 0
var ButtonPressMask = 1 << 2
var ExposureMask = 1 << 15
var KeyPress = 2
var ButtonPress = 4
var Expose = 12
var ClientMessage = 33
var XK_q = 0x0071
var XK_Escape = 0xff1b
foreign class XGC {
construct default(display, screenNumber) {}
}
// XEvent is a C union, not a struct, so we amalgamate the properties
foreign class XEvent {
construct new() {} // creates the union and returns a pointer to it
foreign eventType // gets type field, common to all union members
foreign eventType=(et) // sets type field
foreign state=(st) // sets xkey.state
foreign keycode // gets xkey.keycode
foreign keycode=(kc) // sets xkey.keycode
foreign sameScreen=(ss) // sets xkey.same_screen
foreign dataL // gets xclient.data.l (data is a union)
}
foreign class XDisplay {
construct openDisplay(displayName) {}
foreign defaultScreen()
foreign rootWindow(screenNumber)
foreign blackPixel(screenNumber)
foreign whitePixel(screenNumber)
foreign selectInput(w, eventMask)
foreign mapWindow(w)
foreign closeDisplay()
foreign nextEvent(eventReturn)
foreign createSimpleWindow(parent, x, y, width, height, borderWidth, border, background)
foreign drawString(d, gc, x, y, string, length)
foreign storeName(w, windowName)
foreign flush()
foreign internAtom(atomName, onlyIfExists)
foreign setWMProtocols(w, protocols, count)
foreign sendEvent(w, propogate, eventMask, eventSend)
foreign destroyWindow(w)
}
class X {
foreign static lookupKeysym(keyEvent, index)
foreign static lookupString(eventStruct, bufferReturn, bytesBuffer, keysymReturn, statusInOut)
}
/* open connection with the server */
var xd = XDisplay.openDisplay("")
if (xd == 0) {
System.print("Cannot open display.")
return
}
var s = xd.defaultScreen()
/* create window */
var w = xd.createSimpleWindow(xd.rootWindow(s), 10, 10, 350, 250, 1, xd.blackPixel(s), xd.whitePixel(s))
xd.storeName(w, "Simulate keystrokes")
/* select kind of events we are interested in */
xd.selectInput(w, ExposureMask | KeyPressMask | ButtonPressMask)
/* map (show) the window */
xd.mapWindow(w)
xd.flush()
/* default graphics context */
var gc = XGC.default(xd, s)
/* connect the close button in the window handle */
var wmDeleteWindow = xd.internAtom("WM_DELETE_WINDOW", true)
xd.setWMProtocols(w, [wmDeleteWindow], 1)
/* event loop */
var e = XEvent.new()
var rand = Random.new()
while (true) {
xd.nextEvent(e)
var et = e.eventType
if (et == Expose) {
/* draw or redraw the window */
var msg1 = "Click in the window to generate"
var msg2 = "a random key press event"
xd.drawString(w, gc, 10, 20, msg1, msg1.count)
xd.drawString(w, gc, 10, 35, msg2, msg2.count)
} else if (et == ButtonPress) {
System.print("\nButtonPress event received")
/* manufacture a KeyPress event and send it to the window */
var e2 = XEvent.new()
e2.eventType = KeyPress
e2.state = ShiftMask
e2.keycode = 24 + rand.int(33)
e2.sameScreen = true
xd.sendEvent(w, true, KeyPressMask, e2)
} else if (et == ClientMessage) {
/* delete window event */
if (e.dataL[0] == wmDeleteWindow) break
} else if (et == KeyPress) {
/* handle key press */
System.print("\nKeyPress event received")
System.print("> Keycode: %(e.keycode)")
/* exit if q or escape are pressed */
var keysym = X.lookupKeysym(e, 0)
if (keysym == XK_q || keysym == XK_Escape) {
break
} else {
var buffer = List.filled(2, 0)
var nchars = X.lookupString(e, buffer, 2, 0, 0) // don't need the last 2 parameters
if (nchars == 1) {
var b = buffer[0]
if (b < 0) b = 256 + b
System.print("> Latin-1: %(b)")
if (b < 32 || (b >= 127 && b < 160)) {
System.print("> Key 'control character' pressed")
} else {
System.print("> Key '%(String.fromByte(b))' pressed")
}
}
}
}
}
xd.destroyWindow(w)
/* close connection to server */
xd.closeDisplay()
We now embed this Wren script in the following C program, compile and run it.
/* gcc Simulate_input_Keyboard.c -o Simulate_input_Keyboard -lX11 -lwren -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "wren.h"
/* C <=> Wren interface functions */
void C_displayAllocate(WrenVM* vm) {
Display** pdisplay = (Display**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(Display*));
const char *displayName = wrenGetSlotString(vm, 1);
if (displayName == "") {
*pdisplay = XOpenDisplay(NULL);
} else {
*pdisplay = XOpenDisplay(displayName);
}
}
void C_gcAllocate(WrenVM* vm) {
GC *pgc = (GC *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(GC));
Display* display = *(Display**)wrenGetSlotForeign(vm, 1);
int s = (int)wrenGetSlotDouble(vm, 2);
*pgc = DefaultGC(display, s);
}
void C_eventAllocate(WrenVM* vm) {
wrenSetSlotNewForeign(vm, 0, 0, sizeof(XEvent));
}
void C_eventType(WrenVM* vm) {
XEvent e = *(XEvent *)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)e.type);
}
void C_setEventType(WrenVM* vm) {
XEvent *e = (XEvent *)wrenGetSlotForeign(vm, 0);
int type = (int)wrenGetSlotDouble(vm, 1);
e->type = type;
}
void C_setState(WrenVM* vm) {
XKeyEvent *ke = (XKeyEvent *)wrenGetSlotForeign(vm, 0);
unsigned int state = (unsigned int)wrenGetSlotDouble(vm, 1);
ke->state = state;
}
void C_keycode(WrenVM* vm) {
XKeyEvent ke = *(XKeyEvent *)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)ke.keycode);
}
void C_setKeycode(WrenVM* vm) {
XKeyEvent *ke = (XKeyEvent *)wrenGetSlotForeign(vm, 0);
unsigned int keycode = (unsigned int)wrenGetSlotDouble(vm, 1);
ke->keycode = keycode;
}
void C_setSameScreen(WrenVM* vm) {
XKeyEvent *ke = (XKeyEvent *)wrenGetSlotForeign(vm, 0);
Bool sameScreen = (Bool)wrenGetSlotBool(vm, 1);
ke->same_screen = sameScreen;
}
void C_dataL(WrenVM* vm) {
XClientMessageEvent cme = *(XClientMessageEvent *)wrenGetSlotForeign(vm, 0);
wrenEnsureSlots(vm, 2);
wrenSetSlotNewList(vm, 0);
int i;
for (i = 0; i < 5; ++i) {
wrenSetSlotDouble(vm, 1, (double)cme.data.l[i]);
wrenInsertInList(vm, 0, i, 1);
}
}
void C_defaultScreen(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
int screenNumber = DefaultScreen(display);
wrenSetSlotDouble(vm, 0, (double)screenNumber);
}
void C_rootWindow(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
int screenNumber = (int)wrenGetSlotDouble(vm, 1);
Window w = RootWindow(display, screenNumber);
wrenSetSlotDouble(vm, 0, (double)w);
}
void C_blackPixel(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
int screenNumber = (int)wrenGetSlotDouble(vm, 1);
unsigned long p = BlackPixel(display, screenNumber);
wrenSetSlotDouble(vm, 0, (double)p);
}
void C_whitePixel(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
int screenNumber = (int)wrenGetSlotDouble(vm, 1);
unsigned long p = WhitePixel(display, screenNumber);
wrenSetSlotDouble(vm, 0, (double)p);
}
void C_selectInput(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (Window)wrenGetSlotDouble(vm, 1);
long eventMask = (long)wrenGetSlotDouble(vm, 2);
XSelectInput(display, w, eventMask);
}
void C_mapWindow(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (Window)wrenGetSlotDouble(vm, 1);
XMapWindow(display, w);
}
void C_closeDisplay(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
XCloseDisplay(display);
}
void C_nextEvent(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
XEvent* pe = (XEvent*)wrenGetSlotForeign(vm, 1);
XNextEvent(display, pe);
}
void C_storeName(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (Window)wrenGetSlotDouble(vm, 1);
char *windowName = (char *)wrenGetSlotString(vm, 2);
XStoreName(display, w, windowName);
}
void C_flush(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
XFlush(display);
}
void C_internAtom(WrenVM* vm) {
Display* display = *(Display**)wrenGetSlotForeign(vm, 0);
char *atomName = (char *)wrenGetSlotString(vm, 1);
Bool onlyIfExists = (Bool)wrenGetSlotBool(vm, 2);
Atom atom = XInternAtom(display, atomName, onlyIfExists);
wrenSetSlotDouble(vm, 0, (double)atom);
}
void C_setWMProtocols(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (Window)wrenGetSlotDouble(vm, 1);
int count = (int)wrenGetSlotDouble(vm, 3);
Atom protocols[count];
int i;
for (i = 0; i < count; ++i) {
wrenGetListElement(vm, 2, i, 1);
protocols[i] = (Atom)wrenGetSlotDouble(vm, 1);
}
XSetWMProtocols(display, w, protocols, count);
}
void C_sendEvent(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (Window)wrenGetSlotDouble(vm, 1);
Bool propogate = (Bool)wrenGetSlotBool(vm, 2);
long eventMask = (long)wrenGetSlotDouble(vm, 3);
XEvent* pe = (XEvent*)wrenGetSlotForeign(vm, 4);
XSendEvent(display, w, propogate, eventMask, pe);
}
void C_destroyWindow(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (Window)wrenGetSlotDouble(vm, 1);
XDestroyWindow(display, w);
}
void C_createSimpleWindow(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Window parent = (Window)wrenGetSlotDouble(vm, 1);
int x = (int)wrenGetSlotDouble(vm, 2);
int y = (int)wrenGetSlotDouble(vm, 3);
unsigned int width = (unsigned int)wrenGetSlotDouble(vm, 4);
unsigned int height = (unsigned int)wrenGetSlotDouble(vm, 5);
unsigned int borderWidth = (unsigned int)wrenGetSlotDouble(vm, 6);
unsigned long border = (unsigned long)wrenGetSlotDouble(vm, 7);
unsigned long background = (unsigned long)wrenGetSlotDouble(vm, 8);
Window w = XCreateSimpleWindow(display, parent, x, y, width, height, borderWidth, border, background);
wrenSetSlotDouble(vm, 0, (double)w);
}
void C_drawString(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Drawable d = (Drawable)wrenGetSlotDouble(vm, 1);
GC gc = *(GC *)wrenGetSlotForeign(vm, 2);
int x = (int)wrenGetSlotDouble(vm, 3);
int y = (int)wrenGetSlotDouble(vm, 4);
const char *string = wrenGetSlotString(vm, 5);
int length = (int)wrenGetSlotDouble(vm, 6);
XDrawString(display, d, gc, x, y, string, length);
}
void C_lookupKeysym(WrenVM* vm) {
XKeyEvent *pke = (XKeyEvent*)wrenGetSlotForeign(vm, 1);
int index = (int)wrenGetSlotDouble(vm, 2);
KeySym k = XLookupKeysym(pke, index);
wrenSetSlotDouble(vm, 0, (double)k);
}
void C_lookupString(WrenVM* vm) {
XKeyEvent *pke = (XKeyEvent*)wrenGetSlotForeign(vm, 1);
int bytesBuffer = (int)wrenGetSlotDouble(vm, 3);
char bufferReturn[bytesBuffer];
int i;
for (i = 0; i < bytesBuffer; ++i) {
wrenGetListElement(vm, 2, i, 3);
bufferReturn[i] = (char)wrenGetSlotDouble(vm, 3);
}
int count = XLookupString(pke, bufferReturn, bytesBuffer, NULL, NULL);
for (i = 0; i < 2; ++i) {
wrenSetSlotDouble(vm, 3, (double)bufferReturn[i]);
wrenSetListElement(vm, 2, i, 3);
}
wrenSetSlotDouble(vm, 0, (double)count);
}
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.finalize = NULL;
if (strcmp(className, "XDisplay") == 0) {
methods.allocate = C_displayAllocate;
} else if (strcmp(className, "XGC") == 0) {
methods.allocate = C_gcAllocate;
} else if (strcmp(className, "XEvent") == 0) {
methods.allocate = C_eventAllocate;
} else {
methods.allocate = NULL;
}
return methods;
}
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "XEvent") == 0) {
if (!isStatic && strcmp(signature, "eventType") == 0) return C_eventType;
if (!isStatic && strcmp(signature, "eventType=(_)") == 0) return C_setEventType;
if (!isStatic && strcmp(signature, "state=(_)") == 0) return C_setState;
if (!isStatic && strcmp(signature, "keycode") == 0) return C_keycode;
if (!isStatic && strcmp(signature, "keycode=(_)") == 0) return C_setKeycode;
if (!isStatic && strcmp(signature, "sameScreen=(_)") == 0) return C_setSameScreen;
if (!isStatic && strcmp(signature, "dataL") == 0) return C_dataL;
} else if (strcmp(className, "XDisplay") == 0) {
if (!isStatic && strcmp(signature, "defaultScreen()") == 0) return C_defaultScreen;
if (!isStatic && strcmp(signature, "rootWindow(_)") == 0) return C_rootWindow;
if (!isStatic && strcmp(signature, "blackPixel(_)") == 0) return C_blackPixel;
if (!isStatic && strcmp(signature, "whitePixel(_)") == 0) return C_whitePixel;
if (!isStatic && strcmp(signature, "selectInput(_,_)") == 0) return C_selectInput;
if (!isStatic && strcmp(signature, "mapWindow(_)") == 0) return C_mapWindow;
if (!isStatic && strcmp(signature, "closeDisplay()") == 0) return C_closeDisplay;
if (!isStatic && strcmp(signature, "nextEvent(_)") == 0) return C_nextEvent;
if (!isStatic && strcmp(signature, "storeName(_,_)") == 0) return C_storeName;
if (!isStatic && strcmp(signature, "flush()") == 0) return C_flush;
if (!isStatic && strcmp(signature, "internAtom(_,_)") == 0) return C_internAtom;
if (!isStatic && strcmp(signature, "setWMProtocols(_,_,_)") == 0) return C_setWMProtocols;
if (!isStatic && strcmp(signature, "sendEvent(_,_,_,_)") == 0) return C_sendEvent;
if (!isStatic && strcmp(signature, "destroyWindow(_)") == 0) return C_destroyWindow;
if (!isStatic && strcmp(signature, "createSimpleWindow(_,_,_,_,_,_,_,_)") == 0) return C_createSimpleWindow;
if (!isStatic && strcmp(signature, "drawString(_,_,_,_,_,_)") == 0) return C_drawString;
} else if (strcmp(className, "X") == 0) {
if (isStatic && strcmp(signature, "lookupKeysym(_,_)") == 0) return C_lookupKeysym;
if (isStatic && strcmp(signature, "lookupString(_,_,_,_,_)") == 0) return C_lookupString;
}
}
return NULL;
}
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Simulate_input_Keyboard.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}
- Programming Tasks
- GUI
- Testing
- ACL2/Omit
- Batch File/Omit
- Brainf***/Omit
- Maxima/Omit
- Modula-3/Omit
- PARI/GP/Omit
- PHP/Omit
- PostScript/Omit
- R/Omit
- Retro/Omit
- SmileBASIC/Omit
- TI-83 BASIC/Omit
- TI-89 BASIC/Omit
- Zkl/Omit
- AutoHotkey
- AutoIt
- BASIC
- Applesoft BASIC
- Commodore BASIC
- C
- Xlib
- Gadget
- Clojure
- Go
- Keybd event
- GUISS
- Java
- AWT
- Kotlin
- LabVIEW
- Nim
- OCaml
- OCaml-Xlib
- Oz
- Tk
- Perl
- Phix
- Phix/pGUI
- PicoLisp
- PowerShell
- PureBasic
- AutoWin
- Python
- AutoPy
- PyAutoGUI
- Racket
- Raku
- REXX
- Rust
- AutoPilot
- Scala
- Tcl
- VBScript
- Wren