#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
  • No labels
You must log in to comment.