Simulate input/Mouse: Difference between revisions

Content added Content deleted
(Added Wren)
Line 552: Line 552:
Note that many of Tk's windows also need appropriate <Enter> and <Leave> events in order to work correctly. For the process of actually simulating a click on a button, it is actually easier to work at the method-call level rather than the event generation level:
Note that many of Tk's windows also need appropriate <Enter> and <Leave> events in order to work correctly. For the process of actually simulating a click on a button, it is actually easier to work at the method-call level rather than the event generation level:
<lang tcl>.okBtn invoke</lang>
<lang tcl>.okBtn invoke</lang>

=={{header|Wren}}==
{{libheader|Xlib}}
<br>
The following program - an embedded Wren application using a C host to communicate with Xlib - reuses most of the code from the [[Simulate input/Keyboard#Wren]] task.

However, a mouse click here switches the background color of the window from white to green and vice versa. Pressing the 'a' key simulates a mouse click to achieve the safe effect.

Xlib can of course work with any X server, local or remote.
<lang ecmascript>/* simulate_input_keyboard.wren */

var KeyPressMask = 1 << 0
var ButtonPressMask = 1 << 2
var Button1Mask = 1 << 8
var ExposureMask = 1 << 15
var Button1 = 1
var KeyPress = 2
var ButtonPress = 4
var Expose = 12
var ClientMessage = 33

var XK_a = 0x0061
var XK_q = 0x0071
var XK_Escape = 0xff1b

foreign class XGC {
construct default(display, screenNumber) {}
}

foreign class XColormap {
construct default(display, screenNumber) {}
}

foreign class XColor {
construct new() {}

foreign pixel
}

// 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 button // gets xbutton.button

foreign button=(b) // sets xbutton.button

foreign state=(st) // sets xbutton.state

foreign sameScreen=(ss) // sets xbutton.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)

foreign parseColor(colormap, spec, exactDefReturn)

foreign allocColor(colormap, screenInOut)

foreign setWindowBackground(w, backgroundPixel)

foreign clearArea(w, x, y, width, height, exposures)
}

class X {
foreign static lookupKeysym(keyEvent, index)
}

/* 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 mouse press")
var white = true // current background color

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

/* create color green */
var green = XColor.new()
var colormap = XColormap.default(xd, s)
xd.parseColor(colormap, "#00FF00", green)
xd.allocColor(colormap, green)

/* event loop */
var e = XEvent.new()
while (true) {
xd.nextEvent(e)
var et = e.eventType
if (et == Expose) {
/* draw or redraw the window */
var msg1 = "Press the 'a' key to switch the background color"
var msg2 = "between white and green."
xd.drawString(w, gc, 10, 20, msg1, msg1.count)
xd.drawString(w, gc, 10, 35, msg2, msg2.count)
} else if (et == ButtonPress) {
System.write("\nButtonPress event received, ")
if (white) {
System.print("switching from white to green")
xd.setWindowBackground(w, green.pixel)
} else {
System.print("switching from green to white")
xd.setWindowBackground(w, xd.whitePixel(s))
}
xd.clearArea(w, 0, 0, 0, 0, true)
white = !white
} else if (et == ClientMessage) {
/* delete window event */
if (e.dataL[0] == wmDeleteWindow) break
} else if (et == KeyPress) {
System.print("\nKeyPress event received")
/* exit if q or escape are pressed */
var keysym = X.lookupKeysym(e, 0)
if (keysym == XK_q || keysym == XK_Escape) {
break
} else if (keysym == XK_a) {
/* if a is pressed, manufacture a ButtonPress event and send it to the window */
System.print("> Key 'a' pressed, sending ButtonPress event")
var e2 = XEvent.new()
e2.eventType = ButtonPress
e2.state = Button1Mask
e2.button = Button1
e2.sameScreen = true
xd.sendEvent(w, true, ButtonPressMask, e2)
} else {
System.print("> Key other than 'a' pressed, not processed")
}
}
}

xd.destroyWindow(w)

/* close connection to server */
xd.closeDisplay()</lang>
<br>
We now embed this Wren script in the following C program, compile and run it.
<lang c>#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_colormapAllocate(WrenVM* vm) {
Colormap *pcm = (Colormap *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(Colormap));
Display* display = *(Display**)wrenGetSlotForeign(vm, 1);
int s = (int)wrenGetSlotDouble(vm, 2);
*pcm = DefaultColormap(display, s);
}

