Sida 1 av 1
Läsa tangentbord m.m. i C++
Postat: 29 mar 2009, 20:36
av Johnny Rosenberg
Tänkte börja med ett litet personligt miniprojekt, men inser direkt att mina kunskaper är ganska bristfälliga när det gäller att komma åt saker som är mer systemspecifika. Att be någon annan göra programmet åt mig känns inte riktigt kul givetvis, utan jag tänkte mer låta projektet lära mig saker samtidigt som jag kommer att ha nytta av resultatet, och kanske fler än jag, för av vissa trådar på diverse forum att döma, så är det i alla fall någon mer än jag som skulle vilja ha ett program som gör ungefär det jag tänkte försöka göra, trots min klåparnivå…
Så min taktik här är att jag försöker göra så mycket som möjligt själv och så fort jag undrar något söker jag mig till svaret så gott det går och i värsta fall ställer jag en eller flera frågor i ämnet här…
Då var det väl dags att ställa frågan, antar jag, och den gäller hur man läser av tangentbordet globalt från ett program som går i bakgrunden.
Användaren startar programmet i bakgrunden och börjar sedan att jobba med något annat, vad som helst, låt oss säga webbläsaren. Vilka tangenter han än trycker på, så ska programmet snappa upp dem. Hur gör man sådant?
Dessutom, när vissa saker snappats upp, ska programmet kunna radera de x antal sista tecken som skrivits och ersätta dem men andra tecken. Men hur då? Antar att man ska manipulera någon ström av något slag…
Har försökt söka på nätet, men vet inte riktigt vad jag ska söka på…
Det blev visst två frågor…
Re: Läsa tangentbord m.m. i C++
Postat: 29 mar 2009, 22:19
av gruble
Någonting likt en tangent loggare av hex eller binär värdet från tangentbordets port/interface. Skulle ju kanske gå att läsa upp tangenten med hjälp av talsyntes för synsvaga...
Re: Läsa tangentbord m.m. i C++
Postat: 30 mar 2009, 18:00
av Johnny Rosenberg
gruble skrev:Någonting likt en tangent loggare av hex eller binär värdet från tangentbordets port/interface. Skulle ju kanske gå att läsa upp tangenten med hjälp av talsyntes för synsvaga...
Jag skulle nog, om möjligt, hellre föredra att plocka upp händelsen efter att tangentnedtryckningen ”översatts” till ett tecken (evdev?), så att min egen tangentbordslayout inte äventyras. Detta av många skäl, ett av dem är att jag vill kunna köra programmet även på min Eee PC som jag inte kan ha samma tangentbordslayout på eftersom den saknar numeriska tangenter och jag vill inte hålla på och fippla med Num Lock hit och dit. På min stora laptop har jag nämligen siffror ENDAST på det numeriska tangentbordet, så tecken som @/()= skriver jag utan skifttangent för att ge plats åt ytterligare tecken på den raden.
Eller med andra ord: Jag vill hellre läsa av vilket tecken som just skrivits, exempelvis ”a”, ”\n” eller ” ”, hellre än att ”nu trycktes sjunde tangenten från höger på tredje raden ner”, för den tangenten är ju inte samma med alla olika tangentbordslayouter som finns.
Re: Läsa tangentbord m.m. i C++
Postat: 30 mar 2009, 18:50
av Lars
Vi pratar alltså X11 här? Då tror jag det normalt är fönsterhanteraren som sköter det där, och skickar tangenttryckningarna till rätt fönster. Fast jag kan inte svära på det. Kika på funktionen XGrabKey() och nysta vidare därifrån. Eller så kan man väl lägga in snabbkommandon i Gnome/KDE, jag inte hur det fungerar exakt.
Re: Läsa tangentbord m.m. i C++
Postat: 30 mar 2009, 20:18
av Johnny Rosenberg
Lars skrev:Vi pratar alltså X11 här? Då tror jag det normalt är fönsterhanteraren som sköter det där, och skickar tangenttryckningarna till rätt fönster. Fast jag kan inte svära på det. Kika på funktionen XGrabKey() och nysta vidare därifrån. Eller så kan man väl lägga in snabbkommandon i Gnome/KDE, jag inte hur det fungerar exakt.
Rätt fönster…? Jag vill ju läsa av vad som skrivs på tangentbordet över huvud taget, oavsett fönster. Mitt program ska ligga i bakgrunden och spionera på och i vissa fall ändra på det som skrivs. Syftet är att åstadkomma ”textmakron” som funkar i alla applikationer där man matar in text. Sådant man matar in ofta ska vara kort att mata in, är tanken. Även korrigering av vanliga stavfel, som exempelvis min favorit ”yttelrigare”, ingår i min tanke (som egentligen inte är min; det finns redan program för detta, men det är lite tunt med program för Linux och som klarar UTF-8 och som är skrivna i C++).
Ska ta mig en titt på XGrabKey() i alla fall.
Re: Läsa tangentbord m.m. i C++
Postat: 11 apr 2009, 23:11
av gasol
Du snappa upp "tangenttryck" genom att polla X-servern. Den här koden skrev jag som ett litet projekt för att räkna hur många tecken man har skrivit. Den är baserad på en keylogger jag hittade på internet.
Det är XQueryKeymap du vill kolla på för att läsa av knappen som är intryckt.
http://tronche.com/gui/x/xlib/input/XQueryKeymap.html
Att "ta bort" vissa tecken, eller teckensekvenser är vad jag inte möjligt, om du inte buffrar dom först och sedan skickar dom vidare till programmen ifråga. Det görs nog lämpligast som ett plug-in / modifikation av en fönsterhanterare, som någon tidigare föreslog.
Det är dock inte möjligt att skicka key-events till ett program och sedan "ta bort dom".
Kod: Markera allt
/* compile: gcc -o counter counter.c -lX11 -Wall -std=c99
* usage: counter file
*
* Based on:
* xspy
* Jon A. Maxwell (JAM)
* jmaxwell@acm.vt.edu
*
*/
#include <X11/Xlib.h>
#include <X11/X.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#define DEFAULT_DISPLAY ":0"
#define DEFAULT_DELAY 10000
#define BIT(c, x) ( c[x/8]&(1<<(x%8)) )
#define TRUE 1
#define FALSE 0
long int count;
FILE *f;
void usleep(int x) {
struct timeval time;
time.tv_sec= x/1000000;
time.tv_usec=x%1000000;
select(0, NULL, NULL, NULL, &time);
}
void sig_hant(int sig) {
rewind(f);
fprintf(f,"%ld",count);
exit(0);
}
int main(int argc, char *argv[]) {
char *hostname=DEFAULT_DISPLAY,
*char_ptr,
buf1[32], buf2[32],
*keys,
*saved,
saved_count[256];
int i, delay=DEFAULT_DELAY;
Display *disp;
pid_t pid;
signal(SIGTERM,sig_hant);
if(argc < 2) {
fprintf(stderr,"usage %s file\n",argv[0]);
return -1;
}
if((pid = fork()) < 0) {
fprintf(stderr,"cant fork(1)!");
} else if(pid !=0) {
exit(0);
}
if((pid=fork()) < 0)
fprintf(stderr,"cant fork(2)!");
else if(pid != 0)
exit(0);
setsid();
f = fopen(argv[1],"r+");
if(f == NULL) {
fprintf(stderr,"could not open file\n");
return -1;
}
memset(saved_count,0,256);
fread(saved_count,256,sizeof(char),f);
count = atol(saved_count);
//printf("Initial count %ld\n",count);
/* setup Xwindows */
disp=XOpenDisplay(hostname);
if (NULL==disp) {
fprintf(stderr, "Cannot open X display: %s\n", hostname);
return -1;
}
XSynchronize(disp, TRUE);
/* setup buffers */
saved=buf1;
keys=buf2;
XQueryKeymap(disp, saved);
while (1) {
/* find changed keys */
XQueryKeymap(disp, keys);
for (i=0; i<32*8; i++) {
if (BIT(keys, i)!=BIT(saved, i)) {
if (BIT(keys, i) != 0 ) {
count++;
/* printf("count %ld\n",count);*/
if(!(count % 10)) {
rewind(f);
fprintf(f,"%ld",count);
}
}
}
}
/* swap buffers */
char_ptr=saved;
saved=keys;
keys=char_ptr;
usleep(delay);
}
}
Re: Läsa tangentbord m.m. i C++
Postat: 12 apr 2009, 10:21
av Johnny Rosenberg
gasol skrev:Du snappa upp "tangenttryck" genom att polla X-servern. Den här koden skrev jag som ett litet projekt för att räkna hur många tecken man har skrivit. Den är baserad på en keylogger jag hittade på internet.
Det är XQueryKeymap du vill kolla på för att läsa av knappen som är intryckt.
http://tronche.com/gui/x/xlib/input/XQueryKeymap.html
Att "ta bort" vissa tecken, eller teckensekvenser är vad jag inte möjligt, om du inte buffrar dom först och sedan skickar dom vidare till programmen ifråga. Det görs nog lämpligast som ett plug-in / modifikation av en fönsterhanterare, som någon tidigare föreslog.
Okej, det där med att ta bort tecken inte skulle vara så enkelt köper jag, men om man istället skickar ett antal Backspace och därefter sin egen sekvens, skulle det kunna vara en utväg? Det borde nästan vara så motsvarande program för Windows fungerar, för de tecken man skriver kommer ju ut och när den känner igen en kombination tas ju tecknen bort och ersätts med motsvarande ersättningssträng.
gasol skrev:Det är dock inte möjligt att skicka key-events till ett program och sedan "ta bort dom".
Kod: Markera allt
/* compile: gcc -o counter counter.c -lX11 -Wall -std=c99
* usage: counter file
*
* Based on:
* xspy
* Jon A. Maxwell (JAM)
* jmaxwell@acm.vt.edu
*
*/
#include <X11/Xlib.h>
#include <X11/X.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#define DEFAULT_DISPLAY ":0"
#define DEFAULT_DELAY 10000
#define BIT(c, x) ( c[x/8]&(1<<(x%8)) )
#define TRUE 1
#define FALSE 0
long int count;
FILE *f;
void usleep(int x) {
struct timeval time;
time.tv_sec= x/1000000;
time.tv_usec=x%1000000;
select(0, NULL, NULL, NULL, &time);
}
void sig_hant(int sig) {
rewind(f);
fprintf(f,"%ld",count);
exit(0);
}
int main(int argc, char *argv[]) {
char *hostname=DEFAULT_DISPLAY,
*char_ptr,
buf1[32], buf2[32],
*keys,
*saved,
saved_count[256];
int i, delay=DEFAULT_DELAY;
Display *disp;
pid_t pid;
signal(SIGTERM,sig_hant);
if(argc < 2) {
fprintf(stderr,"usage %s file\n",argv[0]);
return -1;
}
if((pid = fork()) < 0) {
fprintf(stderr,"cant fork(1)!");
} else if(pid !=0) {
exit(0);
}
if((pid=fork()) < 0)
fprintf(stderr,"cant fork(2)!");
else if(pid != 0)
exit(0);
setsid();
f = fopen(argv[1],"r+");
if(f == NULL) {
fprintf(stderr,"could not open file\n");
return -1;
}
memset(saved_count,0,256);
fread(saved_count,256,sizeof(char),f);
count = atol(saved_count);
//printf("Initial count %ld\n",count);
/* setup Xwindows */
disp=XOpenDisplay(hostname);
if (NULL==disp) {
fprintf(stderr, "Cannot open X display: %s\n", hostname);
return -1;
}
XSynchronize(disp, TRUE);
/* setup buffers */
saved=buf1;
keys=buf2;
XQueryKeymap(disp, saved);
while (1) {
/* find changed keys */
XQueryKeymap(disp, keys);
for (i=0; i<32*8; i++) {
if (BIT(keys, i)!=BIT(saved, i)) {
if (BIT(keys, i) != 0 ) {
count++;
/* printf("count %ld\n",count);*/
if(!(count % 10)) {
rewind(f);
fprintf(f,"%ld",count);
}
}
}
}
/* swap buffers */
char_ptr=saved;
saved=keys;
keys=char_ptr;
usleep(delay);
}
}
Re: Läsa tangentbord m.m. i C++
Postat: 12 apr 2009, 19:52
av gasol
Skulle ladda hem man-sidorna till xlib om jag var du, finns mkt intressant att läsa där. Jag har aldrig försökt mig på det du vill göra, men skulle kunna tänka mig att XSendEvent kan fungera. Däremot så kan jag inte på rak arm säga på vilket sätt du kan "snoopa" fram vilket X11 fönster som har keyboard input.
Kod: Markera allt
Status XSendEvent(Display *display, Window w, Bool propagate, long
event_mask, XEvent *event_send);
Dessa länkar kan också vara intressanta för dig skulle jag tro: (XEvent är en union)
http://tronche.com/gui/x/xlib/events/ke ... inter.html (om keyboard events)
http://tronche.com/gui/x/xlib/event-handling/ (allmänt om xlib events)
Re: Läsa tangentbord m.m. i C++
Postat: 13 apr 2009, 10:23
av Johnny Rosenberg
gasol skrev:Skulle ladda hem man-sidorna till xlib om jag var du, finns mkt intressant att läsa där. Jag har aldrig försökt mig på det du vill göra, men skulle kunna tänka mig att XSendEvent kan fungera. Däremot så kan jag inte på rak arm säga på vilket sätt du kan "snoopa" fram vilket X11 fönster som har keyboard input.
Kod: Markera allt
Status XSendEvent(Display *display, Window w, Bool propagate, long
event_mask, XEvent *event_send);
Dessa länkar kan också vara intressanta för dig skulle jag tro: (XEvent är en union)
http://tronche.com/gui/x/xlib/events/ke ... inter.html (om keyboard events)
http://tronche.com/gui/x/xlib/event-handling/ (allmänt om xlib events)
Tack så mycket för all information. Jag är ganska säker på att det borde gå i alla fall, även i Linux alltså, för det finns ju redan ett program som gör detta. Jag tänker på AutoKey, som dock är skrivet i Python, ett språk jag själv aldrig varit inne och ens nosat på.
Haken med AutoKey när jag testade det förra gången, var att stöd för Unicode saknades. Inte ens åäöÅÄÖ fungerade, vilket gjorde programmet totalt oanvändbart för mig.
Nu har det dock kommit i en ny version (0.52.2-1, alltså fortfarande en nollversion, eller vad man ska kalla det) som sägs ha Unicode-stöd och jag håller på att försöka få den att funka. Har inte lyckats än men jag såg att jag fått svar på deras forum (en särskild liten avdelning på internationella Ubuntu-forumet), så det kanske löser sig ändå.
Men även om jag får igång det så vill jag ändå göra min egen C++-variant. Gillar ju egentligen inte idén med Python, Perl, Java och allt vad det heter. Kanske helt utan anledning, men så är det i alla fall… Kanske kan jag använda koden till AutoKey som inspirationskälla också. Det borde ju i alla fall framgå ungefär hur de tänkt och det kanske går använda sig av samma tänk i C++, vad vet jag?
Re: Läsa tangentbord m.m. i C++
Postat: 13 apr 2009, 19:27
av gasol
Tog en lite peek på python-programmet, verkar som att dom får reda på vilket fönster som har focus genom (via någon pyrhon wrapper):
Kod: Markera allt
XGetInputFocus(Display *display; Window *focus_return; int *revert_to_return)
Re: Läsa tangentbord m.m. i C++
Postat: 09 maj 2010, 11:43
av Johnny Rosenberg
Kan meddela att AutoKey numera fungerar riktigt bra, så det hela slutade med att jag lade ner hela projektet och använder Autokey istället…