Detecting single keystrokes
Several times I have wanted to detect single keystrokes in R but have failed to find anything else than readline()
or similar.
An example would be to do interactive plotting or data browsing and be able to change parameter values with the arrow keys and automatically update the plot. Of course I could use readline()
and have the user input "u" then instead 开发者_开发问答of up arrow but I don't find it very elegant.
Could it be done with a system()
command reading stdin in some way?
EDIT: I have now been told elsewhere that stdin also wait for an enter-stroke before doing anything and that catching keystrokes immediately is system specific and tricky to accomplish. If anyone knows how to do it on ubuntu 10.10 or any other Linux/unix system I'd be glad to know.
Very OS-dependent solution. First some C code in getkey3.c:
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
void mygetch ( int *ch )
{
struct termios oldt, newt;
tcgetattr ( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr ( STDIN_FILENO, TCSANOW, &newt );
*ch = getchar();
tcsetattr ( STDIN_FILENO, TCSANOW, &oldt );
return;
}
Compile for R with R CMD SHLIB getkey3.c
That produces getkey3.so. Start R.
> dyn.load("getkey3.so")
> .C("mygetch",as.integer(0))
then press a key, it should return a list with the first element as the integer value of the ASCII code of that key. Store it in an R variable if you want.
Works for me on Ubuntu, you're on your own for any other OSes.
Barry
If you don't mind pulling in a graphical toolkit, like tcltk or RGtk2 then the gWidgets package can detect simple keystrokes in a text editing widget. For example:
require(gWidgets)
w <- gwindow("Detect keystrokes", visible=FALSE)
e <- gedit("", cont=w)
addHandlerKeystroke(e, handler=function(h,...) {
key <- h$key
print(key)
})
visible(w) <- TRUE
It doesn't do some basic things though: uparrow, downarrow may not show, modifiers etc.
I haven't used the R FFI in a long time but you can call the C-function getchar() with it, right?
in R type: ?.C
I used to write a tiny .dll to wrap some custom C-functions and then call them using .C(), however that was on Win. The way to build the dll in Linux is different but I assume the way to call into the dll is the same.
This is a more general solution: C non-blocking keyboard input. Especially it is restoring the terminal behavior after it has been killed or cashed.
精彩评论