void C_colorAllocate(WrenVM* vm) {
wrenSetSlotNewForeign(vm, 0, 0, sizeof(XColor));
}

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_button(WrenVM* vm) {
XButtonEvent be = *(XButtonEvent *)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)be.button);
}

void C_setButton(WrenVM* vm) {
XButtonEvent *be = (XButtonEvent *)wrenGetSlotForeign(vm, 0);
unsigned int button = (unsigned int)wrenGetSlotDouble(vm, 1);
be->button = button;
}

void C_setState(WrenVM* vm) {
XButtonEvent *be = (XButtonEvent *)wrenGetSlotForeign(vm, 0);
unsigned int state = (unsigned int)wrenGetSlotDouble(vm, 1);
be->state = state;
}

void C_setSameScreen(WrenVM* vm) {
XButtonEvent *be = (XButtonEvent *)wrenGetSlotForeign(vm, 0);
Bool sameScreen = (Bool)wrenGetSlotBool(vm, 1);
be->same_screen = sameScreen;
}

void C_pixel(WrenVM* vm) {
XColor c = *(XColor *)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)c.pixel);
}

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_parseColor(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Colormap cm = *(Colormap *)wrenGetSlotForeign(vm, 1);
char *spec = (char *)wrenGetSlotString(vm, 2);
XColor* pc = (XColor*)wrenGetSlotForeign(vm, 3);
XParseColor(display, cm, spec, pc);
}

void C_allocColor(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Colormap cm = *(Colormap *)wrenGetSlotForeign(vm, 1);
XColor* pc = (XColor*)wrenGetSlotForeign(vm, 2);
XAllocColor(display, cm, pc);
}

void C_setWindowBackground(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (Window)wrenGetSlotDouble(vm, 1);
unsigned long backgroundPixel = (unsigned long)wrenGetSlotDouble(vm, 2);
XSetWindowBackground(display, w, backgroundPixel);
}

void C_clearArea(WrenVM* vm) {
Display *display = *(Display**)wrenGetSlotForeign(vm, 0);
Window w = (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);
Bool exposures = (Bool)wrenGetSlotBool(vm, 6);
XClearArea(display, w, x, y, width, height, exposures);
}

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);
}

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 if (strcmp(className, "XColormap") == 0) {
methods.allocate = C_colormapAllocate;
} else if (strcmp(className, "XColor") == 0) {
methods.allocate = C_colorAllocate;
} 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, "button") == 0) return C_button;
if (!isStatic && strcmp(signature, "button=(_)") == 0) return C_setButton;
if (!isStatic && strcmp(signature, "state=(_)") == 0) return C_setState;
if (!isStatic && strcmp(signature, "sameScreen=(_)") == 0) return C_setSameScreen;
if (!isStatic && strcmp(signature, "dataL") == 0) return C_dataL;
} else if (strcmp(className, "XColor") == 0) {
if (!isStatic && strcmp(signature, "pixel") == 0) return C_pixel;
} 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;
if (!isStatic && strcmp(signature, "parseColor(_,_,_)") == 0) return C_parseColor;
if (!isStatic && strcmp(signature, "allocColor(_,_)") == 0) return C_allocColor;
if (!isStatic && strcmp(signature, "setWindowBackground(_,_)") == 0) return C_setWindowBackground;
if (!isStatic && strcmp(signature, "clearArea(_,_,_,_,_,_)") == 0) return C_clearArea;
} else if (strcmp(className, "X") == 0) {
if (isStatic && strcmp(signature, "lookupKeysym(_,_)") == 0) return C_lookupKeysym;
}
}
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_mouse.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;
}</lang>


{{omit from|ACL2}}
{{omit from|ACL2}}