Simulate input/Keyboard: Difference between revisions

m
→‎{{header|Wren}}: Added compilation hint for C program.
m (→‎{{header|Raku}}: New default)
m (→‎{{header|Wren}}: Added compilation hint for C program.)
 
(17 intermediate revisions by 8 users not shown)
Line 11:
{{omit from|Retro}}
{{omit from|SmileBASIC}}
{{omit from|TI-83 BASIC}} {{omit from|TI-89 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}}==
Target may be externally created.
<langsyntaxhighlight AutoHotkeylang="autohotkey">run, cmd /k
WinWait, ahk_class ConsoleWindowClass
controlsend, ,hello console, ahk_class ConsoleWindowClass</langsyntaxhighlight>
 
=={{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.
<langsyntaxhighlight AutoItlang="autoit">Run("notepad")
WinWaitActive("Untitled - Notepad")
Send("The answer is 42")</langsyntaxhighlight>
 
It takes user input in variable using "input box"
and displays that in "message box"
<langsyntaxhighlight AutoItlang="autoit">$name="type your name here"
$name = InputBox("Name","Your name please ?",$name)
MsgBox(0,"Name","Your name is: "&$name)</langsyntaxhighlight>
 
=={{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}}==
Line 46 ⟶ 102:
gcc -o simkeypress -L/usr/X11R6/lib -lX11 simkeypress.c
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
Line 159 ⟶ 215:
XCloseDisplay(dpy);
return 1;
}</langsyntaxhighlight>
 
 
{{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}}==
{{trans|Java}}
<langsyntaxhighlight Clojurelang="clojure">(import java.awt.Robot)
(import java.awt.event.KeyEvent)
(defn keytype [str]
Line 177 ⟶ 360:
(doto robot
(.keyPress (int upCh))
(.keyRelease (int upCh))))))))</langsyntaxhighlight>
 
=={{header|Go}}==
Line 187 ⟶ 370:
 
N.B. You may need to execute: 'sudo chmod +0666 /dev/uinput' first if running on Linux.
<langsyntaxhighlight lang="go">package main
 
import (
Line 215 ⟶ 398:
log.Fatal(err)
}
}</langsyntaxhighlight>
 
=={{header|GUISS}}==
 
<langsyntaxhighlight lang="guiss">Start,Programs,Accessories,Notepad,Textbox,Type:Hello World[pling]</langsyntaxhighlight>
 
=={{header|Java}}==
Line 227 ⟶ 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.
<langsyntaxhighlight lang="java5">import java.awt.Robot
public static void type(String str){
Robot robot = new Robot();
Line 242 ⟶ 425:
}
}
}</langsyntaxhighlight>
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.1.2
 
import java.awt.Robot
Line 265 ⟶ 448:
fun main(args: Array<String>) {
sendChars("dir") // runs 'dir' command
}</langsyntaxhighlight>
 
=={{header|LabVIEW}}==
Line 273 ⟶ 456:
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.
<langsyntaxhighlight lang="nim">when defined(windows):
import winlean
else:
Line 354 ⟶ 537:
 
main()
</syntaxhighlight>
</lang>
Compile and run it by (assuming we have GNU C compiler):
<pre>nim c -r ourfile.nim</pre>
Line 367 ⟶ 550:
ocaml -I +Xlib Xlib.cma keysym.cma send_event.ml
 
<langsyntaxhighlight lang="ocaml">open Xlib
 
let () =
Line 471 ⟶ 654:
(* close connection to server *)
xCloseDisplay d;
;;</langsyntaxhighlight>
 
=={{header|Oz}}==
Line 477 ⟶ 660:
 
Oz' default GUI toolkit is based on Tk. So we can do the same thing as in Tcl:
<langsyntaxhighlight lang="oz">declare
[QTk] = {Module.link ['x-oz://system/wp/QTk.ozf']}
Entry
Line 490 ⟶ 673:
{Delay 100}
{Tk.send event(generate Entry Key)}
end</langsyntaxhighlight>
 
This only works with internal windows.
Line 499 ⟶ 682:
Target may be externally created, but process must be able to open tty/pty for writing.
 
<langsyntaxhighlight 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 ;
Line 507 ⟶ 690:
sleep(2);
foreach $a ( @c ) { ioctl(TTY,$TIOCSTI,$a); select(undef,undef,undef,0.1);} ;
print "DONE\n";</langsyntaxhighlight>
 
 
Line 517 ⟶ 700:
Target may be externally created.
 
<langsyntaxhighlight lang="perl">SendKeys("Hello, how are you?\n");</langsyntaxhighlight>
 
