RosettaCodeData/Task/Simulate-input-Keyboard/Wren/simulate-input-keyboard-1.wren

161 lines
4.4 KiB
Plaintext

/* 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()