Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Pasting into Second Life Linux client - a workaround

Zi Ree
Mrrrew!
Join date: 25 Feb 2006
Posts: 723
03-08-2006 13:56
Hi Linux group!

I hacked a perl script that sends x-events to the Second Life client, so I can write my LSL scripts in my favorite editor and paste them into SL. It's still very ugly, but at least it's a start. Copy is not possible this way, but maybe someone finds this script useful. German and english/US keymap support is already implemented. Other layouts can be added.

You will need xse to use the script. Get it from ftp://ftp.uni-magdeburg.de/pub/mirror/hpux.ask.uni-karlsruhe.de/X11/Misc/xse-2.1

Have fun!

CODE

#!/usr/bin/perl -w

# text2xev.pl V0.1 (C)2006 Zi Ree@Second Life
# converter for pasting text into Second Life client window.
# use, copy, modify and spread freely, I hope it wonj't be needed too much longer :)
# have fun!
# -- Zi!

# you need xse installed somewhere
# get it from ftp://ftp.uni-magdeburg.de/pub/mirror/hpux.ask.uni-karlsruhe.de/X11/Misc/xse-2.1

use strict;

# Your Second Life window id (try xwininfo to get it)
my($id)="0x2a0000e";

# path to the xse binary
my($xse)="xse-2.1/xse";

my($line);

# read from stdin
while($line=<>)
{
my($char);
$line =~ s/^ +//; # skip blanks in the front, makes LSL editor behave better

# split line into individual characters
my(@chars)=split //,$line;
my($oldsym)="";

# go through characters
foreach $char (@chars)
{
# convert key to xevent syntax, depending on keyboard layout
my($output,$sym)=char2xev($char);

# pause for a moment if the same key is pressed twice (events get lost otherwise)
if($sym eq $oldsym)
{
select(undef,undef,undef,0.25);
}

# send events via xse to the Second Life client
open(XSE,"| $xse -window $id -file /dev/stdin");
print XSE $output;
close(XSE);

# remember sent key
$oldsym=$sym;
} # foreach
} # while

# ------------------------