=={{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}}==
Line 529 ⟶ 744:
in the following example. Keyboard input is simulated with the function 'enter'
to fill the login form's name and password fields.
<langsyntaxhighlight PicoLisplang="picolisp">(load "@lib/http.l" "@lib/scrape.l")
 
# Connect to the demo app at http://7fach.de/8080
Line 543 ⟶ 758:
(click "Spare Part") # Click on "Spare Part" article
(prinl (value 8)) # Print the price (12.50)
(click "logout") # Log out</langsyntaxhighlight>
{{out}}
<pre>12.50</pre>
Line 551 ⟶ 766:
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">
<lang PowerShell>
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName System.Windows.Forms
Line 558 ⟶ 773:
[Microsoft.VisualBasic.Interaction]::AppActivate(“Calc”)
[System.Windows.Forms.SendKeys]::SendWait(“2{ADD}2=”)
</syntaxhighlight>
</lang>
 
=={{header|PureBasic}}==
{{libheader|AutoWin}}
 
<langsyntaxhighlight PureBasiclang="purebasic">If AW_WinActivate("Calc")
AW_SendKeys("123+3=")
EndIf</langsyntaxhighlight>
 
=={{header|Python}}==
Line 572 ⟶ 787:
{{libheader|AutoPy}}
 
<langsyntaxhighlight Pythonlang="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)</langsyntaxhighlight>
 
{{works with|Python|2.5+}}
Line 585 ⟶ 800:
Target may be externally created.
 
<langsyntaxhighlight Pythonlang="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
Line 594 ⟶ 809:
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.keyUp('shift') # release the shift key
>>> pyautogui.hotkey('ctrl', 'shift', 'esc')</langsyntaxhighlight>
 
=={{header|Racket}}==
<langsyntaxhighlight Racketlang="racket">#lang racket/gui
 
(define frame (new frame%
Line 620 ⟶ 835:
(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</langsyntaxhighlight>
 
=={{header|Raku}}==
Line 627 ⟶ 842:
Use libxdo bindings to send text / keystrokes to any application that will accept keystrokes from X11.
 
<syntaxhighlight lang="raku" perl6line>use X11::libxdo;
 
my $xdo = Xdo.new;
Line 639 ⟶ 854:
sleep 1;
 
my $match = rx[^'Google -'];
 
say my $w = $xdo.search(:name($match))<ID>;
Line 648 ⟶ 863:
$xdo.activate-window($w);
say "Window name: ", $xdo.get-window-name( $w );
$xdo.type($w, 'Raku language');
sleep .25;
$xdo.send-sequence($w, 'Tab');
Line 657 ⟶ 872:
sleep .5;
$xdo.send-sequence($w, 'Return');
}</langsyntaxhighlight>
 
=={{header|REXX}}==
Line 663 ⟶ 878:
{{works with|Personal REXX}}
Note: &nbsp; this REXX program &nbsp; ''only'' &nbsp; works with the above two REXXes.
<langsyntaxhighlight 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. */</langsyntaxhighlight><br><br>
 
=={{header|Rust}}==
Line 674 ⟶ 889:
{{libheader|AutoPilot}}
 
<langsyntaxhighlight Rustlang="rust">extern crate autopilot;
fn main() {
autopilot::key::type_string("Hello, world!", None, None, &[]);
}</langsyntaxhighlight>
 
=={{header|Scala}}==
{{libheader|Scala}}
<langsyntaxhighlight lang="scala">import java.awt.Robot
import java.awt.event.KeyEvent
 
Line 706 ⟶ 921:
}
keystroke(args(0))
}</langsyntaxhighlight>
 
=={{header|Tcl}}==
Line 713 ⟶ 928:
This only works with windows created by Tk;
it sends a single key "x" to the given window.
<langsyntaxhighlight lang="tcl">set key "x"
event generate $target <Key-$key></langsyntaxhighlight>
To send multiple keys, call repeatedly in order.
Alphabetic keys can be used directly as events, " " has to be mapped to "<space>".
<langsyntaxhighlight Tcllang="tcl">package require Tk
pack [text .t]
focus -force .t
foreach c [split "hello world" ""] {
event generate .t [expr {$c eq " "?"<space>": $c}]
}</langsyntaxhighlight>
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}}==
The keystrokes are sent to the active window.
 
<langsyntaxhighlight lang="vbscript">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</langsyntaxhighlight>
 
=={{header|Wren}}==
{{trans|C}}
{{libheader|Xlib}}
<br>
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.
<syntaxhighlight lang="wren">/* 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()</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>
9,476

edits