IO manager

// Compiles, untested
// Madinit proper rather than rigged fr test
// added the binding common definition
//
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <linux/input.h>
#define  COMMON_MAPS
#include "/home/so/maps.h"
#define IO_VERSION "io 1.0.5"
/// this is a testing hack, ignore
char test_dat[] = {KEY_A,KEY_B,KEY_ENTER,KEY_C,KEY_D,KEY_C,KEY_ENTER,KEY_LEFT,KEY_RIGHT,KEY_UP,KEY_DOWN};
int test_index=0;
int test_sig;

// compile time constants and defines

// should be replaced by a discovery function and/or swiches
#define fmouse "/dev/input/event5"
#define fkeyboard "/dev/input/event3"
// Loop signals and a fake fd for redraw timeout
#define FD_XCB 16
#define TIMEOUT 20000
#define TEST_RATE 10
#define XCB_RATE 10
#define MAXSRC 0x400
#define MASKSRC 0x3ff
#define MAXLINE 0x40
#define MASKLINE 0x3f
char strings[MAXSRC]; // full of collected chars marked with enter key
int strings_index=0;
/// IOfds
int fmd;
int fkd;
int fxd;

// Set up entry points on the Bus
char * IO_Rect; // one rectangle for test
EntryType * ExecCommand;
EntryType * XcharsCommand;
typedef struct input_event IE;
typedef IE * PIE;
int line_cursor, char_cursor;
int IO_SIG; //track events in the loop
#define IO_MOUSE 1
#define IO_KEYS 2
#define IO_XCB 4
#define IO_TEST 8
int  FD_Scroll;
char * echo_rect;
typedef int bool;
void * args[20]; //local args
int argc=0;

// print utils
#define putstr(a) fputs(a,stdout)
#define putchr(a) fputc(a,stdout)
void putint(int i)
{
char str[6];
putstr(ItoA(i,str));
}
#define erck(a) error_check(a,#a)
int error_check(int var,char *str) {
perror(str);
exit(0);
}


// Attempt a non blocking read on fd
int event(int fd,PIE ie) {
int ioerr;
//if(fd == fetch) XcbPoll();
//else
if(fd == FD_XCB && (IO_SIG & IO_XCB))
{
//Xcb_Poll(argc,args);
IO_SIG ^= IO_XCB;
}
else if(IO_SIG & IO_TEST)
{
ie->type= EV_KEY;
ie->code=test_dat[test_index];
test_index++;
if(test_index == sizeof(test_dat)) test_index=0;
ioerr=24; // fake it for test
} else
ioerr = read(fd, ie, sizeof(IE));
if(ioerr < (-1))
erck(fd);
return(ioerr);
}
// Diagnostics
void print_event_type(PIE ie) {
switch(ie->type) {
case EV_SYN: putstr("State"); break;
case EV_KEY: putstr("Key  "); break;
case EV_REL: putstr("Rel  "); break;
case EV_MSC: putstr("Misc "); break;
case EV_ABS: putstr("Abs  "); break;
default:  putint(ie->type); break;
}
putint(ie->code);
putchr('\n');
}

bool is_char_key(unsigned int code);
bool is_func_key(unsigned int code);
int to_char_keys_index(unsigned int keycode);
int code_to_ascii(unsigned int keycode);
int addcode(unsigned short type, unsigned short code);
void print_event_type(IE * ie);


// Echo char or command line.
typedef long unsigned int lui;
int IO_Echo(char *str)
{

int base=0;
XString echo = {{(lui) "PutStr"},{(lui) echo_rect}};
echo.x=char_cursor;
echo.ptr=str;
XcharsCommand(&base,(void **) &echo);
return(SUCCESS);
}

int IO_Cursor(int dx,int dy)
{
int base=0;
XYCursor cursor = {{(lui)"MovePtr"},{(lui)echo_rect}};
cursor.x +=dx;
cursor.y +=dy;
XcharsCommand(&base,(void **) &cursor);
return(SUCCESS);
}
#define incr(a,m) a= (a+1) & m
#define decr(a,m) a= (a-1) & m

void handle_char(PIE ie)
{
char ch[2];
switch(ie->code) {
case KEY_LEFT:
decr(char_cursor,MASKLINE);
IO_Cursor(-1,0);
break;
case KEY_RIGHT:
incr(char_cursor,MASKLINE);
IO_Cursor(1,0);
break;
case KEY_DOWN:
while(strings[line_cursor] != '\n')
{decr(line_cursor,MASKSRC);}
char_cursor=0;
IO_Echo(strings+line_cursor);
break;
case KEY_UP:
while(strings[line_cursor] != '\n')
{incr(line_cursor,MASKSRC);}
char_cursor=0;
IO_Echo(strings+line_cursor);
break;
case KEY_ENTER:
strings[char_cursor]=0;
args[argc]=strings+line_cursor;
ExecCommand(&argc,args);
incr(line_cursor,MASKSRC);
write(FD_Scroll,strings+line_cursor,char_cursor);
char_cursor=0;
break;
default:
if(!is_char_key(ie->code)) break;
ch[0] = (char)code_to_ascii(ie->code);
ch[1]='\n';
IO_Echo(ch);
strings[strings_index] = ch[0];
incr(char_cursor,MASKLINE);
break;
}
}

