I need a way to detect mouse/keyboard activity on Linux. Something similar to what any IM program would do. If no activity is detected for, say 5 minutes, it will set your IM status to "I'm not here right now".
Any help towards this is appreciated.
Thanks.
Or simply use the command xprintidle which returns the idle time in milliseconds.
It has been packaged for debian based systems. (the source is not available any more on the original site dtek.chalmers.se/~henoch but you can get it at packages.ubuntu.com)
more info on freshmeat.net
Complete c solution : (cut & paste the whole code in a terminal)
cat>/tmp/idletime.c<<EOF
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/scrnsaver.h>
int GetIdleTime () {
time_t idle_time;
static XScreenSaverInfo *mit_info;
Display *display;
int screen;
mit_info = XScreenSaverAllocInfo();
if((display=XOpenDisplay(NULL)) == NULL) { return(-1); }
screen = DefaultScreen(display);
XScreenSaverQueryInfo(display, RootWindow(display,screen), mit_info);
idle_time = (mit_info->idle) / 1000;
XFree(mit_info);
XCloseDisplay(display);
return idle_time;
}
int main() {
printf("%d\n", GetIdleTime());
return 0;
}
EOF
gcc -Wall /tmp/idletime.c -o /tmp/idletime -L/usr/X11R6/lib/ -lX11 -lXext -lXss
DISPLAY=:0 /tmp/idletime
(the main part is coming from X11::IdleTime perl module)
My aproach is to use ad-hoc perl module :
# cpan -i X11::IdleTime; sleep 2; perl -MX11::IdleTime -e 'print GetIdleTime(), $/;'
Don't poll when there's better methods available.
You don't specify the environment, but since you mention the mouse, I'm going to assume modern X11.
xidle uses the MIT-SCREEN-SAVER extension to determine whether the user is idle or not -- you can use xidle directly, or read its source code to learn how to use the XScreenSaver(3) yourself.
Edit
man 3 XScreenSaver -- just use the idle-reporting/notification portions of it, since there is no more XIDLE extension since X11R6.
This is an example how to check that an user is idle for 5 minutes using xprintidle and shell script:
#!/bin/sh
idletime=$(xprintidle)
threshold=300000 # 5 min = 5 * 60 * 1000 ms
if [ "$idletime" -gt "$threshold" ]; then
echo "idle"
fi
xprintidle returns time in milliseconds.
This script does not do any polling or the like. It only executes some code if user is idle and does nothing otherwise.
Try executing who -u -H at the command line. It will tell you who's logged in and how long they've been idle. At least users logged in to a terminal; I don't think it works at all in X. Anyhow, with this information you can tell who's idle or not and take actions appropriately.
If you're in X you could create a script to run as a screen saver or something like that.
I wrote the wait-while-idle.rb which does the "detecting keyboard, mouse activity in linux" but the other way around — wait until the user's come back.
Yes, sure — it's polling, but I doubt anyone requires performance here.
Planning to catch pranksters sneaking up on my computer with it and a little scripting.
Related
I would like to run a command line program again and again inside an infinite loop.
The program will occasionally output different data.
Whenever the new data is output, I would like the previous data to be overwritten.
Example:
The following program will output the time of day.
#include <stdio.h>
#include <time.h>
int main (){
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
printf ( "Current local time and date: %s", asctime (timeinfo) );
}
The naive approach would be the following:
while true; do ./main; clear; done
Of course, this will clear the screen every run, and cause a flicker.
I could certainly pipe it into a custom program that only refreshes output on change,
but I was hoping to find a solution using standard linux commands
(or Bash language features).
The program output could be multi-line, so returning(/r) and re-writting is not an option.
If you have the command watch available, you could use that. Simply type
watch ls
This ought to do it:
while true; do LINE=$(date) | echo -en "\r$LINE"; done
Replace date with the program of interest, but it makes a cool demo.
Using a pipe in this way prevents the clearing from taking place until there is new output to print, and makes clearing and printing new output happen in one step.
Caveat: This won't clear correctly if something prints more than one line.
On the other hand, it doesn't nuke your entire terminal screen like watch or clear does.
We have a Linux device which has a speaker and MIC devices. These devices are shared among different modules - example a VOIP call can use speaker, a hazard Warning system can use speaker, a Voice prompt can use a speaker etc:
There seems to be a function in ALSA which uses pcm to provide the status.
int snd_pcm_status (snd_pcm_t * pcm, snd_pcm_status_t * status)
However the *pcm is returned by snd_pcm_open. We do not want to open the device as we would like to know the status of the device using its "name"
Alsa API is here
How can we check if a resource/device is busy without opening it and using its name?
The same information for playback stream X of device Y on card Z is available in the file /proc/asound/cardZ/pcmYp/subX/status; when the device is not open, it just says "closed".
Please note that you cannot use this information to decide if you can open the device, because some other process could have openend it just after you've read this information. The only way to check if you can open it is to actually try.
Though it requires /dev/dsp, this seems to work:
#!/bin/dash
## If the speaker is not used by any, returns 0, and prints "free"
## Otherwise, returns 1 and prints "not free"
iExit (){
trap '' 0
exit $1
}
iCatch (){
# The speaker is already in use
echo not free
iExit 1
}
trap iCatch 0
{
exec 3>&1 1>/dev/dsp
# If the execution reaches here, the speaker is not used by any
# Otherwise, it's catched by iCatch
exec 1>&3
echo free
iExit 0
} 2>/dev/null
Without PulseAudio, it seems on some PC only one output is accepted at one time; on others simultaneous playbacks are allowed. But even in the latter case, the above code works.
NB: The above code does not work with bash; for bash, simply use if/else rather than trap.
NB 2: /dev/dsp may be lacking depending on the kernel configuration.
I'm using a serial device for a project, and what I'm trying to accomplish PC side, is listening for a command sent by the serial device, interpreting the query, running some code depending on the query, and transmitting back the result.
To be honest I tried out using PHP as the listener, and it works, unfortunately the infinite loop required to make the script act as a receiver, loads the CPU to 25%. So it's not really the best option.
I'm using cygwin right now, I'd like to create a bash script using linux native commands.
I can receive data by using:
cat /dev/ttyS2
And send a response with:
echo "command to send" > /dev/ttyS2
My question is, how do I make an automated listener to be able to receive and send data? The main issue I have, is actually how do I stop the cat /dev/ttyS2 command once information was received, put it into a variable which then I could compare with a switch, or a series of if else then blocks. Afterwards send back a response and start the cycle all over again?
Thanks
Is this not what you're looking for?
while read -r line < /dev/ttyS2; do
# $line is the line read, do something with it
# which produces $result
echo $result > /dev/ttyS2
done
It's possible that reopening the serial device on every line has some side-effect, in which case you could try:
while read -r line; do
# $line is the line read, do something with it
# which produces $result
echo $result > /dev/ttyS2
done < /dev/ttyS2
You could also move the output redirection, but I suspect you will have to turn off stdout buffering.
To remain fairly system independent, use a cross platform programming language: like Python, use a cross platform serial library like : pySerial and do the processing inside a script. I have used pySerial and I could run the script cross platform with almost no changes in source code. By using BASH you're limiting yourself a fair little.
If you use right tools, it is possible to actually have your CPU usage to be exactly 0 when your device does not have any output.
To accomplish this, you should use some higher level language (Perl, Python, C/C++ would do, but not bash) and use select loop on top of file handle of your serial device. This is an example for Perl http://perldoc.perl.org/IO/Select.html, but you can use any other language as long as it has support for select() syscall.
I would recommend to use C/C++ with Qt 5.1.1, it's really easy and if you are familiar with the framework it'll be a piece of cake!!!
Here you can find more information and here more helpful examples, give it a try,
it's really pain free!! Also you can develop on win and then port your code to linux...straight forward.
Declare an object like this:
QSerialPort mPort; //remember to #include <QtSerialPort/QSerialPort>
//also add QT += serialport to your .pro file
Then add this code:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setupUi(this);
connect(this->pushButton,SIGNAL(clicked()),this,SLOT(sendData()));
mPort.setPortName("ttyS0");
mPort.setBaudRate(QSerialPort::Baud115200);
mPort.setParity(QSerialPort::EvenParity);
if(!mPort.open(QSerialPort::ReadWrite))
{
this->label->setText(tr("unable to open port, %1").arg(mPort.error()));
}
connect(&(this->mPort),SIGNAL(readyRead()),this,SLOT(readData()));
}
void MainWindow::sendData()
{
QByteArray data = lineEdit->text().toLatin1();
if(mPort.isOpen())
{
mPort.write(data);
}
else
{
this->label->setText(tr("port closed %1").arg( mPort.error()));
}
}
void MainWindow::readData()
{
QString newData;
int bread=0;
while(bread < mPort.bytesAvailable() ){
newData += mPort.readAll();
bread++;
}
this->textEdit->insertPlainText("\n" + newData);
}
How to listen to the spoken DTMD digit every time the sound card capture one?
The objective is radio controlling my pc and interfaces activities dialing dtmf tones via a hand-held transceiver.
I used multimon to hear DTMF tones
I tried to use awk to filter digits and proceed accordingly.
For example, if I key "0" from the radio the system must reboot, etc, but first confirming the operation. " The computer will reboot, send # to confirm"...
I tried to use espeak for a voice confirmation to the remote radio.
The radio connected to the pc soundcard receives the commands and transmits the responses.
I do not simply know how to nest multimon within awk within espeak.
Multimon itself doesnt let me do anything with its stdout because its running ( do not terminate after hearing a digit, which is indeed right).
It would be extremely helpful if I knew how to just speak each digit, without exiting the natural multimon loop.
Say, multimon -a DTMF | awk'{print}' espeak -stdin
If this simply worked!
Is it possible to do? Any help wellcome.
3 years passed and still no advance in linux DTMF decoding.
Once I didnt see any DTMF Radio Controlling project in Linux, I plan to publish this shall I can solve this issue.
Thanks / Mario/ sao paulo brazil
I believe that my answer is out of date and perhaps you have found how to solve this.
I faced the same issue and figured out that the problem is in multimon. When you pipe the stdout from multimon to another program, multimon does not flush the verbose output properly.
Try to patch and recompile multimon, adding a "fflush(stdout);", like this:
(unixinput.c , around line 71 )
void verbprintf(int verb_level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (verb_level <= verbose_level) {
vfprintf(stdout, fmt, args);
fflush(stdout); //ADD THIS LINE!!!!!!!!!!!!!!!
}
va_end(args);
}
Best regards,
-Eduardo
You can use the system() function to launch espeak from your awk script.
#OP, i am not clear about your question, but seeing that system() interests you, here's how you call external command in awk
multimon -a DTMF | awk '{
cmd="espeak "$0 #$0 comes from the multimon output
system(cmd)
}
'
how to capture the command line output in a window using ncurses?
Suppose I am excecuting a command like "ls" I want to print that output in a specific window which is designed in ncurses. I am new to ncurses.help me.Thanks in advance
One thing I can think of is using system() to execute the command, redirecting its output to a temp file:
system("ls > temp");
Then opening the file temp, reading its content and displaying it on the window.
Not an elegant solution, but works.
The more elegant solution might be to implement the redirect within your program. Look into the dup() and dup2() system calls (see the dup(2) manpage). So, what you would want to do is (this is essentially what the shell called by system() ends up doing):
Code Snippet:
char *tmpname;
int tmpfile;
pid_t pid;
int r;
tmpname = strdup("/tmp/ls_out_XXXXXX");
assert(tmpname);
tmpfile = mkstemp(tmpname);
assert(tmpfile >= 0);
pid = fork();
if (pid == 0) { // child process
r = dup2(STDOUT_FILENO, tmpfile);
assert(r == STDOUT_FILENO);
execl("/bin/ls", "ls", NULL);
assert(0);
} else if (pid > 0) { // parent
waitpid(pid, &r, 0);
/* you can mmap(2) tmpfile here, and read from it like it was a memory buffer, or
* read and write as normal, mmap() is nicer--the kernel handles the buffering
* and other memory management hassles.
*/
} else {
/* fork() failed, bail violently for this example, you can handle differently as
* appropriately.
*/
assert(0);
}
// tmpfile is the file descriptor for the ls output.
unlink(tmpname); // file stays around until close(2) for this process only
For more picky programs (ones that care that they have a terminal for input and output), you'll want to look into pseudo ttys, see the pty(7) manpage. (Or google 'pty'.) This would be needed if you want ls to do its multicolumn pretty-printing (eg, ls will detect it is outputting to a file, and write one filename to a line. If you want ls to do the hard work for you, you'll need a pty. Also, you should be able to set the $LINES and $COLUMNS environment variables after the fork() to get ls to pretty print to your window size--again, assuming you are using a pty. The essential change is that you would delete the tmpfile = mkstemp(...); line and replace that and the surrounding logic with the pty opening logic and expand the dup2() call to handle stdin and stderr as well, dup2()ing them from the pty file handles).
If the user can execute arbitrary programs in the window, you'll want to be careful of ncurses programs--ncurses translates the move() and printw()/addch()/addstr() commands into the appropriate console codes, so blindly printing the output of ncurses programs will stomp your program's output and ignore your window location. GNU screen is a good example to look into for how to handle this--it implements a VT100 terminal emulator to catch the ncurses codes, and implements its own 'screen' terminal with its own termcap/terminfo entries. Screen's subprograms are run in pseudo-terminals. (xterm and other terminal emulators perform a similar trick.)
Final note: I haven't compiled the above code. It may have small typos, but should be generally correct. If you mmap(), make sure to munmap(). Also, after you are done with the ls output, you'll want to close(tmpfile). unlink() might be able to go much earlier in the code, or right before the close() call--depends on if you want people to see the output your playing with--I usually put the unlink() directly after the mkstemp() call--this prevents the kernel from writing the file back to disk if the tmp directory is disk backed (this is less and less common thanks to tmpfs). Also, you'll want to free(tmpname) after you unlink() to keep from leaking memory. The strdup() is necessary, as tmpname is modified by mkstemp().
Norman Matloff shows in his Introduction to the Unix Curses Library on page five a way:
// runs "ps ax" and stores the output in cmdoutlines
runpsax()
{ FILE* p; char ln[MAXCOL]; int row,tmp;
p = popen("ps ax","r"); // open Unix pipe (enables one program to read
// output of another as if it were a file)
for (row = 0; row < MAXROW; row++) {
tmp = fgets(ln,MAXCOL,p); // read one line from the pipe
if (tmp == NULL) break; // if end of pipe, break
// don’t want stored line to exceed width of screen, which the
// curses library provides to us in the variable COLS, so truncate
// to at most COLS characters
strncpy(cmdoutlines[row],ln,COLS);
// remove EOL character
cmdoutlines[row][MAXCOL-1] = 0;
}
ncmdlines = row;
close(p); // close pipe
}
...
He then calls mvaddstr(...) to put out the lines from the array through ncurses.