sub char2xev
{
my($char)=shift;
if($char eq "\n")
{
$char="LF";
}

# modifier key / states
my(%modifiers)=(
"-" => "",
"s" => "Shift",
"l" => "Lock",
"c" => "Ctrl",
"a" => "Mod1", # untested
"g" => "Mod5" # ALT-GR for german keyboard
);

# select one of the following mappings by calling it "%conv"
# more mappings can be added later

# german keyboard mapping (currently active)
my(%conv)=(
"^" => ["-","dead_circumflex"],
"ß" => ["-","ssharp"],
"´" => ["-","dead_acute"],
"°" => ["s","dead_circumflex"],
"!" => ["s","1"],
"\"" => ["s","2"],
"§" => ["s","3"],
"\$" => ["s","4"],
"%" => ["s","5"],
"&" => ["s","6"],
"/" => ["s","7"],
"(" => ["s","8"],
")" => ["s","9"],
"=" => ["s","0"],
"?" => ["s","ssharp"],
"`" => ["s","dead_acute"],
"¬" => ["g","dead_circumflex"],
"¹" => ["g","1"],
"²" => ["g","2"],
"³" => ["g","3"],
"¼" => ["g","4"],
"½" => ["g","5"],
"¬" => ["g","6"],
"{" => ["g","7"],
"[" => ["g","8"],
"]" => ["g","9"],
"}" => ["g","0"],
"\\" => ["g","ssharp"],
"ü" => ["-","udiaeresis"],
"+" => ["-","plus"],
"\t" => ["-","Tab"],
"Q" => ["s","q"],
"W" => ["s","w"],
"E" => ["s","e"],
"R" => ["s","r"],
"T" => ["s","t"],
"Z" => ["s","z"],
"U" => ["s","u"],
"I" => ["s","i"],
"O" => ["s","o"],
"P" => ["s","p"],
"Ü" => ["s","udiaeresis"],
"*" => ["s","plus"],
"@" => ["g","q"],
"~" => ["g","plus"],
"ö" => ["-","odiaeresis"],
"ä" => ["-","adiaeresis"],
"#" => ["-","numbersign"],
"A" => ["s","a"],
"S" => ["s","s"],
"D" => ["s","d"],
"F" => ["s","f"],
"G" => ["s","g"],
"H" => ["s","h"],
"J" => ["s","j"],
"K" => ["s","k"],
"L" => ["s","l"],
"Ö" => ["s","odiaeresis"],
"Ä" => ["s","adiaeresis"],
"'" => ["s","numbersign"],
"<" => ["-","less"],
"," => ["-","comma"],
"." => ["-","period"],
"-" => ["-","minus"],
">" => ["s","less"],
"Y" => ["s","y"],
"X" => ["s","x"],
"C" => ["s","c"],
"V" => ["s","v"],
"B" => ["s","b"],
"N" => ["s","n"],
"M" => ["s","m"],
";" => ["s","comma"],
":" => ["s","period"],
"_" => ["s","minus"],
"|" => ["g","less"],
"µ" => ["g","m"],
"·" => ["g","period"],
" " => ["-","space"],
"LF" => ["-","Return"],
);

# english (EN or US) keyboard mapping (partly untested)
my(%conv_us)=(
"`" => ["-","grave"],
"-" => ["-","minus"],
"=" => ["-","equal"],
"~" => ["s","grave"],
"!" => ["s","1"],
"@" => ["s","2"],
"#" => ["s","3"],
"\$" => ["s","4"],
"%" => ["s","5"],
"^" => ["s","6"],
"&" => ["s","7"],
"*" => ["s","8"],
"(" => ["s","9"],
")" => ["s","0"],
"_" => ["s","minus"],
"+" => ["s","equal"],
"\t" => ["-","Tab"],
"[" => ["-","braceleft"],
"]" => ["-","braceright"],
"Q" => ["s","q"],
"W" => ["s","w"],
"E" => ["s","e"],
"R" => ["s","r"],
"T" => ["s","t"],
"Y" => ["s","y"],
"U" => ["s","u"],
"I" => ["s","i"],
"O" => ["s","o"],
"P" => ["s","p"],
"{" => ["s","braceleft"],
"}" => ["s","braceright"],
";" => ["-","semicolon"],
"'" => ["-","apostrophe"],
"\\" => ["-","backslash"],
"A" => ["s","a"],
"S" => ["s","s"],
"D" => ["s","d"],
"F" => ["s","f"],
"G" => ["s","g"],
"H" => ["s","h"],
"J" => ["s","j"],
"K" => ["s","k"],
"L" => ["s","l"],
":" => ["s","semicolon"],
"\"" => ["s","apostrophe"],
"|" => ["s","backslash"],
"," => ["-","comma"],
"." => ["-","period"],
"/" => ["-","slash"],
"Z" => ["s","z"],
"X" => ["s","x"],
"C" => ["s","c"],
"V" => ["s","v"],
"B" => ["s","b"],
"N" => ["s","n"],
"M" => ["s","m"],
"<" => ["s","comma"],
">" => ["s","period"],
"?" => ["s","slash"],
" " => ["-","space"],
"LF" => ["-","Return"],
);
# if key is on convert list
if(defined($conv{$char}))
{
my($out)="";

# get event definition
my($def)=$conv{$char};

# build xse string
$out=$modifiers{@$def[0]}."<Key>".@$def[1]."\n".$modifiers{@$def[0]}."<KeyUp>".@$def[1]."\n";
return ($out,@$def[1]);
}
else
{
# standard letter / digit, just return xse string
return ("<Key>$char\n<KeyUp>$char\n",$char);
}
}
_____________________
Zi!

(SuSE Linux 10.2, Kernel 2.6.13-15, AMD64 3200+, 2GB RAM, NVidia GeForce 7800GS 512MB (AGP), KDE 3.5.5, Second Life 1.13.1 (6) alpha soon beta thingie)

Blog: http://ziree.wordpress.com/ - QAvimator: http://qavimator.org

Second Life Linux Users Group IRC Channel: irc.freenode.org #secondlifelug
Hello Toonie
Registered User
Join date: 25 Jul 2005
Posts: 212
03-08-2006 15:29
It fakes pasting by sending a whole load of synthetic keypress events to the Second Life window? That's hideous and great. XD
Sky Roundfield
Registered User
Join date: 10 Feb 2006
Posts: 44
03-08-2006 16:38
Wow, that's evil. It's also exactly what I need to enter some scripts. Thanks a bunch!
Khamon Fate
fategardens.net
Join date: 21 Nov 2003
Posts: 4,177
03-08-2006 18:30
/hearty clap
_____________________
Visit the Fate Gardens Website @ fategardens.net
Jarod Godel
Utilitarian
Join date: 6 Nov 2003
Posts: 729
03-08-2006 18:42
Sir... Dude... I mean... You need to email Wilder Linden now and get this on the SLHacks Wiki. You will be-- NO! You are the king of SL hacks!

Bravo. :)
_____________________
"All designers in SL need to be aware of the fact that there are now quite simple methods of complete texture theft in SL that are impossible to stop..." - Cristiano Midnight

Ad aspera per intelligentem prohibitus.
ninjafoo Ng
Just me :)
Join date: 11 Feb 2006
Posts: 713
03-08-2006 21:51
Only on Linux - Inspired and evil all at the same time!
_____________________
FooRoo : clothes,bdsm,cages,houses & scripts