// This tracker is just discoveryand messing
// around, and last on piority
float pos[2]={0.,0.};
float  vel[2]={0.,0.};
float  acc[2]={0.,0.};
float rate[2] = {300.0, .75};
float prev[2]={0.,0.};
float sigma;
int handle_mouse(PIE ie) {
int ibuf= ie->code & 1;
sigma = (1.0-rate[2]) * (1.0-rate[2])/2;
acc[ibuf] = ie->value - prev[ibuf];
prev[ibuf]=ie->value;
vel[ibuf]=rate[1] * vel[ibuf] + sigma * acc[ibuf];
pos[ibuf]=pos[ibuf] + rate[0] * vel[ibuf];
if(IO_SIG & IO_MOUSE)  {
printf("code %s  ", (ie->code ? "Dy " : "Dx "));
printf("P %8.0f V %6.2f A %6.2f",pos[ibuf],vel[ibuf],acc[ibuf]);
printf(" value %d\n",ie->value);
}
return(SUCCESS);
}
void setup(char * argv) {
if(*argv ) IO_SIG |= atoi( argv);
putstr(IO_VERSION);
putstr( ( (IO_SIG & IO_MOUSE) ?
"Verbose Mouse" : ((IO_SIG & IO_KEYS) ?
"Verbose keys"  :
"Unknown flag") ));
printf("Rates %6.2f %6.2f %xf\n",rate[0],rate[1],IO_SIG);
}
int DefaultReturn(int * argc,void * args[]) {
putstr("DefaultReurn\n");
return(SUCCESS);
}
int Init(int * argc, Bind * c) {
int base;
base = *argc;
ExecCommand = c->exec;
if(!(XcharsCommand = arg_key(c->entry).entry))
XcharsCommand = DefaultReturn;
*argc=base+3;
FD_Scroll = open("./flusher", O_WRONLY | O_NONBLOCK);
// Open the mouse and keyord
fxd= FD_XCB;
fmd = open(fmouse,O_RDONLY | O_NONBLOCK);
if(fmd < 0) erck(fmd);
int fkd = open(fkeyboard,O_RDONLY | O_NONBLOCK);
if(fkd < 0) erck(fkd);
setup(c->flag);
return(SUCCESS);
}

int IOLoop() {
IE ie;
int count=0;
int test_count=0;
int xcb_count=0;
int ikey,imouse,idraw;
while(1) {
count = (count + 1) &  0xf;
if( (  (  imouse = event(fmd,&ie)  ) <= 0) && // mouser
(  (  ikey = event(fkd,&ie)  ) <= 0) && // keyboard
(  (  idraw = event(fxd,&ie) ) )  // xchars poll
   )
{ // simple, general purpose, multi count sampler
usleep(TIMEOUT);
if(!--test_count) {
test_count=TEST_RATE;
IO_SIG |= IO_TEST;
} else
if(!(--xcb_count)) {
xcb_count=XCB_RATE;
IO_SIG |= IO_XCB;
}
continue;
}
// hardly tested, barely working tracker
if( imouse > 0 && (ie.type == EV_REL)){
handle_mouse(&ie);
imouse=0;
if(ikey > 0 && (ie.type == EV_KEY) )
handle_char(&ie);
ikey=0;
}
}
perror("My fail");
}

// Old fashioned, simple look up for three commnds

int io( int *argc, void * args[]) {
if(!strcmp(args[*argc],"Init")) return(Init(argc,(Bind *) args));
if(!strcmp(args[*argc],"IOLoop")) return(IOLoop());
return(NOTFOUND);
}

// Mr. Kernc, you are my hero, thanks
/*
  Copyleft (ɔ) 2009 Kernc
  This program is free software. It comes with absolutely no warranty whatsoever.
  See COPYING for further information.
 
  Project homepage: https://github.com/kernc/logkeys
*/

// these are ordered default US keymap keys
wchar_t char_keys[49] =  L"1234567890-=qwertyuiop[]asdfghjkl;'`\\zxcvbnm,./<";
wchar_t shift_keys[49] = L"!@#$%^&*()_+QWERTYUIOP{}ASDFGHJKL:\"~|ZXCVBNM<>?>";
wchar_t altgr_keys[49] = {0}; // old, US don't use AltGr key: L"\0@\0$\0\0{[]}\\\0qwertyuiop\0~asdfghjkl\0\0\0\0zxcvbnm\0\0\0|";  // \0 on no symbol; as obtained by `loadkeys us`
// TODO: add altgr_shift_keys[] (http://en.wikipedia.org/wiki/AltGr_key#US_international)

