p, li { white-space: pre-wrap; }
\#include "arch.h"
\#ifdef LINUX
\#include <dirent.h>
\#include <errno.h>
\#include <stdio.h>
\#include <stdio_ext.h>
\#include <sys/types.h>
\#include <sys/stat.h>
\#include <fcntl.h>
\#include <stdlib.h>
\#include <unistd.h>
\#include <linux/input.h>
\#include <sys/select.h>
\#include <poll.h>
\#include <sys/signal.h>
\#include <sys/types.h>
\#include <termios.h>
\#include <pthread.h>
\#include "inputevent.h"
\#include "util/vt100.h"
struct sigaction sigint_action, sighup_action, sigterm_action;
static void (*sig_exit_function)(void)=NULL; // Tätä kutsutaan kun Ctrl+C painettu, jos määritelty
static pthread_attr_t attr;
static pthread_t thread;
static int num_event_devices;
struct pollfd epollfd\[20\];
struct einfo {
int fd;
int devices; // 1=key, 2=mouse, 4=led, 8=joy, 16=syn
} evdev_info\[20\];
static int ledfd=0;
static unsigned int ledstates=0;
int evmousex=0; // voidaan lukea suoraan ilman funktiokutsua
int evmousey=0;
int evmwheel=0;
int evmlbutton=0;
int evmrbutton=0;
int evmmbutton=0;
unsigned int eventdebug=0;
static unsigned char keystate\[255\]={0};
//static struct sigaction saio,oldsaio;
static struct termios tios;
//void (*evfunction)(int , int )=NULL;
static unsigned int evtype_bitmask\[EV_MAX/8 + 1\];
//static int oldrep\[2\];
static int eventsdisabled=0;
// ASCII-koodien mappaukset näppäimistön scankoodeihin
// Saatetaan ehkä joskus tarvita
// myös toisin päin olisi tarpeen tehdä vastaava taulukko
//static unsigned char keytable\[128\] =
//{
//0,0,0,0,0,0,0,0,0,0,
//0,0,0,0,0,0,0,0,0,0,
//0,0,0,0,0,0,0,0,0,0,
//0,0,57,0,0,0,0,0,0,0,
//0,0,0,0,51,12,52,0,11,2, // 1,0
//3,4,5,6,7,8,9,10,0,0, // 2-9
//0,0,0,0,0,30,48,46,32,18, //-E
//33,34,35,23,36,37,38,50,49,24, //F-O
//25,16,19,31,20,22,47,17,45,21, //P-Y
//44,0,0,0,0,0,0,30,48,46, //Z-c
//32,18,33,34,35,23,36,37,38,50, //d-m
//49,24,25,16,19,31,20,22,47,17, //n-w
//45,21,44,0,0,0,0,0 //x-z
//};
/// Rekisteröidään exit funktio kun esim. ohjelmassa painetaan Ctrl+C.
/// Funktiota kutsutaan tällöin autimaattisesti kun Ctrl+C:tä on painettu.
/// Koska Ctrl+C lopettaa ohjelman toiminnan voidaan lopetus hoitaa siististi tämän avulla.
void register_signal_exit(void (f) (void)) { sig_exit_function = f; }
// Palauttaa mousen X-koordinaatin arvon
int getmousex(void) { return evmousex; }
// Palauttaa mousen Y-koordinaatin arvon
int getmousey(void) { return evmousey; }
// Palauttaa mousen wheelin laskurin arvon
int getmousewheel(void) { return evmwheel; }
/// Asetetaan eventtien debuggaus.
/// Bittien arvot: 0=none 1=key 2=mouse 4=joystic.
void eventdebugmode(unsigned int mode) { eventdebug=mode; }
/// Asetetaan mousen x ja y positio arvot halutuiksi.
void resetmousepos(int x, int y)
{
evmousex=x;
evmousey=y;
}
/// Palauttaa true jos näppäin on painettuna.
bool key(keymap key) { return keystate\[key\] & 1; }
/// Palauttaa true jos näppäin on painettuna.
bool key(unsigned char key) { return keystate\[key\] & 1; }
/// Palauttaa true vain kerran kun näppäimen tila on vaihtuu alas tilaan
bool keydown(keymap key)
{
if (keystate\[key\]&2) {
// Nollataan alaspainamistieto
keystate\[key\] &= \~2;
return true;
}
return false;
}
/// Palauttaa true vain kerran kun näppäimen tila on vaihtuu ylös tilaan.
bool keyup(keymap key)
{
if (keystate\[key\]&4) {
// Nollataan ylösnousu tieto
keystate\[key\] &= \~4;
return true;
}
return false;
}
/// Palauttaa true vain kerran kun näppäimen tila on vaihtuu alas tilaan.
bool keydown(unsigned char key)
{
if (keystate\[key\]&2) {
// Nollataan alaspainamistieto
keystate\[key\] &= \~2;
return true;
}
return false;
}
/// Palauttaa true vain kerran kun näppäimen tila on vaihtuu ylös tilaan.
bool keyup(unsigned char key)
{
if (keystate\[key\]&4) {
// Nollataan ylösnousu tieto
keystate\[key\] &= \~4;
return true;
}
return false;
}
/// Voidaan asettaa näppäimistön ledit.
/// Bittiarvot 1=NumLock 2=CapsLoc 4=ScrollLock 8=Compose.
void setled(unsigned int ledparam)
{
int retval;
struct input_event ev;
// if (ledfd \!= keyfd) { printf("NO keyboard LED support \!\n"); return; }
ev.type = EV_LED;
if ((ledparam&1) \!= (ledstates&1))
{
ev.code = LED_NUML;
ledparam&1 ? ev.value = 1 : ev.value = 0 ;
retval = write(ledfd, &ev, sizeof(struct input_event));
}
if ((ledparam&2) \!= (ledstates&2))
{
ev.code = LED_CAPSL;
ledparam&2 ? ev.value = 1 : ev.value = 0 ;
retval = write(ledfd, &ev, sizeof(struct input_event));
}
if ((ledparam&4) \!= (ledstates&4))
{
ev.code = LED_SCROLLL;
ledparam&4 ? ev.value = 1 : ev.value = 0 ;
retval = write(ledfd, &ev, sizeof(struct input_event));
}
if ((ledparam&8) \!= (ledstates&8))
{
ev.code = LED_COMPOSE;
ledparam&8 ? ev.value = 1 : ev.value = 0 ;
retval = write(ledfd, &ev, sizeof(struct input_event));
}
}
/// Haetaan näppäimistön ledien tämän hetkiset tilat.
void getled(unsigned int &ledparam) { ledparam=ledstates; }
/// Käännetään haluttujen näppäimistön ledien tila käänteiseksi.
/// Voidaan helposti vilkuttaa niitä.
void negled(unsigned int ledparam) { ledparam=ledstates ^ ledparam ; setled(ledparam); }
/// Linuxin blokkaava eventtien luku Thread.
/// Luetaan Linuxin kernelin Event-interfacesta näppäimien, mousen, joystikin ja näppäimistön ledien tilat.
/// Käytämme tätä funktiota useiden eri oheislaitteiden eventtien samanaikaiseen lukemiseen. \n
/// Signaalien käyttö saattaa aiheuttaa interrupted system calls erroreita muissa saman prosessin funktioissa.
/// Siksi käytämme Linuxin threadia ja tämä funktio toimii erillisenä threadina joka lukee blokkaavasti koko
/// ajan mahdollisia näppäimistön, mousen tai joystikin tapahtumia.
/// static void readevent(int sig, siginfo_t * si , void * data) // jos halutaan käyttää realiaika-signaaleja
static void \*readevent(void * data) // Tämä funktio on linuxin thread
{
int r;
struct input_event ev\[17\];
int num;
int eventcount;
printf("inputevent: Thread started\n");
while (true)
{
do
{
r = poll(epollfd, num_event_devices, \-1);
}
while (r < 0);
/// Eventtien käsittely
for ( int i=0; i<num_event_devices; i++) if (epollfd\[i\].revents == POLLIN)
{
epollfd\[i\].revents = 0;
r = read(epollfd\[i\].fd, ev, sizeof(input_event)*16);
if (r < 0) continue;
eventcount = r / sizeof(input_event);
for(num=0; num<eventcount ; num++)
{
if(eventdebug & 1)
{
VT100::set_fg_color(VT100::MAGENTA);
printf("code=%3i ",ev\[num\].code);
printf("value=%3i ",ev\[num\].value);
printf("type=%3i \n",ev\[num\].type);
\_flushlbf(); // Varmistetaan tulostus
}
// if (ev.value > 0) printf("DOWN "); else printf("UP ");
// ev.value == 0 ; näppäin ylös
// ev.value == 1 ; näppäin alas
// ev.value == 2 ; näppäin autorepeat
switch (ev\[num\].type)
{
case 1 :
if (ev\[num\].value == 1) // Key down
{
if (ev\[num\].code == 272) evmlbutton = ev\[num\].value;
if (ev\[num\].code == 273) evmrbutton = ev\[num\].value;
if (ev\[num\].code == 274) evmmbutton = ev\[num\].value;
if (eventsdisabled == 0)
{
keystate\[ev\[num\].code\] \|=1; // näppäin painettuna alas
keystate\[ev\[num\].code\] \|= 2; // Talletetaan tieto näppäimen alaspainamisesta;
tcflush(fileno(stdin), TCIFLUSH); // tyhjennetään näppäimistöpuskuri
}
}
else if (ev\[num\].value == 0) // Key up
{
keystate\[ev\[num\].code\] &= \~1; // näppäin vapaassa tilassa
keystate\[ev\[num\].code\] \|= 4; // Talletetaan tieto näppäimen ylösnousemisesta;
}
else if (ev\[num\].value == 2) // Keyboard Repeat event
{
if (eventsdisabled == 0)
{
tcflush(fileno(stdin), TCIFLUSH); // tyhjennetään näppäimistöpuskuri
}
}
break;
case 2 : // mouse event
if (ev\[num\].code == 0) evmousex \+= ev\[num\].value;
if (ev\[num\].code == 1) evmousey \+= ev\[num\].value;
if (ev\[num\].code == 8) evmwheel \+= ev\[num\].value;
// if(eventdebug&2) {
// setfgcolor(CYAN);
// printf("mousex=%5i, mousey=%5i, wheel=%5i %1i %1i %1i \n",mousex,mousey,wheel,lbutton,rbutton,mbutton);
// \_flushlbf();
break;
case 17 : // LED event, ylläpidämme tietoa ledien tilasta
if (ev\[num\].code == LED_NUML) ev\[num\].value ? ledstates \|= 1 : ledstates &= \~1;
else if (ev\[num\].code == LED_CAPSL) ev\[num\].value ? ledstates \|= 2 : ledstates &= \~2;
else if (ev\[num\].code == LED_SCROLLL) ev\[num\].value ? ledstates \|= 4 : ledstates &= \~4;
else if (ev\[num\].code == LED_COMPOSE) ev\[num\].value ? ledstates \|= 8 : ledstates &= \~8;
break;
case 4 : // LED event, ylläpidämme tietoa ledien tilasta
break;
case 0 : // Event tiedon viimeinen osa
break;
default:
printf("inputevent: Unknown Event Type %i\n", ev\[num\].type);
break;
}
// Jos halutaan vielä erillinen keyboard handler funktio
// if (evfunction) evfunction(ev\[1\].value, ev\[1\].code);
// Tällöin funktiota kutsutaan automaattisesti näppäinpainalluksen yhteydessä.
// Ja välitetään painetun näppäimen tiedot funktiolle.
}
}
}
}
/// Kun eventtien käsittely lopetetaan, tätä kutsutaan automaattisesti(man atexit) kun ohjelman suoritus loppuu.
/// Voidaan kutsua halutessa muulloinkin.
static void eventclose(void)
{
// int rep\[2\];
// rep\[0\] = 250;
// rep\[1\] = 100;
// if(ioctl(keyfd, EVIOCSREP, oldrep)) { // keyboard repeatrate alkuperäiseksi
// perror("evdev ioctl repeatrate set");
// }
// \__fpurge(stdout);
// \_flushlbf();
setled(0);
for ( int i=0; i<num_event_devices; i++) if (epollfd\[i\].fd) close(evdev_info\[i\].fd);
// sigaction(SIGIO, &oldsaio, NULL); // Palautetaan alkuperäiset signaaliasetukset
usleep(10000);
eventdisable();
int s = pthread_cancel(thread);
if (s) {
perror("pthread_cancel");
}
}
/// Lopetussignaalien käsittelijä.
static void evsighandler(int signum)
{
printf("\n\n********************************************\n");
if (signum == SIGTERM) printf("got SIGTERM");
else if (signum == SIGHUP) printf("got SIGHUP");
else if (signum == SIGINT) printf("got SIGINT");
printf(", we will leave the program now ");
printf("\n********************************************\n");
if (sig_exit_function \!= NULL) (*sig_exit_function)();
eventclose();
if ( signum == SIGINT ) (*sigint_action.sa_handler)(signum); // Kutsutaan lopuksi edellistä action handleriä
else if ( signum == SIGHUP ) (*sighup_action.sa_handler)(signum); // Kutsutaan lopuksi edellistä action handleriä
else if ( signum == SIGTERM ) (*sigterm_action.sa_handler)(signum); // Kutsutaan lopuksi edellistä action handleriä
exit(0);
}
/// Napataan lopetus signaalit jotta saadaan lopetetuksi siististi.
static void evsigterm()
{
struct sigaction new_action;
new_action.sa_handler = evsighandler;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction (SIGINT, &new_action, &sigint_action); // we will catch Ctrl-C
sigaction (SIGHUP, &new_action, &sighup_action);
sigaction (SIGTERM, &new_action, &sigterm_action);
// if (old_action.sa_handler == SIG_DFL) sigaction (SIGTERM, &new_action, NULL);
}
/// Käynnistää eventtien käsittelyn.
/// Kutsutaan ohjelman alussa tai siinä vaihessa kun halutaan käyttää Event-toiminnallisuuksia,
/// kuten näppäiten painallusten lukemista, mousen tai joystikin lukemista.
void eventinit()
{
int fd;
int i;
int s;
unsigned int devnum;
unsigned int led_b;
struct input_id device_info;
char name\[256\]= "Unknown";
// evfunction=NULL;
for (int i=0 ; i<20; i++) {
epollfd\[i\].fd = 0;
epollfd\[i\].events = POLLIN;
epollfd\[i\].revents = 0;
evdev_info\[i\].fd = 0;
evdev_info\[i\].devices = 0;
}
char evdevlist\[\]\[50\]={
"/dev/event0",
"/dev/event1",
"/dev/event2",
"/dev/event3",
"/dev/event4",
"/dev/event5",
"/dev/input/event0",
"/dev/input/event1",
"/dev/input/event2",
"/dev/input/event3",
"/dev/input/event4",
"/dev/input/event5"
};
for (devnum=0; devnum < (sizeof(evdevlist)/sizeof(evdevlist\[0\])); devnum++) {
fd=open(evdevlist\[devnum\],O_RDWR\|O_NOCTTY);
if (fd < 0) continue;
\*evtype_bitmask=0;
if (ioctl(fd, EVIOCGBIT(0,EV_MAX), evtype_bitmask) < 0) {
perror("evdev ioctl");
printf("dev %s \n", evdevlist\[devnum\]);
close(fd);
continue;
}
// Tsekataan josko tämä device tukee näitä eventtejä
printf("\n");
if ( \*evtype_bitmask & (1<<EV_SYN) ) {
printf("SYN events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 16;
}
if ( \*evtype_bitmask & (1<<EV_SND) ) {
printf("SOUND events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 32;
}
if ( \*evtype_bitmask & (1<<EV_MSC) ) {
printf("MISC events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 64;
}
if ( \*evtype_bitmask & (1<<EV_SW) ) {
printf("SW events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 128;
}
if ( \*evtype_bitmask & (1<<EV_REP) ) {
printf("Repeat events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 256;
}
if ( \*evtype_bitmask & (1<<EV_FF) ) {
printf("ForceFeedback events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 512;
}
if ( \*evtype_bitmask & (1<<EV_PWR) ) {
printf("PWR events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 1024;
}
if ( \*evtype_bitmask & (1<<EV_FF_STATUS) ) {
printf("ForceFeedback status events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 2048;
}
if ( \*evtype_bitmask & (1<<EV_LED) ) {
ledfd = fd;
printf("LED events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 4;
}
if ( (*evtype_bitmask & (1<<EV_KEY)) ) {
printf("Keyboard/Button events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 1;
}
if ( (*evtype_bitmask & (1<<EV_REL)) ) {
printf("Mouse events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 2;
}
if ( (*evtype_bitmask & (1<<EV_ABS)) ) {
printf("Joystick events available %s\n", evdevlist\[devnum\]);
evdev_info\[num_event_devices\].devices \|= 8;
}
epollfd\[num_event_devices\].fd = fd;
evdev_info\[num_event_devices\].fd = fd;
num_event_devices++;
if(ioctl(fd, EVIOCGID, &device_info)) { perror("evdev ioctl"); } // Kysytään tietoa laitteesta
else {
printf("vendor %04hx product %04hx version %04hx", device_info.vendor, device_info.product, device_info.version);
switch ( device_info.bustype)
{
case BUS_PCI :
printf(" is on a PCI bus\n");
break;
case BUS_ISAPNP :
printf(" is on a ISAPNP Bus\n");
break;
case BUS_USB :
printf(" is on a Universal Serial Bus\n");
break;
case BUS_HIL :
printf(" is on a HIL Bus\n");
break;
case BUS_BLUETOOTH :
printf(" is on a BLUETOOTH Bus\n");
break;
case BUS_ISA :
printf(" is on a ISA Bus\n");
break;
case BUS_I8042 :
printf(" is on a I8042 Bus\n");
break;
case BUS_XTKBD :
printf(" is on a XTKBD Bus\n");
break;
case BUS_RS232 :
printf(" is on a RS232 Serial Bus\n");
break;
case BUS_GAMEPORT :
printf(" is on a Gameport Bus\n");
break;
case BUS_I2C :
printf(" is on a I2C Bus\n");
break;
case BUS_HOST :
printf(" is on a HOST Bus\n");
break;
case BUS_GSC :
printf(" is on a GSC Bus\n");
break;
default:
printf(" is on a Unknown Bus\n");
break;
}
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) { perror("evdev ioctl"); } // Kysytään laitteen nimi
else printf("The device says its name is %s", name);
}
printf("\n");
}
if (ledfd) {
ioctl(ledfd, EVIOCGLED(sizeof(led_b)), &led_b); // Haetaan näppäimistön ledien tilat
ledstates=led_b&255;
}
// int rep\[2\];
// if(ioctl(keyfd, EVIOCGREP, oldrep)) { // Talletamme näppäimistön nykyisen repeatraten
// perror("evdev ioctl repeatrate save");
// }
// printf("Old reapeatrate = %i %i\n",oldrep\[0\],oldrep\[1\]);
//
// rep\[0\] = 2500;
// rep\[1\] = 2500;
// if(ioctl(keyfd, EVIOCSREP, rep)) { // Näppäimistön repeatrate mahdollisimman hitaaksi
// perror("evdev ioctl repeatrate set");
// }
eventenable();
i = atexit(eventclose); // Lopetusfunktio hoituu automaattisesti
if (i \!= 0) {
fprintf(stderr, "inputevent atexit: cannot set exit function\n");
exit(EXIT_FAILURE);
}
pthread_attr_init(&attr); // threadin attribuuttien initialisointi
// pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
printf("inputevent:pthread_attr_setschedpolicy failed\n");
}
sched_param schedulingParameters;
int maxPriority = sched_get_priority_max(SCHED_FIFO);
schedulingParameters.sched_priority = maxPriority;
if (pthread_attr_setschedparam(&attr, &schedulingParameters)) {
printf("inputevent:pthread_attr_setschedparam failed\n");
}
s=pthread_create(&thread, &attr , (void * (*) (void \*))readevent, NULL);
evsigterm(); // Napataan INT KILL HUP signaalit niin poistutaan siististi
}
/// Disabloidaan väliaikaisesti eventtien käsittely.
/// Kutsutaan jos halutaan käyttää välissä normaaleja posixin näppäimistön käsittelyfunktioita kuten getchar().
void eventdisable(void)
{
eventsdisabled=1;
tios.c_lflag \|= ECHO \| ICANON;
tcsetattr(fileno(stdin), TCSANOW, &tios); // Palautetaan alkuperäiset asetukset
tcflush(fileno(stdin), TCIFLUSH); // tyhjennetään puskurit
\__fpurge(stdin); // Tämä tyhjentää C-kirjaston stream puskurit
VT100::showcursor();
}
/// Palataan takaisin eventtien käsittelyyn ja disabloidaan normaali näppäimistön toiminnallisuus.
void eventenable(void)
{
tcgetattr(fileno(stdin), &tios); // vanhat terminaaliasetukset talteen
tios.c_lflag &= \~(ECHO); // Emme halua kaiuttaa painalluksia
tcsetattr(fileno(stdin), TCSANOW, &tios);
tcflush(fileno(stdin), TCIFLUSH); // tyhjennetään puskurit
\__fpurge(stdin); // Tämä tyhjentää C-kirjaston stream puskurit
VT100::hidecursor();
eventsdisabled=0;
}
\#endif // LINUX
\#ifndef LINUX
// Linux tarvitsee tämän funktion jotta näppäimistö, mouse ja joystick toimivat.
// Windowsissa tämä ei tee mitään, ja tämä funktio on vain yhteensopivuuden takia.
void eventinit()
{
return;
}
bool key(unsigned char k)
{
int key_state;
//return (GetKeyState(k) < 0);
key_state = GetAsyncKeyState(k);
return (key_state < 0);
}
bool keydown(unsigned char k)
{
int key_state;
//return (GetKeyState(k) < 0);
key_state = GetAsyncKeyState(k);
if ((key_state < 0 ) && (key_state & 1)) return 1;
return 0;
}
\#endif // \!LINUX\\
|