QAvimator (Linux, MacOS X & Windows) : http://qavimator.org/
Zi Ree
Mrrrew!
Join date: 25 Feb 2006
Posts: 723
03-08-2006 23:47
Mew!

I'm glad the script helped some of you. I will continue to improve things here as needed, feature requests are welcome. I'm planning on a scripted "Button Box" where you can add / remove buttons and define texts and commands to be sent. This could make the use of /1commands much simpler if you have a lot of them.

I also think about an external editor that mimics the LSL editor and sends the keystrokes as typed... but that is still in the future :D
_____________________
Zi!

(SuSE Linux 10.2, Kernel 2.6.13-15, AMD64 3200+, 2GB RAM, NVidia GeForce 7800GS 512MB (AGP), KDE 3.5.5, Second Life 1.13.1 (6) alpha soon beta thingie)

Blog: http://ziree.wordpress.com/ - QAvimator: http://qavimator.org

Second Life Linux Users Group IRC Channel: irc.freenode.org #secondlifelug
Angel Sunset
Linutic
Join date: 7 Apr 2005
Posts: 636
03-11-2006 09:08
Hacker King :D
_____________________
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kubuntu Intrepid 8.10, KDE, linux 2.6.27-11, X.Org 11.0, server glx vendor: NVIDIA Corporation, server glx version: 1.5.2, OpenGL vendor: NVIDIA Corporation, OpenGL renderer: GeForce 9800 GTX+/PCI/SSE2, OpenGL version: 3.0.0 NVIDIA 180.29, glu version: 1.3, NVidia GEForce 9800 GTX+ 512 MB, Intel Core 2 Duo, Mem: 3371368k , Swap: 2570360k
Zi Ree
Mrrrew!
Join date: 25 Feb 2006
Posts: 723
03-11-2006 09:19
Queen!

*pouts*

;)
_____________________
Zi!

(SuSE Linux 10.2, Kernel 2.6.13-15, AMD64 3200+, 2GB RAM, NVidia GeForce 7800GS 512MB (AGP), KDE 3.5.5, Second Life 1.13.1 (6) alpha soon beta thingie)

Blog: http://ziree.wordpress.com/ - QAvimator: http://qavimator.org

Second Life Linux Users Group IRC Channel: irc.freenode.org #secondlifelug
Angel Sunset
Linutic
Join date: 7 Apr 2005
Posts: 636
03-11-2006 13:26
:eek:

I said King?

:(

hehehe
_____________________
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kubuntu Intrepid 8.10, KDE, linux 2.6.27-11, X.Org 11.0, server glx vendor: NVIDIA Corporation, server glx version: 1.5.2, OpenGL vendor: NVIDIA Corporation, OpenGL renderer: GeForce 9800 GTX+/PCI/SSE2, OpenGL version: 3.0.0 NVIDIA 180.29, glu version: 1.3, NVidia GEForce 9800 GTX+ 512 MB, Intel Core 2 Duo, Mem: 3371368k , Swap: 2570360k
Orren Walcott
BraveAlphaClientPioneer
Join date: 27 Oct 2005
Posts: 5
04-01-2006 17:05
Ah, many thanks! This helped me write a tiny bash script to keep SL from logging off after 30 minutes:

#!/bin/bash
while true; do
xse -window 0x2c0000e '<MotionNotify> Normal'
sleep 600
done

Basically just an infinite loop that sends a mouse motion event every 10 minutes. Run it in the background and end it with killall; I'm too lazy to put any kind of control on it.
Claude Desmoulins
Registered User
Join date: 1 Nov 2005
Posts: 388
04-01-2006 21:25
Any idea how to rewrite these for xte? is the -x option in xte equivalent to -window in xse?
Rizzermon Sopor
Registered User
Join date: 15 Mar 2006
Posts: 43
Works Great!
04-02-2006 19:27
The script works great for regular and IM messages as well. Thanks very much for this cool script. I wish I had it the other night when someone had asked me for a web site that had such a long listing that I told them I was on the linux client and it was too long for me to type. :(

For the sake of newer linux users trying this script, one needs to modify two lines in the script for it to work. One is the window id (around line 15 of the script) and the other the location of xse on the system (around line 18 of the script).

Great script Zi Ree and thanks a lot. :D

Edit: Oh, I notice one needs to select the keyboard layout too. I changed to the us layout. So far it works flawlessly.
Jabador Jimador
happy submissive
Join date: 28 Sep 2005
Posts: 15
04-03-2006 12:40
Uhm... this might be a silly / stupid question.
But how would one use this script?
_____________________
Jabador Jimador
Owned and collared by Master Spiritfire Musketeer
Any questions or complaints are to be directed to Him
Rizzermon Sopor
Registered User
Join date: 15 Mar 2006
Posts: 43
04-03-2006 17:27
From: Jabador Jimador
Uhm... this might be a silly / stupid question.
But how would one use this script?


In the current (as of 1_9_0_18 version) linux second life client, there is no way to cut and paste text from say a browser into the client text box Jabador. You would have to type it in manually, which ends up being a real pain for long amounts of text. So that is where this script comes in handy.

Just copy and save the script to a file, maybe like sl_paste.pl,

open up the script with your favorite text editor and towards the beginning of the script set the variables for the window id of the window running second life (by using xwininfo), and where you have the xse executable stored (like maybe /usr/bin/xse ). There are instructions inside the script towards the end telling you how to switch to the us keyboard if you need that.

then do a chmod+x sl_paste.pl to make the script executable.

Then run the script as ./sl_paste.pl from the directory where you have stored the file.

When you run the script, anything you type into the console window where the script is running will get pasted into second life chat. It works very well.

Hope this helps. :)
Foreign Fish
Registered User
Join date: 4 Feb 2006
Posts: 3
08-04-2006 14:35
Very cool script. Will make writing LSL much easier, though still more difficult than it should be (not much more can be done but by Lindens). I made a little change that might be appreciated--to find the Second Life Window interactively. Probably could be done better with a single regexp, but I don't know regexps very well.

my $id = `xwininfo -wm | grep 'Window id'`;
$id =~ s/.* 0/0/;
$id =~ s/ .*//;
chomp $id;
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
08-05-2006 04:09
I couldn't find a version of xse I could actually compile, but seeing this thread has inspired me to write my own version (which I was getting annoyed enough to do anyway). It should compile with any ANSI Standard C++ compiler (though if you're not using g++ you are crazy) and any version of X11. I haven't tested this incredibly thoroughly yet. Try it out and post here with how it is working for you.