wchar_t func_keys[][8] = {
  L"<Esc>", L"<BckSp>", L"<Tab>", L"<Enter>", L"<LCtrl>", L"<LShft>", L"<RShft>", L"<KP*>", L"<LAlt>", L" ", L"<CpsLk>", L"<F1>", L"<F2>", L"<F3>", L"<F4>", L"<F5>",
  L"<F6>", L"<F7>", L"<F8>", L"<F9>", L"<F10>", L"<NumLk>", L"<ScrLk>", L"<KP7>", L"<KP8>", L"<KP9>", L"<KP->", L"<KP4>", L"<KP5>", L"<KP6>", L"<KP+>", L"<KP1>",
  L"<KP2>", L"<KP3>", L"<KP0>", L"<KP.>", /*"<",*/ L"<F11>", L"<F12>", L"<KPEnt>", L"<RCtrl>", L"<KP/>", L"<PrtSc>", L"<AltGr>", L"<Break>" /*linefeed?*/, L"<Home>", L"<Up>", L"<PgUp>",
  L"<Left>", L"<Right>", L"<End>", L"<Down>", L"<PgDn>", L"<Ins>", L"<Del>", L"<Pause>", L"<LMeta>", L"<RMeta>", L"<Menu>"
};

const char char_or_func[] =  // c = character key, f = function key, _ = blank/error ('_' is used, don't change); all according to KEY_* defines from <linux/input.h>
  "_fccccccccccccff"
  "ccccccccccccffcc"
  "ccccccccccfccccc"
  "ccccccffffffffff"
  "ffffffffffffffff"
  "ffff__cff_______"
  "ffffffffffffffff"
  "_______f_____fff";
#define N_KEYS_DEFINED 106  // sum of all 'c' and 'f' chars in char_or_func[]

inline bool is_char_key(unsigned int code)
{
  assert(code < sizeof(char_or_func));
  return (char_or_func[code] == 'c');
}

inline bool is_func_key(unsigned int code)
{
  assert(code < sizeof(char_or_func));
  return (char_or_func[code] == 'f');
}

inline bool is_used_key(unsigned int code)
{
  assert(code < sizeof(char_or_func));
  return (char_or_func[code] != '_');
}

// translates character keycodes to continuous array indexes
inline int to_char_keys_index(unsigned int keycode)
{
  if (keycode >= KEY_1 && keycode <= KEY_EQUAL)  // keycodes 2-13: US keyboard: 1, 2, ..., 0, -, =
    return keycode - 2;
  if (keycode >= KEY_Q && keycode <= KEY_RIGHTBRACE)  // keycodes 16-27: q, w, ..., [, ]
    return keycode - 4;
  if (keycode >= KEY_A && keycode <= KEY_GRAVE)  // keycodes 30-41: a, s, ..., ', `
    return keycode - 6;
  if (keycode >= KEY_BACKSLASH && keycode <= KEY_SLASH)  // keycodes 43-53: \, z, ..., ., /
    return keycode - 7;
 
  if (keycode == KEY_102ND) return 47;  // key right to the left of 'Z' on US layout
 
  return -1;  // not character keycode
}

// translates function keys keycodes to continuous array indexes
inline int to_func_keys_index(unsigned int keycode)
{
  if (keycode == KEY_ESC)  // 1
    return 0;
  if (keycode >= KEY_BACKSPACE && keycode <= KEY_TAB)  // 14-15
    return keycode - 13;
  if (keycode >= KEY_ENTER && keycode <= KEY_LEFTCTRL)  // 28-29
    return keycode - 25;
  if (keycode == KEY_LEFTSHIFT) return keycode - 37;  // 42
  if (keycode >= KEY_RIGHTSHIFT && keycode <= KEY_KPDOT)  // 54-83
    return keycode - 48;
  if (keycode >= KEY_F11 && keycode <= KEY_F12)  // 87-88
    return keycode - 51;
  if (keycode >= KEY_KPENTER && keycode <= KEY_DELETE)  // 96-111
    return keycode - 58;
  if (keycode == KEY_PAUSE)  // 119
    return keycode - 65;
  if (keycode >= KEY_LEFTMETA && keycode <= KEY_COMPOSE)  // 125-127
    return keycode - 70;
 
  return -1;  // not function key keycode
}

int code_to_ascii(unsigned int keycode) {
int index =  to_char_keys_index(keycode);
return(char_keys[index]);
}


#ifdef TEST
int EntryTest(int * argc, void *args[]) {
while(*args[*argc]) puts(args[(*argc)++]);
return(SUCCESS);
}
int main(){
Bind b;
int base =0;
memset(0,&b,izeof(Bind);
b.exec=EntryTest;
Init(&base,&b);
IO_Loop();
putstr(IO_VERSION);}
#endif
/*
 *
// This is just a diagnstic scanner, not production

int codes[40]; // diagnstics only
int codes_index=0;
int types[40];
int types_index=0;

int addcode(unsigned short type, unsigned short code) {
int i;
int st;
st=1;

for(i=0;i < codes_index;i++)
if(code==codes[i]) st=0;
if(codes_index == 40) st=0;
if(st == 1) {
codes[codes_index]=code;
codes_index++;
}
for(i=0;i < types_index;i++)
if(type==types[i]) return(st);
if(types_index == 40) return(st);
types[types_index]=type;
types_index++;
return(st+1);
}
* */

No comments: