[SOLVED] How to simulate a PrintScreen keypress in a shell script?
SlackwareThis Forum is for the discussion of Slackware Linux.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
How to simulate a PrintScreen keypress in a shell script?
I want to include in ~/.xinitrc a command that simulates a Print Screen keypress, to avoid doing it manually before typing startx (I need that to mute espeakup, a text to speech program, else I would hear what's displayed on the tty even in a graphical environment).
But what command? showkey tells me that the keycode is 99.
Under X I could use xdotool for instance, but I need to do that in text mode.
Also, espeakup is a daemon that has to be started by root, so a regular user is not allowed to stop it.
An internet search didn't give me any clue.
Last edited by Didier Spaier; 10-16-2017 at 08:08 AM.
On linux the Magic SysRq Key might make fooling with the [SysRq + PrtSc] Key a little scary.
There does seem to be a sysctl to turn off the Magic SysRq Key( kernel.sysrq=0 ).
However, `showkey -a` gives me nothing when I press [PrtSc].
Maybe one of the 'standard' ANSI Escape Sequences for PrintScreen ( Esc[i or ... ) from the bottom of ANSI Escape Sequences will work for your startup script ?
If so, I've done this sort of thing in scripts:
Code:
PrtSc="$(echo -ne "\033[i")"
echo -n "$PrtSc"
HTH.
EDIT: to send the keystroke back to the app, you'll need something like expect or a small C-Program to simulate the keystroke ( once you find the key ).
EDIT: there is a small C-Program Here: https://unix.stackexchange.com/quest...a-shell-script
One possibility might be using the uinput module. See /usr/src/linux/Documentation/input/uinput.rst
I'm a little surprised to find that you'd need to inject keypresses in order to toggle screen reading. One would think that espeakup would provide a control mechanism for that somehow.
I'm a little surprised to find that you'd need to inject keypresses in order to toggle screen reading. One would think that espeakup would provide a control mechanism for that somehow.
Can't you just "echo 1 >/speakup/silent" ? I'm just going by the sketchy documentation in spkguide.txt, which just says, "Most of the names are self explanatory," for the contents of the /speakup directory.
Thanks for responding khjambrick, GazL, and rnichols
Quote:
Originally Posted by kjhambrick
EDIT: to send the keystroke back to the app, you'll need something like expect or a small C-Program to simulate the keystroke ( once you find the key ).
EDIT: there is a small C-Program Here: https://unix.stackexchange.com/quest...a-shell-script
Yes I saw this. But I'd prefer a shell command if at all possible.
Quote:
Originally Posted by GazL
One possibility might be using the uinput module. See /usr/src/linux/Documentation/input/uinput.rst
Yes that is also suggested in the post linked to by khjambrick, but I have the same objection.
Quote:
I'm a little surprised to find that you'd need to inject keypresses in order to toggle screen reading.
One would think that espeakup would provide a control mechanism for that somehow.
Well I don't need to inject a keypress, the user can just press the key. But that's boring to have to do that every time before typing startx.
On a technical note, actually two pieces of software come into play here:
The speakup Linux driver, cf. /usr/src/linux/staging /speakup
The synthesizer. In Slint we use the software synthesizer espeak.
speakup comunicates with userland through a sys interface whose root is /sys/accessibility/speakup and with the soft synthesizer through /sys/accessibility/speakup/soft.The files in /sys/accessibility/speakup/soft are 666 so I can e.g. minimize the volume with "echo 0 > /sys/accessibility/speakup/soft" but it is not completely muted.
My assumption is that I should echo a value to some file in /speakup as just suggested by rnichols, but they are all writable only by root.
I could have a look in the code to see how Print Screen is handled as after all the key press is done by a regular user.If only I was able to read C code...
I could end up requesting help from Samuel Thibault, one of the writers of spkguide.txt (also found in /usr/src/linux/drivers/staging /speakup).
Last edited by Didier Spaier; 10-16-2017 at 02:01 PM.
Thanks for responding khjambrick, GazL, and rnichols
You're welcome, Didier Spaier.
I build and installed the portaudio and espeak SBo Packages for Slackware64 14.2 ... espeak is kinda kool ...
Takes some getting used to the 'accent' but I can understand most of the text when I run:
Code:
# man espeak |espeak -a 20 -v en-us+f4
Quote:
Originally Posted by Didier Spaier
On a technical note, actually two pieces of software come into play here:
The speakup Linux driver, cf. /usr/src/linux/staging /speakup
The synthesizer. In Slint we use the software synthesizer espeak.
speakup comunicates with userland through a sys interface whose root is /sys/accessibility/speakup and with the soft synthesizer through /sys/accessibility/speakup/soft.The files in /sys/accessibility/speakup/soft are 666 so I can e.g. minimize the volume with "echo 0 > /sys/accessibility/speakup/soft" but it is not completely muted.
My assumption is that I should echo a value to some file in /speakup as just suggested by rnichols, but they are all writable only by root.
Looking at The Speakup User's Guide, it looks like /speakup is a symlink to the /sys/accessibility/speakup/ directory ?
Code:
5. The Speakup Sys System
The Speakup screen reader also creates a speakup subdirectory as a part
of the sys system.
As a convenience, run as root
ln -s /sys/accessibility/speakup /speakup
to directly access speakup parameters from /speakup.
You can see these entries by typing the command:
ls -1 /speakup/*
Q1: Did you create the symlink ?
Q2: Instead of `ls -1 /speakup/*` what if you type:
Code:
ls -lad $(find /speakup -type f)
Q3: Are ALL the files under your /speakup/ directory writable only by root ?
I ask because further down in the The Speakup User's Guide, it says:
Code:
Looking at entries in the Speakup sys system can be useful in many
ways. For example, you might wish to know what level your volume is set
at. You could type:
cat /speakup/KWD/vol
# Replace KWD with the keyword for your synthesizer, E.G., ltlk for LiteTalk.
5
The number five which comes back is the level at which the synthesizer
volume is set at.
Q4: If the /speakup/soft/vol file is world-writable, What happens if you type as 'yourself' ?
Code:
echo 0 > /speakup/soft/vol
HTH ...
-- kjh
Last edited by kjhambrick; 10-16-2017 at 03:53 PM.
Reason: ls-lad -> ls -lad
The modified version below compiles and I can inject a KEY_SYSRQ ( aka [PrtSc] = ScanKey 99 ) into the Keyboard Buffer but only as root and I can't say I've got a handle on what I am doing ( yet )
When I execute ./inject-sysrq as in a KDE Konsole as root, I get the ksnapshot Dialog as defined in [System Settings]->[Shortcuts and Gestures]->[Custom Shortcuts]->[Preset Actions]->[PrintScreen].
And as a BIG bonus, it doesn't crash my system
But if I had to inject a keystroke, I would be more inclined go with a small `expect` script, myself.
Sorry about wasting your time ...
-- kjh
This code will run as root and it does inject a KEY_SYSRQ ( aka [PrtSc] KeyPress ) into the Keyboard buffer.
See: /usr/include/linux/input-event-codes.h for a list of all the KEY_* ScanCodes.
Code:
/* inject-sysrq.c
*
* copied from https://www.kernel.org/doc/html/v4.12/input/uinput.html and modified a tad by kjh
*
* compile: gcc -o inject-sysrq inject-sysrq.c
* execute: ./inject-sysrq # only runs as root !
/*
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <linux/uinput.h>
void emit( int fd, int type, int code, int val )
{
struct input_event ie;
ie.type = type;
ie.code = code;
ie.value = val;
/* timestamp values below are ignored */
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
write( fd, &ie, sizeof( ie ));
}
int main( void )
{
struct uinput_user_dev uud;
int version, rc, fd;
if (( fd = open( "/dev/uinput", O_WRONLY | O_NONBLOCK) ) < 0 )
{
fprintf( stderr, "Unable to open /dev/uinput - errno = %d - %s\n", errno, strerror( errno ));
return( 1 );
}
// EDIT: 2017-10-17 09:03 AM. Reason: handle ioctl UI_GET_VERSION errors
if (( rc = ioctl(fd, UI_GET_VERSION, &version)) != 0 )
{
fprintf( stderr, "ioctl( fd = %d, UI_GET_VERSION ) error = %d - %s\n", fd, errno, strerror( errno ));
return( 2 ) ;
}
// fprintf( stderr, "ioctl( fd = %d, UI_GET_VERSION ) = version %d\n", fd, version );
if ( version >= 5 )
{
/* use UI_DEV_SETUP */
fprintf( stderr, "ioctl wrong version = %d - %s\n", version );
return( 3 );
}
/*
* The ioctls below will enable the device that is about to be
* created, to pass key events, in this case the space key.
*/
ioctl( fd, UI_SET_EVBIT, EV_KEY );
ioctl( fd, UI_SET_KEYBIT, KEY_SYSRQ );
memset( &uud, 0, sizeof( uud ));
snprintf( uud.name, UINPUT_MAX_NAME_SIZE, "uinput old interface" );
write( fd, &uud, sizeof( uud ));
ioctl(fd, UI_DEV_CREATE);
/*
* On UI_DEV_CREATE the kernel will create the device node for this
* device. We are inserting a pause here so that userspace has time
* to detect, initialize the new device, and can start listening to
* the event, otherwise it will not notice the event we are about
* to send. This pause is only needed in our example code!
*/
//
// kjh pounded but I get no key injection when I do ...
sleep(1);
// kjh pounded
//
/* Key press, report the event, send key release, and report again */
emit( fd, EV_KEY, KEY_SYSRQ, 1 );
emit( fd, EV_SYN, SYN_REPORT, 0 );
emit( fd, EV_KEY, KEY_SYSRQ, 0 );
emit( fd, EV_SYN, SYN_REPORT, 0 );
/*
* Give userspace some time to read the events before we destroy the
* device with UI_DEV_DESTOY.
*/
//
// kjh pounded -- this does not seem to be necessary ...
// sleep(1);
// kjh pounded
//
ioctl( fd, UI_DEV_DESTROY );
close(fd);
return 0;
}
Last edited by kjhambrick; 10-17-2017 at 09:05 AM.
Reason: handle ioctl UI_GET_VERSION errors
I ended up installing python-uinput and writing this script:
Code:
import uinput
def main():
events = (
uinput.KEY_SYSRQ,
)
with uinput.Device(events) as device:
device.emit_click(uinput.KEY_SYSRQ)
if __name__ == "__main__":
main()
The name KEY_SYSRQ corresponds to the key code 99 as shown in this file, and the PrintScreen key has the code 99, as says showkey.
To use this as regular user and out as laziness, I modified this udev rule so that the mode be 0666. I should have created a group uinput instead and put myself in it.
I mark this thread as SOLVED although I now realize that it was bad idea from the beginning as if speakup was already stopped that will restart it. Oh, well...
Anyway, thanks all, at least I have learned a few things in the process.
Last edited by Didier Spaier; 10-24-2017 at 12:26 PM.
I certainly like the idea of using a python pip A LOT more than a C-Program -- especially since the C-Structures and the interface for uinput have changed since Kernel 4.4.x.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.