One nifty little feature of this program is that--as is--you don't have to go find the handle for the X Window (though it does depend on your keyboard focus and mouse position being independent). You just bring up a terminal window in front of SL, type a command like (WITHOUT HITTING ENTER!):
CODE
cat myScript.lsl | sltyper

Then you put your mouse cursor over SL window (without giving SL keyboard focus) and hit enter to run the command in your shell. Viola! BTW, this program is pretty fast as it doesn't haved to delay between keypresses at all; it just TELLS SL there was a delay. (Wrong! See below.)

I didn't remove leading whitespace. You can do that easily enough with a filter like 'sed' (and a shell script is your friend if you don't want to type it every time):
CODE
cat myScript.lsl | sed -r 's/^[[:space:]]*//' | sltyper

Also it only handles printable ASCII characters at the moment. Sorry! :-)

So without further ado, here is the code: (NOTE: Broken. See post below.)
CODE
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

#include <iostream>
#include <map>

long KEY_EVENT_MASK = KeyPressMask | KeyReleaseMask;

Display* display = 0;
KeyCode lShiftKeycode;

Window rootWindow;
Window targetWindow;
int rootPointerX;
int rootPointerY;
int pointerX;
int pointerY;

void openDisplay(void)
{
display = XOpenDisplay(0);
rootWindow = XDefaultRootWindow(display);

lShiftKeycode = XKeysymToKeycode(display, XK_Shift_L);
}

XKeyEvent defaultKeyEvent(void)
{
XKeyEvent event;

event.window = targetWindow;
event.root = rootWindow;
event.subwindow = targetWindow;
event.time = CurrentTime;
event.x = 0;
event.y = 0;
event.x_root = 0;
event.y_root = 0;
event.same_screen = False;

return event;
}

void findPointerWindow(void)
{
Window childWindow;
unsigned int modifierMask;

childWindow = rootWindow;
do
{
targetWindow = childWindow;

if (!XQueryPointer(display, targetWindow,
&rootWindow, &childWindow,
&rootPointerX, &rootPointerY,
&pointerX, &pointerY,
&modifierMask))
{
std::cerr << "Couldn't locate pointer window. Exiting." << std::endl;
std::exit(-1);
}
} while (childWindow != None);

if (targetWindow == rootWindow)
{
std::cerr << "Pointer is in root window. Exiting." << std::endl;
std::exit(-1);
}
}

void closeDisplay(void)
{
XCloseDisplay(display);
display = 0;
}

void sendKeyEvent(XKeyEvent* keyEvent)
{
static long timeDelay_ms = 0;

// It seems we don't actually need a delay, even for repeated characters.
// We just need to TELL SL there was a delay!
keyEvent->time += (timeDelay_ms += HOLD_TIME__MS);

XSendEvent(display, targetWindow, True, KEY_EVENT_MASK, (XEvent*)keyEvent);
}

void sendShiftEvent(bool shiftDown)
{
XKeyEvent shiftKeyEvent = defaultKeyEvent();

shiftKeyEvent.type = (shiftDown) ? KeyPress : KeyRelease;
shiftKeyEvent.window = targetWindow;
shiftKeyEvent.state = (shiftDown) ? 0 : ShiftMask;
shiftKeyEvent.keycode = lShiftKeycode;

sendKeyEvent(&shiftKeyEvent);
}

void sendKeyStroke(KeyCode keyCode, bool shiftDown)
{
static bool wasShiftDown = false;

if (shiftDown != wasShiftDown)
{
sendShiftEvent(shiftDown);
wasShiftDown = shiftDown;
}

XKeyEvent mainKeyEvent = defaultKeyEvent();

mainKeyEvent.state = (shiftDown) ? ShiftMask : 0;
mainKeyEvent.keycode = keyCode;

mainKeyEvent.type = KeyPress;
sendKeyEvent(&mainKeyEvent);

mainKeyEvent.type = KeyRelease;
sendKeyEvent(&mainKeyEvent);
}

void sendKeysym(KeySym keysym)
{
KeyCode keycode = XKeysymToKeycode(display, keysym);

KeySym lowerKeysym;
KeySym upperKeysym;
XConvertCase(keysym, &lowerKeysym, &upperKeysym);

bool needShift = (keysym != XKeycodeToKeysym(display, keycode, 0)) ||
(keysym != lowerKeysym);

sendKeyStroke(keycode, needShift);
}

void sendChar(char ch)
{
KeySym keysym;

if (!isascii(ch))
{
return;
}

switch (ch)
{
case '\n':
keysym = XK_Return;
break;

case '\r':
return;

case '\t':
keysym = XK_space;
break;

case '\v':
return;

default:
if (!isprint(ch))
{
return;
}
keysym = ch;
break;
}

sendKeysym(keysym);
}

int main(int argc, char** argv)
{
openDisplay();
findPointerWindow();

char ch;
while (std::cin.get(ch))
{
sendChar(ch);
}

closeDisplay();

return 0;
}

Don't forget to place your mouse cursor over SL! Otherwise it will silently do nothing (at least, most terminals are set to ignore events sent bye 'XSendEvent()' for security, so PROBABLY nothing will happen...).
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
08-05-2006 04:42
Erg! I tested all characters, but not large scripts. A delay WAS necessary after all. I guess X events were stacking up too much. Here's the new version:
CODE
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

#include <time.h>

#include <iostream>
#include <map>

long HOLD_TIME__MS = 5;

long KEY_EVENT_MASK = KeyPressMask | KeyReleaseMask;

Display* display = 0;
KeyCode lShiftKeycode;

Window rootWindow;
Window targetWindow;
int rootPointerX;
int rootPointerY;
int pointerX;
int pointerY;

void msleep(int time_ms)
{
struct timespec sleepTime =
{time_ms / 1000,
(long)(time_ms % 1000) * 1000000};
while (nanosleep(&sleepTime, &sleepTime) < 0)
{}
}

void openDisplay(void)
{
display = XOpenDisplay(0);
rootWindow = XDefaultRootWindow(display);

lShiftKeycode = XKeysymToKeycode(display, XK_Shift_L);
}

XKeyEvent defaultKeyEvent(void)
{
XKeyEvent event;

event.window = targetWindow;
event.root = rootWindow;
event.subwindow = targetWindow;
event.time = CurrentTime;
event.x = 0;
event.y = 0;
event.x_root = 0;
event.y_root = 0;
event.same_screen = False;

return event;
}

void findPointerWindow(void)
{
Window childWindow;
unsigned int modifierMask;

childWindow = rootWindow;
do
{
targetWindow = childWindow;

if (!XQueryPointer(display, targetWindow,
&rootWindow, &childWindow,
&rootPointerX, &rootPointerY,
&pointerX, &pointerY,
&modifierMask))
{
std::cerr << "Couldn't locate pointer window. Exiting." << std::endl;
std::exit(-1);
}
} while (childWindow != None);

if (targetWindow == rootWindow)
{
std::cerr << "Pointer is in root window. Exiting." << std::endl;
std::exit(-1);
}
}

void closeDisplay(void)
{
XCloseDisplay(display);
display = 0;
}

void sendKeyEvent(XKeyEvent* keyEvent)
{
XSendEvent(display, targetWindow, True, KEY_EVENT_MASK, (XEvent*)keyEvent);
}

void sendShiftEvent(bool shiftDown)
{
XKeyEvent shiftKeyEvent = defaultKeyEvent();

shiftKeyEvent.type = (shiftDown) ? KeyPress : KeyRelease;
shiftKeyEvent.window = targetWindow;
shiftKeyEvent.state = (shiftDown) ? 0 : ShiftMask;
shiftKeyEvent.keycode = lShiftKeycode;

sendKeyEvent(&shiftKeyEvent);
}

void sendKeyStroke(KeyCode keyCode, bool shiftDown)
{
static bool wasShiftDown = false;

if (shiftDown != wasShiftDown)
{
sendShiftEvent(shiftDown);
wasShiftDown = shiftDown;
}

XKeyEvent mainKeyEvent = defaultKeyEvent();

mainKeyEvent.state = (shiftDown) ? ShiftMask : 0;
mainKeyEvent.keycode = keyCode;

mainKeyEvent.type = KeyPress;
sendKeyEvent(&mainKeyEvent);

mainKeyEvent.type = KeyRelease;
sendKeyEvent(&mainKeyEvent);

XSync(display, False);
msleep(HOLD_TIME__MS);
}

void sendKeysym(KeySym keysym)
{
KeyCode keycode = XKeysymToKeycode(display, keysym);

KeySym lowerKeysym;
KeySym upperKeysym;
XConvertCase(keysym, &lowerKeysym, &upperKeysym);

bool needShift = (keysym != XKeycodeToKeysym(display, keycode, 0)) ||
(keysym != lowerKeysym);

sendKeyStroke(keycode, needShift);
}

void sendChar(char ch)
{
KeySym keysym;

if (!isascii(ch))
{
return;
}

switch (ch)
{
case '\n':
keysym = XK_Return;
break;

case '\r':
return;

case '\t':
keysym = XK_space;
break;

case '\v':
return;

default:
if (!isprint(ch))
{
return;
}
keysym = ch;
break;
}

sendKeysym(keysym);
}

int main(int argc, char** argv)
{
openDisplay();
findPointerWindow();

char ch;
while (std::cin.get(ch))
{
sendChar(ch);
}

closeDisplay();

return 0;
}
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
08-05-2006 04:55
BTW, to compile the above a command such as the following should work on most distributions (assuming you named the file sltyper.C and it is in the current working directory):
CODE
g++ -o sltyper sltyper.C -lX11
Llauren Mandelbrot
Twenty-Four Weeks Old.
Join date: 26 Apr 2006
Posts: 665
Where can I get this?
08-05-2006 10:07
Way cool! Where can I get a binary of this? I`m not prepared to compile my own sources. [Heck, I don`t even know if I have a compiler installed.:o]
Michael Balboa
Registered User
Join date: 4 Aug 2006
Posts: 2
08-05-2006 17:13
From: Orren Walcott
Ah, many thanks! This helped me write a tiny bash script to keep SL from logging off after 30 minutes:

#!/bin/bash
while true; do
xse -window 0x2c0000e '<MotionNotify> Normal'
sleep 600
done

Basically just an infinite loop that sends a mouse motion event every 10 minutes. Run it in the background and end it with killall; I'm too lazy to put any kind of control on it.


Thanks to you too Oren.
Bash script works a treat...I can now earn some money while sleeping.

Much appreciated

Michael
Michael Balboa
Registered User
Join date: 4 Aug 2006
Posts: 2
08-05-2006 17:20
From: Zi Ree
Hi Linux group!

I hacked a perl script that sends x-events to the Second Life client, so I can write my LSL scripts in my favorite editor and paste them into SL. It's still very ugly, but at least it's a start. Copy is not possible this way, but maybe someone finds this script useful. German and english/US keymap support is already implemented. Other layouts can be added.

You will need xse to use the script. Get it from ftp://ftp.uni-magdeburg.de/pub/mirror/hpux.ask.uni-karlsruhe.de/X11/Misc/xse-2.1

Have fun!

CODE

#!/usr/bin/perl -w

# text2xev.pl V0.1 (C)2006 Zi Ree@Second Life
# converter for pasting text into Second Life client window.
# use, copy, modify and spread freely, I hope it wonj't be needed too much longer :)
# have fun!
# -- Zi!

# you need xse installed somewhere
# get it from ftp://ftp.uni-magdeburg.de/pub/mirror/hpux.ask.uni-karlsruhe.de/X11/Misc/xse-2.1

use strict;

# Your Second Life window id (try xwininfo to get it)
my($id)="0x2a0000e";

# path to the xse binary
my($xse)="xse-2.1/xse";

my($line);

# read from stdin
while($line=<>)
{
my($char);
$line =~ s/^ +//; # skip blanks in the front, makes LSL editor behave better

# split line into individual characters
my(@chars)=split //,$line;
my($oldsym)="";

# go through characters
foreach $char (@chars)
{
# convert key to xevent syntax, depending on keyboard layout
my($output,$sym)=char2xev($char);

# pause for a moment if the same key is pressed twice (events get lost otherwise)
if($sym eq $oldsym)
{
select(undef,undef,undef,0.25);
}

# send events via xse to the Second Life client
open(XSE,"| $xse -window $id -file /dev/stdin");
print XSE $output;
close(XSE);

# remember sent key
$oldsym=$sym;
} # foreach
} # while

# ------------------------

sub char2xev
{
my($char)=shift;
if($char eq "\n")
{
$char="LF";
}

# modifier key / states
my(%modifiers)=(
"-" => "",
"s" => "Shift",
"l" => "Lock",
"c" => "Ctrl",
"a" => "Mod1", # untested
"g" => "Mod5" # ALT-GR for german keyboard
);

# select one of the following mappings by calling it "%conv"
# more mappings can be added later

# german keyboard mapping (currently active)
my(%conv)=(
"^" => ["-","dead_circumflex"],
"ß" => ["-","ssharp"],
"´" => ["-","dead_acute"],
"°" => ["s","dead_circumflex"],
"!" => ["s","1"],
"\"" => ["s","2"],
"§" => ["s","3"],
"\$" => ["s","4"],
"%" => ["s","5"],
"&" => ["s","6"],
"/" => ["s","7"],
"(" => ["s","8"],
")" => ["s","9"],
"=" => ["s","0"],
"?" => ["s","ssharp"],
"`" => ["s","dead_acute"],
"¬" => ["g","dead_circumflex"],
"¹" => ["g","1"],
"²" => ["g","2"],
"³" => ["g","3"],
"¼" => ["g","4"],
"½" => ["g","5"],
"¬" => ["g","6"],
"{" => ["g","7"],
"[" => ["g","8"],
"]" => ["g","9"],
"}" => ["g","0"],
"\\" => ["g","ssharp"],
"ü" => ["-","udiaeresis"],
"+" => ["-","plus"],
"\t" => ["-","Tab"],
"Q" => ["s","q"],
"W" => ["s","w"],
"E" => ["s","e"],
"R" => ["s","r"],
"T" => ["s","t"],
"Z" => ["s","z"],
"U" => ["s","u"],
"I" => ["s","i"],
"O" => ["s","o"],
"P" => ["s","p"],
"Ü" => ["s","udiaeresis"],
"*" => ["s","plus"],
"@" => ["g","q"],
"~" => ["g","plus"],
"ö" => ["-","odiaeresis"],
"ä" => ["-","adiaeresis"],
"#" => ["-","numbersign"],
"A" => ["s","a"],
"S" => ["s","s"],
"D" => ["s","d"],
"F" => ["s","f"],
"G" => ["s","g"],
"H" => ["s","h"],
"J" => ["s","j"],
"K" => ["s","k"],
"L" => ["s","l"],
"Ö" => ["s","odiaeresis"],
"Ä" => ["s","adiaeresis"],
"'" => ["s","numbersign"],
"<" => ["-","less"],
"," => ["-","comma"],
"." => ["-","period"],
"-" => ["-","minus"],
">" => ["s","less"],
"Y" => ["s","y"],
"X" => ["s","x"],
"C" => ["s","c"],
"V" => ["s","v"],
"B" => ["s","b"],
"N" => ["s","n"],
"M" => ["s","m"],
";" => ["s","comma"],
":" => ["s","period"],
"_" => ["s","minus"],
"|" => ["g","less"],
"µ" => ["g","m"],
"·" => ["g","period"],
" " => ["-","space"],
"LF" => ["-","Return"],
);

# english (EN or US) keyboard mapping (partly untested)
my(%conv_us)=(
"`" => ["-","grave"],
"-" => ["-","minus"],
"=" => ["-","equal"],
"~" => ["s","grave"],
"!" => ["s","1"],
"@" => ["s","2"],
"#" => ["s","3"],
"\$" => ["s","4"],
"%" => ["s","5"],
"^" => ["s","6"],
"&" => ["s","7"],
"*" => ["s","8"],
"(" => ["s","9"],
")" => ["s","0"],
"_" => ["s","minus"],
"+" => ["s","equal"],
"\t" => ["-","Tab"],
"[" => ["-","braceleft"],
"]" => ["-","braceright"],
"Q" => ["s","q"],
"W" => ["s","w"],
"E" => ["s","e"],
"R" => ["s","r"],
"T" => ["s","t"],
"Y" => ["s","y"],
"U" => ["s","u"],
"I" => ["s","i"],
"O" => ["s","o"],
"P" => ["s","p"],
"{" => ["s","braceleft"],
"}" => ["s","braceright"],
";" => ["-","semicolon"],
"'" => ["-","apostrophe"],
"\\" => ["-","backslash"],
"A" => ["s","a"],
"S" => ["s","s"],
"D" => ["s","d"],
"F" => ["s","f"],
"G" => ["s","g"],
"H" => ["s","h"],
"J" => ["s","j"],
"K" => ["s","k"],
"L" => ["s","l"],
":" => ["s","semicolon"],
"\"" => ["s","apostrophe"],
"|" => ["s","backslash"],
"," => ["-","comma"],
"." => ["-","period"],
"/" => ["-","slash"],
"Z" => ["s","z"],
"X" => ["s","x"],
"C" => ["s","c"],
"V" => ["s","v"],
"B" => ["s","b"],
"N" => ["s","n"],
"M" => ["s","m"],
"<" => ["s","comma"],
">" => ["s","period"],
"?" => ["s","slash"],
" " => ["-","space"],
"LF" => ["-","Return"],
);
# if key is on convert list
if(defined($conv{$char}))
{
my($out)="";

# get event definition
my($def)=$conv{$char};

# build xse string
$out=$modifiers{@$def[0]}."<Key>".@$def[1]."\n".$modifiers{@$def[0]}."<KeyUp>".@$def[1]."\n";
return ($out,@$def[1]);
}
else
{
# standard letter / digit, just return xse string
return ("<Key>$char\n<KeyUp>$char\n",$char);
}
}


Zi,

Great stuff...just want to say thanks...works a charm!
I had a little fun getting xse to compile, but it worked eventually..:)

thanks again

Michael
Davorak Black
Registered User
Join date: 12 Apr 2005
Posts: 3
Bash scripting wth a pinch of python
08-09-2006 11:56
After reading the thread I thought to myself there is a perl implementation
a C++ implementation it would be nice to have a python implementation.

After a little research I discovered Xlib was apparently the library to use to
interface python and the X11. My lack of understanding of X11 and the fact that I could not google, krugle, koder a good example, and general laziness prevented
anything from happening on The Xlib python front.

Instead of a python Xlib implementation I give some command line shenanigans with and optional python wrapper.

Scripting is not my forte so improvements may be need and are welcomed.

Needed utilities xte, xwit(or wmctrl) xte is part of the xautomation deb package

xnee could possible replace xte though I could not get it to type all characters
correctly.

On the command line.
CODE

xwit -focus -select; xte "str $(cat <file>)"

This command will prompt the user to click the window they want the automation to
run on.

To work on a specific window id
CODE

xwit -focus -id <winid>; xte "str $(cat <file>)"


I did not want to write that all out each time I ran the script though so..
In python
CODE

import sys
import os

args = sys.argv
if len(args)==1:
print "send.py [file] [xwit options:default='-select']"
sys.exit()

file = open(sys.argv[1]).read()

xwitcommands = ' '.join(sys.argv[2:])
if xwitcommands is '':
xwitcommands = '-select'

command = r'xwit -focus ' + xwitcommands + '; xte "str ' + file + '"'

os.popen(command)


And in bash:
CODE

#!/bin/bash

if [ $# -eq 0 ]; then
echo 'send [file] [xwit options:default='-select']'
fi

if [ $# -eq 1 ]; then
xwitcommands="-select"
else
xwitcommands=${@:2}
fi

echo $xwitcommands

xwit -focus $xwitcommands; xte "str $(cat $1)"


These scripts take the file name first and then options for xwit. The default
behavior is to prompt the user to select what window to run on.

I have not done it yet but I am sure that xte, xwit could be used to script other sl
events maybe an automatic import of a directory filled with scripts.

Best regards,

pjw

Edit: The above code only works on very short files. Here is a better version:
CODE

import sys
import os
import time

if len(sys.argv)==1:
print "send.py [file] [xwit options:default='-select']"
sys.exit()

file = open(sys.argv[1])

xwitoptions = ' '.join(sys.argv[2:])
if xwitoptions is '':
xwitoptions = '-select'

# Making wxit command for window selection
xwitcommand = r'xwit -focus ' + xwitoptions

charmaping = {'\n':'Return'}

input = file.read()
mappedinput = [charmaping.get(c, c) for c in input]
xteinput = ['"key ' + c + '"' for c in mappedinput]
xtecommand = 'xte ' + ' "usleep 5000" '.join(xteinput)
command = xwitcommand + ' ; ' + xtecommand
os.popen(xwitcommand)
time.sleep(.2)
os.popen(xtecommand)
tiller Gilman
Registered User
Join date: 22 Jul 2004
Posts: 200
Wow
08-20-2006 06:42
This stuff is fntastic what is it,lol. :eek: .waits quietly for a lamer version. :)
Issarlk Chatnoir
Cross L. apologist.
Join date: 3 Oct 2004
Posts: 424
08-31-2006 04:38
From: Hewee Zetkin
Don't forget to place your mouse cursor over SL! Otherwise it will silently do nothing (at least, most terminals are set to ignore events sent bye 'XSendEvent()' for security, so PROBABLY nothing will happen...).


It works great. Thanks.
_____________________
Vincit omnia Chaos
From: Flugelhorn McHenry
Anyway, ignore me, just listen to the cow
1 2