docs/mindstab.net_blog/resources/ipaq-hx4700/kbd.c

1568 lines
36 KiB
C

/*
* Copyright (C) 2004,2005,2006 Nils Faerber <nils.faerber@kernelconcepts.de>
* Parts for Stowaway (c) 2005 by Paul Eggleton
* See README for other authors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <linux/apm_bios.h>
#ifdef USELIRC
#include <lirc_client.h>
#endif
#include "keyboards.h"
#include "dev_uinput.h"
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
char debug = 0;
int uindev = 0;
static int reinit = 0;
#define DEFAULT_TTS "/dev/ttyS0"
char TTY_PORT[PATH_MAX] = DEFAULT_TTS;
void handle_sigterm(int signal)
{
dev_uinput_close(uindev);
exit(EXIT_SUCCESS);
}
int open_serial(char *port, speed_t baud)
{
int fd, res;
struct termios ssetup;
fd=open(port, O_RDWR /*| O_NONBLOCK*/);
if (fd <= 0) {
perror("open serial");
fprintf(stderr,"opening %s failed\n", port);
return (-1);
}
res = tcgetattr(fd, &ssetup);
if (res < 0) {
perror("tcgetattr");
return (-1);
}
ssetup.c_iflag = 0L;
ssetup.c_oflag = 0L;
ssetup.c_cflag &= ~(CSTOPB|PARENB|CRTSCTS);
ssetup.c_cflag |= (CS8|CLOCAL);
ssetup.c_lflag = 0L;
ssetup.c_cc[VTIME] = 0;
ssetup.c_cc[VMIN] = 1;
cfsetispeed(&ssetup, baud);
cfsetospeed(&ssetup, baud);
res=tcsetattr(fd, TCSANOW, &ssetup);
if (res < 0) {
perror("tcsetattr");
return (-1);
}
return (fd);
}
#ifdef USELIRC
int lirc(char *progname)
{
struct lirc_config *config;
if (debug)
fprintf(stderr, "progname %s\n",progname);
if (lirc_init(progname,1) == -1) {
printf("failed to init lirc\n");
exit(EXIT_FAILURE);
}
if (debug)
fprintf(stderr, "in lirc\n");
if (lirc_readconfig(NULL,&config,NULL) == 0) {
int i, ret;
char *code, *c;
while (lirc_nextcode(&code) == 0) {
if (code == NULL)
continue;
while ((ret = lirc_code2char(config, code, &c)) == 0 &&
c != NULL) {
sscanf(c,"%x",&i);
if (debug)
fprintf(stderr, "%s %u\n",c,i);
dev_uinput_key(uindev, i, KEY_PRESSED);
dev_uinput_key(uindev, i, KEY_RELEASED);
if (debug)
fprintf(stderr, "Code : %s\n",c);
}
free(code);
if (ret == -1)
break;
}
lirc_freeconfig(config);
}
return lirc_deinit();
}
#endif
int compaq_foldable(void)
{
int fd;
unsigned char buf[16];
char fn=0;
fd = open_serial(TTY_PORT, B4800);
if (fd <= 0)
return (-1);
while (fd > 0) {
read (fd, buf, 2);
// fprintf(stderr, "0x%02x 0x%02x 0x%02x | ", buf[0], buf[1], ~buf[0]);
if (buf[0] == (unsigned char)~buf[1]) {
if (debug) fprintf(stderr, "press: %d ", buf[0]);
if (buf[0] == 0x02) {
fn=1;
continue;
}
if (fn)
buf[0] = foldable_function[buf[0]];
else
buf[0] = foldable_normal[buf[0]];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] > 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
} else if (((unsigned char)buf[0] & (unsigned char)~0x80) == (unsigned char)~buf[1]) {
if (debug)
fprintf(stderr, "rel. : %d ", buf[0] & ~0x80);
if ((buf[0] & ~0x80) == 0x02) {
fn = 0;
continue;
}
if (fn)
buf[0] = foldable_function[(unsigned char)buf[0] & (unsigned char)~0x80];
else
buf[0] = foldable_normal[(unsigned char)buf[0] & (unsigned char)~0x80];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] > 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
}
}
return 0;
}
int lastChar = 0;
char shiftState = 0;
char altState = 0;
char ctrlState = 0;
//struct timeval tvlast;
//unsigned char lastkey;
int belkin_infrared(void)
{
int fd;
//unsigned char buf[16];
unsigned char buf;
unsigned char key;
unsigned int key_down;
unsigned int key_state;
unsigned char keycode;
int isChar = 0;
//struct timeval tv;
// gettimeofday(&tv, NULL);
fd = open_serial(TTY_PORT, B9600);
if (fd <= 0)
return (-1);
while (fd > 0) {
// read (fd, buf, 2);
// key = buf[1] & 0x7f;
// key_down = !(buf[1] & 0x80);
read (fd, &buf, 1);
key = buf & 0x7f;
key_down = !(buf & 0x80);
// keycode = belkin_irda_normal[key];
keycode = key;
switch (keycode) {
case 81: keycode = 16; break; //q -
case 87: keycode = 17; break; //w -
case 69: keycode = 18; break; //e -
case 82: keycode = 19; break; //r -
case 84: keycode = 20; break; //t -
case 89: keycode = 21; break; //y -
case 85: keycode = 22; break; //u -
case 73: keycode = 23; break; //i -
case 79: keycode = 24; break; //o -
case 80: keycode = 25; break; //p -
case 91: keycode = 26; break; //[ -
case 93: keycode = 27; break; //] -
case 13: keycode = 28; break; // ret -
case 94: keycode = 30; break; //a -
case 83: keycode = 31; break; //s -
case 68: keycode = 32; break; //d -
case 70: keycode = 33; break; //f -
case 71: keycode = 34; break; //g -
case 72: keycode = 35; break; //h
case 74: keycode = 36; break; //j -
case 75: keycode = 37; break; //k -
case 76: keycode = 38; break; //l -
case 59: keycode = 39; break; //;
case 44: keycode = 40; break; //' -
case 90: keycode = 44; break; //z -
case 88: keycode = 45; break; //x -
case 67: keycode = 46; break; //c -
case 86: keycode = 47; break; //v
case 66: keycode = 48; break; //b
case 78: keycode = 49; break; //n
case 77: keycode = 50; break; //m
case 60: keycode = 51; break; //,<
case 46: keycode = 52; break; //.>
case 47: keycode = 53; break; // /? -
case 27: keycode = 1; break; // til
case 49: keycode = 2; break; // 1
case 50: keycode = 3; break; // 2
case 51: keycode = 4; break; // 3
case 52: keycode = 5; break; // 4
case 53: keycode = 6; break; // 5
case 54: keycode = 7; break; // 6
case 55: keycode = 8; break; // 7
case 56: keycode = 9; break; // 8
case 57: keycode = 10; break; // 9
case 48: keycode = 11; break; // 0
case 45: keycode = 12; break; // -
case 61: keycode = 13; break; //-=
case 8: keycode = 14; break; // bkspace
case 9: keycode = 15; break; // tab
case 20: keycode = 58; break; // caps lock
case 16: // shift l -
case 18: keycode = 42;
break; // shift r
case 17: keycode = 29;
break; // ctrl
case 29: keycode = 56;
break; // alt
case 32: keycode = 57; break; // space -
case 33: keycode = 57; break; // space -
case 92: keycode = 43; break; // backslash bar -
case 19: keycode = 111; break; // del
case 37: keycode = 103; break; // right
case 38: keycode = 105; break; // up
case 39: keycode = 108; break; // left
case 40: keycode = 106; break; // down
//default: keycode =0; break;
//case 79: keycode = 24; break;
}
if ( /*(keycode >= 2 && keycode <=13) || */(keycode >= 16 && keycode <= 25)
|| (keycode >= 30 && keycode <= 38) || (keycode >= 44 && keycode <= 50))
{
isChar = 1;
if (debug && isChar) fprintf (stderr, "is char\n");
}
//if (debug)
// fprintf(stderr, "ctrl:%d alt:%d shift:%d\n", ctrlState, altState, shiftState);
// if (! isChar) {
if ( key_down )
key_state = KEY_PRESSED;
else
key_state = KEY_RELEASED;
if (lastChar == 64)
key_state = KEY_RELEASED;
if (debug)
fprintf(stderr,"event %d %d\n", key_state, keycode);
dev_uinput_key(uindev, (unsigned short)keycode, key_state);
lastChar = keycode;
/* } else {
if (! key_down && keycode == lastChar) {
if (shiftState) {
if (debug) fprintf(stderr,"release %d\n", 14);
dev_uinput_key(uindev, (unsigned short)14, KEY_RELEASED);
} else if (ctrlState || altState) {
if (debug) fprintf(stderr,"release %d\n", 19);
dev_uinput_key(uindev, (unsigned short)19, KEY_RELEASED);
}
if (debug && keycode)
fprintf(stderr,"press %d\n", keycode);
dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED);
if (debug && keycode)
fprintf(stderr,"release %d\n", keycode);
dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED);
if (debug && keycode)
fprintf(stderr,"release %d\n", keycode);
dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED);
}
lastChar = keycode;
}*/
}
return 0;
}
int freedom_keyboard(void)
{
int fd;
unsigned char buf[16];
unsigned char key;
unsigned int key_down;
unsigned char keycode;
fd = open_serial(TTY_PORT, B9600);
if (fd <= 0)
return (-1);
while (fd > 0) {
read (fd, buf, 1);
key = buf[0];
//keyboard sends n when pressing a key
// and n+63 when releasing the key
key_down = ( key < 63 );
if (!key_down)
key = (key-63)&0x3F; // convert key code for key up
keycode = freedom_kbd[key];
if (debug)
fprintf(stdout, "0x%02x 0x%02x\n", buf[0], keycode);
if ( key_down ) {
if (debug)
fprintf(stdout,"press %d\n", keycode);
dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED);
} else {
if (debug)
fprintf(stdout,"release %d\n", keycode);
dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED);
}
}
return 0;
}
int select_read(int fd, int timeout_sec, int timeout_us)
{
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = timeout_sec;
tv.tv_usec = timeout_us;
return select(fd+1, &fds, NULL, NULL, &tv);
}
int stowaway_init(int fd)
{
int status;
unsigned char buf[16];
ioctl(fd, TIOCMGET, &status);
status |= TIOCM_DTR; /* Set DTR */
status &= ~TIOCM_RTS; /* Clear RTS */
ioctl(fd, TIOCMSET, &status);
/* Unfortunately, DCD seems to be high all of the time on H3900, so the following can't be used */
/* ioctl(fd, TIOCMIWAIT, TIOCM_CAR */
/* So we just wait instead */
usleep(1000000);
ioctl(fd, TIOCMGET, &status);
status |= TIOCM_RTS; /* Set RTS */
ioctl(fd, TIOCMSET, &status);
/* Stowaway will send back 0xFA 0xFD indicating successful init */
if (select_read(fd, 2, 0)) {
read(fd, buf, 2);
if ((buf[0] == 0xFA) && (buf[0] == 0xFD))
if (debug)
fprintf(stderr, "keyboard initialised\n");
}
return 0;
}
int open_apm(void)
{
int fd;
fd = open( "/dev/apm_bios", O_RDONLY | O_NONBLOCK );
if (fd <= 0)
return -1;
return fd;
}
int check_apm_resume(int fd)
{
apm_event_t ev;
int resumed;
resumed = 0;
while (read(fd, &ev, sizeof(apm_event_t)) > 0) {
if (ev == APM_NORMAL_RESUME)
resumed = 1;
}
return resumed;
}
void stowaway_sig(int sig)
{
reinit = 1;
}
int stowaway(void)
{
int fd, apm_fd;
unsigned char buf[16];
char fn=0;
struct sigaction act;
int rc;
fd = open_serial(TTY_PORT, B9600);
if (fd <= 0)
return (-1);
/* Make SIGHUP cause a reinit of the keyboard */
act.sa_handler = stowaway_sig;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGHUP, &act, NULL);
/* Open APM so we can listen for resume events */
apm_fd = open_apm();
while (fd > 0) {
stowaway_init(fd);
while (fd > 0) {
rc = select_read(fd, 0, 100000);
if (rc == -1) {
if (reinit) {
reinit = 0;
break;
} else {
perror("select");
return 1;
}
} else if (rc == 0) {
/* Timeout expired with nothing read, do APM resume check */
if ((apm_fd > 0) && (check_apm_resume(apm_fd)))
break;
continue;
}
rc = read (fd, buf, 1);
if (rc == -1) {
if (reinit) {
reinit = 0;
break;
} else {
perror("read");
return 1;
}
}
if ( ((unsigned char)buf[0] & (unsigned char)0x80) == 0 ) {
if (debug)
fprintf(stderr, "press: %d\n", buf[0]);
if (buf[0] == 0x08) {
fn = 1;
continue;
}
if (fn)
buf[0] = stowaway_function[buf[0]];
else
buf[0] = stowaway_normal[buf[0]];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] > 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
} else {
if (debug)
fprintf(stderr, "rel. : %d\n", buf[0] & ~0x80);
if ((buf[0] & ~0x80) == 0x08) {
fn = 0;
continue;
}
if (fn)
buf[0] = stowaway_function[(unsigned char)buf[0] & (unsigned char)~0x80];
else
buf[0] = stowaway_normal[(unsigned char)buf[0] & (unsigned char)~0x80];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] > 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
}
}
}
return 0;
}
int stowawayxt(void)
{
#define STOWAWAYXT_GR_FN 33
#define STOWAWAYXT_BL_FN 34
int fd, apm_fd;
unsigned char buf[16];
char bluefn=0,greenfn=0;
struct sigaction act;
int rc;
fd = open_serial(TTY_PORT, B9600);
if (fd <= 0)
return (-1);
/* Make SIGHUP cause a reinit of the keyboard */
act.sa_handler = stowaway_sig;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGHUP, &act, NULL);
/* Open APM so we can listen for resume events */
apm_fd = open_apm();
while (fd > 0) {
stowaway_init(fd);
while (fd > 0) {
rc = select_read(fd, 0, 100000);
if (rc == -1) {
if (reinit) {
reinit = 0;
break;
} else {
perror("select");
return 1;
}
} else if (rc == 0) {
/* Timeout expired with nothing read, do APM resume check */
if ((apm_fd > 0) && (check_apm_resume(apm_fd)))
break;
continue;
}
rc = read (fd, buf, 1);
if (rc == -1) {
if (reinit) {
reinit = 0;
break;
} else {
perror("read");
return 1;
}
}
if ( ((unsigned char)buf[0] & (unsigned char)0x80) == 0 ) {
/* KEY PRESSED */
if (debug)
fprintf(stderr, "press: %d\n", buf[0]);
if (buf[0] == STOWAWAYXT_BL_FN) {
bluefn = 1;
continue;
}
if (buf[0] == STOWAWAYXT_GR_FN) {
greenfn = 1;
dev_uinput_key(uindev,42,KEY_PRESSED);
continue;
}
if (bluefn)
buf[0] = stowawayxt_function[buf[0]];
else if (greenfn) {
buf[0] = stowawayxt_function[buf[0]];
/* fixup where green function is not shift blue function */
switch (buf[0]) {
case KEY_UP:
buf[0] = KEY_PAGEUP;
break;
case KEY_LEFT:
buf[0] = KEY_HOME;
break;
case KEY_DOWN:
buf[0] = KEY_PAGEDOWN;
break;
case KEY_RIGHT:
buf[0] = KEY_END;
break;
case KEY_INTL2:
buf[0] = KEY_INTL3;
break;
} /* /switch */
} else
buf[0]=stowawayxt_normal[buf[0]];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] != KEY_RESERVED)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
} else {
/* KEY RELEASED */
if (debug)
fprintf(stderr, "rel. : %d\n", buf[0] & ~0x80);
if ((buf[0] & ~0x80) == STOWAWAYXT_BL_FN) {
bluefn = 0;
continue;
}
if ((buf[0] & ~0x80) == STOWAWAYXT_GR_FN) {
greenfn = 0;
dev_uinput_key(uindev,42,KEY_RELEASED);
continue;
}
if (bluefn)
buf[0] = stowawayxt_function[(unsigned char) buf[0] & (unsigned char)~0x80];
else if (greenfn) {
buf[0] = stowawayxt_function[(unsigned char) buf[0] & (unsigned char)~0x80];
/* fixup where green function is not shift blue function */
switch(buf[0]) {
case KEY_UP:
buf[0] = KEY_PAGEUP;
break;
case KEY_LEFT:
buf[0] = KEY_HOME;
break;
case KEY_DOWN:
buf[0] = KEY_PAGEDOWN;
break;
case KEY_RIGHT:
buf[0] = KEY_END;
break;
case KEY_INTL2:
buf[0] = KEY_INTL3;
break;
} /* /switch */
} else
buf[0] = stowawayxt_normal[(unsigned char)buf[0] & (unsigned char)~0x80];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] != KEY_RESERVED)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
}
}
}
return 0;
}
int snapntype(void)
{
int fd;
unsigned char buf[16];
char symb=0;
fd = open_serial(TTY_PORT, B2400);
while (fd > 0) {
read (fd, buf, 1);
if (debug)
fprintf(stderr, "got %d\n", buf[0]);
if (buf[0] & 0x80) { /* release */
read(fd,buf+1,1);
buf[0] = buf[0] & 0x7f;
if (buf[0] == 27) {
symb = 0;
continue;
}
if (symb)
buf[0] = snapntype_symbol[buf[0]];
else
buf[0] = snapntype_normal[buf[0]];
if (debug)
fprintf(stderr, " release %d\n", buf[0]);
if (buf[0] != 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
} else { /* press */
if (buf[0] == 27) {
symb=1;
continue;
}
if (symb)
buf[0] = snapntype_symbol[buf[0]];
else
buf[0] = snapntype_normal[buf[0]];
if (debug)
fprintf(stderr, " press %d\n", buf[0]);
if (buf[0] != 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
}
}
return 0;
}
int snapntypebt(void)
{
int fd;
unsigned char buf[16];
unsigned char key, last_key=0;
unsigned char pressed;
unsigned char fn = 0;
fd = open_serial(TTY_PORT, B9600);
while (fd > 0) {
read (fd, buf, 1);
read (fd, buf+1, 1);
if (debug)
fprintf(stderr, "got %02x%02x\n", buf[0],buf[1]);
if (buf[1] & 0x80) { /* release */
key = buf[1] & 0x7F;
if (key == 30) {
fn = 0;
if (last_key) {
dev_uinput_key(uindev, (unsigned short)snapntypebt_fn[last_key], KEY_RELEASED);
}
continue;
}
pressed = KEY_RELEASED;
if (debug)
fprintf(stderr, " release:");
} else {
key = buf[1];
if (key == 30) {
fn = 1;
last_key = 0;
continue;
}
pressed = KEY_PRESSED;
if (debug)
fprintf(stderr, " press: ");
}
if (debug)
fprintf(stderr, " %d (%d)\n",key,snapntypebt_normal[key]);
if (!fn)
key = snapntypebt_normal[key];
else {
last_key = key;
key = snapntypebt_fn[key];
}
if (key != 0 && !debug)
dev_uinput_key(uindev, (unsigned short)key, pressed);
}
return 0;
}
int hpslim(void)
{
int fd;
unsigned char cin;
unsigned char cnew;
char symb=0;
char shft=0;
char symshft=0;
char numlck=0;
fd = open_serial(TTY_PORT, B4800);
if (fd < 0)
return -1;
for (;;) {
if (read (fd, &cin, 1) < 0) {
perror(TTY_PORT);
return -1;
}
if (debug)
fprintf(stderr, "got %d 0x%x\n", cin,cin);
if (cin & 0x80) { /* release */
cin &= 0x7f;
switch (cin) {
case MKBD_HPS_FNKEY: /* Fn key release */
symb = 0;
continue;
case KEY_LEFTSHIFT:
case KEY_RIGHTSHIFT:
shft = 0;
break;
}
if (symb)
cnew = hpslim_symbol[cin];
else {
/* if numlock, convert QWERTYUIOP to 1-9,0 */
if (numlck && cin >= KEY_Q && cin <= KEY_P)
cnew = cin + KEY_1 - KEY_Q;
else
cnew = hpslim_normal[cin];
}
if (debug)
fprintf(stderr, " release cnew=%d 0x%x\n", cnew,cnew);
if (cnew != 0) {
dev_uinput_key(uindev, (unsigned short)cnew, KEY_RELEASED);
if (symshft)
dev_uinput_key(uindev, (unsigned short)KEY_RIGHTSHIFT, KEY_RELEASED);
symshft = 0;
// toggle numlck on release
if (cnew == KEY_NUMLOCK) numlck = !numlck;
}
} else { /* press */
switch (cin) {
case MKBD_HPS_FNKEY: /* Fn key press */
symb = 1;
continue;
case KEY_LEFTSHIFT:
case KEY_RIGHTSHIFT:
shft = 1;
break;
}
if (symb) {
/* if shift needed to get correct char */
symshft = hpslim_symshft[cin] && !shft;
cnew = hpslim_symbol[cin];
} else {
/* if numlock, convert QWERTYUIOP to 1-9,0 */
if (numlck && cin >= KEY_Q && cin <= KEY_P)
cnew = cin + KEY_1 - KEY_Q;
else
cnew = hpslim_normal[cin];
}
if (debug)
fprintf(stderr, " press cnew=%d 0x%x\n", cnew,cnew);
if (cnew != 0) {
if (symshft)
dev_uinput_key(uindev, (unsigned short)KEY_RIGHTSHIFT, KEY_PRESSED);
dev_uinput_key(uindev, (unsigned short)cnew, KEY_PRESSED);
}
}
}
return 0;
}
int smartbt(void)
{
int fd;
unsigned char buf[16];
fd = open_serial(TTY_PORT, B2400);
while (fd > 0) {
read (fd, buf, 1);
if (buf[0] > 126) {
if (debug)
fprintf(stderr, "error: unexpected char %d\n", buf[0]);
continue;
}
if (buf[0] > 63) {
/* release */
buf[0] = buf[0] - 63;
if (debug)
fprintf(stderr, "rel.: %d\n", buf[0]);
buf[0] = smartbt_normal[buf[0]];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] > 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
} else {
/* press */
if (debug)
fprintf(stderr, "press: %d\n", buf[0]);
buf[0] = smartbt_normal[buf[0]];
if (debug)
fprintf(stderr,"= 0x%02x\n", buf[0]);
if (buf[0] > 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
}
}
return 0;
}
int flexis(void)
{
int fd;
unsigned char buf[16];
char symb=0;
fd = open_serial(TTY_PORT, B9600);
while (fd > 0) {
read (fd, buf, 1);
if (debug)
fprintf(stderr, "got %d\n", buf[0]);
if (buf[0] & 0x80) { /* key press */
buf[0] = buf[0] & 0x7f;
if (symb)
buf[0] = flexis_fx100_function[buf[0]];
else
buf[0] = flexis_fx100_normal[buf[0]];
/* FIXME: function key */
/* FIXME: this code is a little broken, it should check scancode not keycode for set 1/2 */
if (buf[0] == KEY_LEFTSHIFT || buf[0] == KEY_RIGHTSHIFT ||
buf[0] == KEY_LEFTCTRL || buf[0] == KEY_RIGHTCTRL ||
buf[0] == KEY_LEFTALT || buf[0] == KEY_RIGHTALT ) {
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
} else {
read(fd,buf+1,1);
if (debug)
fprintf(stderr, "got %d\n", buf[1]);
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
}
} else { /* release of key from Set 2 */
if (symb)
buf[0] = flexis_fx100_function[buf[0]];
else
buf[0] = flexis_fx100_normal[buf[0]];
if (buf[0] != 0)
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
}
}
return 0;
}
int benqgamepad(void) {
int fd;
unsigned char buf[16];
int i;
unsigned char keycode;
fd = open_serial(TTY_PORT, B4800);
while (fd > 0) {
keycode = 0;
read (fd, buf, 2);
if (buf[0] & 0x80) { /* release */
if (debug)
fprintf(stderr, "release: %d %d\n", buf[0], buf[1]);
buf[0] = buf[0] & 0x7f;
for (i=0; i<10; i++) {
if (benq_gamepad_map[i][0] == buf[0]) {
keycode = benq_gamepad_map[i][1];
break;
}
}
if (keycode != 0)
dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED);
} else {
if (debug)
fprintf(stderr, "press: %d %d\n", buf[0], buf[1]);
for (i=0; i<10; i++) {
if (benq_gamepad_map[i][0] == buf[0]) {
keycode = benq_gamepad_map[i][1];
break;
}
}
if (keycode != 0)
dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED);
}
}
return 0;
}
int pocketvik(void)
{
int fd;
unsigned char buf[16];
unsigned char mods=0;
int res;
struct termios ssetup;
int i;
fd = open_serial(TTY_PORT, B57600);
/* PocketVIK needs CRTSCTS */
res = tcgetattr(fd, &ssetup);
if (res < 0) {
perror("tcgetattr");
return (-1);
}
ssetup.c_cflag |= CRTSCTS;
res = tcsetattr(fd, TCSANOW, &ssetup);
if (res < 0) {
perror("tcgetattr");
return (-1);
}
while (fd > 0) {
read (fd, buf, 1);
if (debug)
fprintf(stderr, "got %d\n", buf[0]);
if (buf[0] & 0x80) { /* press with modifiers */
mods = buf[0] & 0x7f;
read (fd, buf, 1);
} else
mods = 0;
if (mods & POCKETVIK_Fn)
buf[0] = pocketvik_function[buf[0]];
else
buf[0] = pocketvik_normal[buf[0]];
if (buf[0] != 0) {
if (debug)
fprintf(stderr, "press/release %d\n", buf[0]);
/* Modifiers down */
for ( i = 0 ; i < ARRAY_SIZE(pocketvik_modifiers) ; i++ ) {
if (pocketvik_modifiers[i].mask & mods)
dev_uinput_key(uindev, pocketvik_modifiers[i].key, KEY_PRESSED);
}
/* Key down */
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
/* Key up */
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_RELEASED);
/* Modifiers up */
for (i = 0; i < ARRAY_SIZE(pocketvik_modifiers); i++ ) {
if (pocketvik_modifiers[i].mask & mods)
dev_uinput_key(uindev, pocketvik_modifiers[i].key, KEY_RELEASED);
}
}
}
return 0;
}
int micro_foldaway(void) {
int fd;
unsigned char buf[16];
unsigned char lastkey = 0;
// char symb=0;
int checkkey = 0;
fd = open_serial(TTY_PORT, B9600);
while (fd > 0) {
read (fd, buf, 1);
if (debug)
fprintf(stderr, "got: %d\n", buf[0]);
if (buf[0] & 0x80) { /* possible release */
checkkey = (159 - buf[0]);
if (checkkey > 0 && checkkey <= 4) {
buf[0] = micro_foldaway_normal[159 - buf[0]];
dev_uinput_key(uindev, buf[0], KEY_RELEASED);
} else if (buf[0] == 133 && lastkey > 0) {
dev_uinput_key(uindev, lastkey, KEY_RELEASED);
lastkey = 0;
}
/* Eat repeated code */
read (fd, buf, 1);
} else {
checkkey = buf[0];
/* if (symb)
buf[0] = micro_foldaway_function[buf[0]];
else*/
buf[0] = micro_foldaway_normal[buf[0]];
if (buf[0] != 0) {
if (checkkey > 4)
lastkey = buf[0]; /* Not a modifier, record key */
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
}
}
}
return 0;
}
int micro_datapad(void) {
int fd;
unsigned char buf[16];
unsigned char lastkey = 0;
int checkkey = 0;
fd = open_serial(TTY_PORT, B9600);
while (fd > 0) {
read (fd, buf, 1);
if (debug)
fprintf(stderr, "got: %d\n", buf[0]);
if (buf[0] & 0x80) { /* possible release */
checkkey = (159 - buf[0]);
if (checkkey > 0 && checkkey <= 4) {
buf[0] = micro_foldaway_normal[159 - buf[0]];
dev_uinput_key(uindev, buf[0], KEY_RELEASED);
} else if (buf[0] == 133 && lastkey > 0) {
dev_uinput_key(uindev, lastkey, KEY_RELEASED);
lastkey = 0;
}
/* Eat repeated code */
read (fd, buf, 1);
} else {
checkkey = buf[0];
/* if (symb)
buf[0]=micro_datapad_function[buf[0]];
else*/
buf[0] = micro_datapad_normal[buf[0]];
if (buf[0] != 0) {
if (checkkey > 4)
lastkey = buf[0]; /* Not a modifier, record key */
dev_uinput_key(uindev, (unsigned short)buf[0], KEY_PRESSED);
}
}
}
return 0;
}
int hp_bt_foldable(void){
int fd;
unsigned char buf[1];
unsigned char cnew;
char symb=0;
fd = open_serial(TTY_PORT, B9600);
if (fd < 0)
return -1;
for (;;) {
if (read (fd, buf, 1) < 0) {
perror(TTY_PORT);
return -1;
}
if (debug)
fprintf(stderr, "got %d (0x%x)\n", buf[0], buf[0]);
if (buf[0] & 0x80) { /* release */
buf[0] &= 0x7f;
if (buf[0] == 2) {
symb = 0;
continue;
}
if (symb)
cnew = btfoldable_function[buf[0]];
else
cnew = btfoldable_normal[buf[0]];
if (debug)
fprintf(stderr, " release cnew=%d (0x%x)\n", cnew, cnew);
if (cnew != 0)
dev_uinput_key(uindev, (unsigned short)cnew, KEY_RELEASED);
} else { /* press */
if (buf[0] == 2) {
symb = 1;
continue;
}
if (symb)
cnew = btfoldable_function[buf[0]];
else
cnew = btfoldable_normal[buf[0]];
if (debug)
fprintf(stderr, " press cnew=%d (0x%x)\n", cnew, cnew);
if (cnew != 0)
dev_uinput_key(uindev, (unsigned short)cnew, KEY_PRESSED);
}
}
return 0;
}
int compaq_microkbd(void)
{
int fd;
unsigned char buf[2];
unsigned char cnew;
char symb=0;
fd = open_serial(TTY_PORT, B4800);
if (fd < 0)
return -1;
for (;;) {
if (read (fd, buf, 2) < 0) {
perror(TTY_PORT);
return -1;
}
if (debug)
fprintf(stderr, "got %d %d (0x%x 0x%x)\n", buf[0], buf[1], buf[0], buf[1]);
if (buf[0] & 0x80) { /* release */
buf[0] &= 0x7f;
if (buf[0] == 2) {
symb = 0;
continue;
}
if (symb)
cnew = compaq_function[buf[0]];
else
cnew = compaq_normal[buf[0]];
if (debug)
fprintf(stderr, " release cnew=%d (0x%x)\n", cnew, cnew);
if (cnew != 0)
dev_uinput_key(uindev, (unsigned short)cnew, KEY_RELEASED);
} else { /* press */
if (buf[0] == 2) {
symb = 1;
continue;
}
if (symb)
cnew = compaq_function[buf[0]];
else
cnew = compaq_normal[buf[0]];
if (debug)
fprintf(stderr, " press cnew=%d (0x%x)\n", cnew, cnew);
if (cnew != 0)
dev_uinput_key(uindev, (unsigned short)cnew, KEY_PRESSED);
}
}
return 0;
}
int targus_infrared(void)
{
int fd;
unsigned char buf;
unsigned char key;
unsigned int key_down;
unsigned char keycode;
fd = open_serial(TTY_PORT, B9600);
if (fd <= 0)
return (-1);
while (fd > 0) {
read (fd, &buf, 1);
key = buf & 0x7f;
key_down = !(buf & 0x80);
// keycode = belkin_irda_normal[key];
keycode = key;
if (debug)
fprintf(stderr, "0x%02x 0x%02x\n", buf, key);
if ( key_down ) {
if (debug)
fprintf(stderr,"press %d\n", keycode);
dev_uinput_key(uindev, (unsigned short)keycode, KEY_PRESSED);
} else {
if (debug)
fprintf(stderr,"release %d\n", keycode);
dev_uinput_key(uindev, (unsigned short)keycode, KEY_RELEASED);
}
}
return 0;
}
void print_usage(char *arg0)
{
fprintf (stderr, "kbdd %s\n", VERSION);
fprintf (stderr, "Usage:\n");
fprintf (stderr, "%s [-d] [-h] [-c <config file>] -p <serial-port> -t <kbd type>\n", arg0);
fprintf (stderr, "-d\tenable debugging output\n");
fprintf (stderr, "-h\tprint this help\n");
fprintf (stderr, "-c <config file>\n");
fprintf (stderr, "\tRead port and type from config file\n");
fprintf (stderr, "-p <serial-port>\n");
fprintf (stderr, "\tspecify serial port device, default %s\n", DEFAULT_TTS);
fprintf (stderr, "-t <kbd type>\n");
fprintf (stderr, "\tspecify the serial keyboard type, supported are:\n");
fprintf (stderr, "\tfoldable - Compaq/HP foldable keyboard\n");
fprintf (stderr, "\tstowaway - Targus Stowaway keyboard\n");
fprintf (stderr, "\tstowawayxt - Stowaway XT\n");
fprintf (stderr, "\tsnapntype - Snap'n'Type\n");
fprintf (stderr, "\tsnapntypebt - Snap'n'Type Bluetooth\n");
fprintf (stderr, "\thpslim - HP Slim keyboard\n");
fprintf (stderr, "\tsmartbt - Smart Bluetooth keyboard\n");
fprintf (stderr, "\tlirc - LIRC consumer IR\n");
fprintf (stderr, "\tbelkinir - Belkin IR (not IrDA)\n");
fprintf (stderr, "\tflexis - Flexis FX-100 keyboard\n");
fprintf (stderr, "\tg250 - Benq G250 gamepad\n");
fprintf (stderr, "\tpocketvik - GrandTec PocketVIK\n");
fprintf (stderr, "\tmicrofold - Micro Innovations Foldaway keyboard\n");
fprintf (stderr, "\tmicropad - Micro Innovations Datapad\n");
fprintf (stderr, "\tmicrokbd - Compaq MicroKeyboard\n");
fprintf (stderr, "\ttargusir - Targus Universal Wireless keyboard\n");
fprintf (stderr, "\tbtfoldable - HP iPAQ Bluetooth Foldable Keyboard\n\n");
fprintf (stderr, "\tfreedom - Freedom keyboard\n");
fprintf (stderr, "Example:\n\t%s -t foldable\n", arg0);
}
#define KBD_TYPE_NONE 0
#define KBD_TYPE_FOLDABLE 1
#define KBD_TYPE_SNAPNTYPE 2
#define KBD_TYPE_STOWAWAY 3
#define KBD_TYPE_STOWAWAYXT 4
#define KBD_TYPE_HPSLIM 5
#define KBD_TYPE_SMARTBT 6
#define KBD_TYPE_LIRC 7
#define KBD_TYPE_BELKINIR 8
#define KBD_TYPE_FLEXIS 9
#define KBD_TYPE_BENQ_GAMEPAD 10
#define KBD_TYPE_POCKETVIK 11
#define KBD_TYPE_MICRO_FOLDAWAY 12
#define KBD_TYPE_MICRO_DATAPAD 13
#define KBD_TYPE_COMPAQ_MICROKBD 14
#define KBD_TYPE_TARGUSIR 15
#define KBD_TYPE_SNAPNTYPEBT 16
#define KBD_TYPE_BTFOLDABLE 17
#define KBD_TYPE_FREEDOM 18
int find_kbd_type(const char *ktype)
{
if (strncmp("foldable", ktype, 8) == 0)
return KBD_TYPE_FOLDABLE;
else if (strncmp("snapntypebt", ktype, 11) == 0)
return KBD_TYPE_SNAPNTYPEBT;
else if (strncmp("snapntype", ktype, 9) == 0)
return KBD_TYPE_SNAPNTYPE;
else if (strncmp("stowawayxt", ktype, 10) == 0)
return KBD_TYPE_STOWAWAYXT;
else if (strncmp("stowaway", ktype, 8) == 0)
return KBD_TYPE_STOWAWAY;
else if (strncmp("hpslim", ktype, 6) == 0)
return KBD_TYPE_HPSLIM;
else if (strncmp("smartbt", ktype, 7) == 0)
return KBD_TYPE_SMARTBT;
else if (strncmp("flexis", ktype, 6) == 0)
return KBD_TYPE_FLEXIS;
else if (strncmp("lirc", ktype, 4) == 0)
return KBD_TYPE_LIRC;
else if (strncmp("belkinir", ktype, 8) == 0)
return KBD_TYPE_BELKINIR;
else if (strncmp("g250", ktype, 4) == 0)
return KBD_TYPE_BENQ_GAMEPAD;
else if (strncmp("pocketvik", ktype, 9) == 0)
return KBD_TYPE_POCKETVIK;
else if (strncmp("microfold", ktype, 9) == 0)
return KBD_TYPE_MICRO_FOLDAWAY;
else if (strncmp("micropad", ktype, 8) == 0)
return KBD_TYPE_MICRO_DATAPAD;
else if (strncmp("microkbd", ktype, 8) == 0)
return KBD_TYPE_COMPAQ_MICROKBD;
else if (strncmp("targusir", ktype, 8) == 0)
return KBD_TYPE_TARGUSIR;
else if (strncmp("btfoldable", ktype, 10) == 0)
return KBD_TYPE_BTFOLDABLE;
else if (strncmp("freedom", ktype, 7) == 0)
return KBD_TYPE_FREEDOM;
fprintf(stderr, "unrecognised keyboard type %s\n", ktype);
return KBD_TYPE_NONE;
}
void parse_config(const char *path, int *kbdtype, char port[])
{
char *needle;
FILE *fd;
char buf[PATH_MAX];
fd = fopen(path, "r");
if (!fd) {
fprintf(stderr, "could not open config file %s\n", path);
return;
}
while (!feof(fd)) {
fgets(buf, PATH_MAX, fd);
if (*buf == '#' || *buf == '\0') {
/* It's a comment or a blank line */
continue;
}
if ((needle = strstr(buf, "port:")) != 0) {
needle += 5;
/* Trim whitespaces */
while (isspace(*needle)) {
needle++;
}
while (isspace(needle[strlen(needle)-1])) {
needle[strlen(needle)-1] = '\0';
}
strncpy(port, needle, PATH_MAX);
} else if ((needle = strstr(buf, "type:")) != 0) {
needle += 5;
/* Trim whitespaces */
while (isspace(*needle)) {
needle++;
}
while (isspace(needle[strlen(needle)-1])) {
needle[strlen(needle)-1] = '\0';
}
*kbdtype = find_kbd_type(needle);
}
}
}
int main(int argc, char **argv)
{
int optc;
int kbdtype=KBD_TYPE_NONE;
while ((optc = getopt(argc, argv, "c:t:p:dh")) != -1) {
switch ((char)optc) {
case 'h':
print_usage(argv[0]);
exit(1);
break;
case 'd':
debug = 1;
break;
case 't':
kbdtype = find_kbd_type(optarg);
break;
case 'p':
strncpy(TTY_PORT, optarg, PATH_MAX);
break;
case 'c':
parse_config(optarg, &kbdtype, TTY_PORT);
break;
}
}
if (kbdtype == 0) {
print_usage(argv[0]);
exit(1);
}
uindev = dev_uinput_init();
if (uindev <= 0) {
fprintf(stderr, "init uinput failed\n");
exit (1);
}
signal(SIGTERM, handle_sigterm);
if (kbdtype == KBD_TYPE_FOLDABLE)
compaq_foldable();
else if (kbdtype == KBD_TYPE_BTFOLDABLE)
hp_bt_foldable();
else if (kbdtype == KBD_TYPE_SNAPNTYPE)
snapntype();
else if (kbdtype == KBD_TYPE_SNAPNTYPEBT)
snapntypebt();
else if (kbdtype == KBD_TYPE_STOWAWAY)
stowaway();
else if (kbdtype == KBD_TYPE_STOWAWAYXT)
stowawayxt();
else if (kbdtype == KBD_TYPE_HPSLIM)
hpslim();
else if (kbdtype == KBD_TYPE_SMARTBT)
smartbt();
else if (kbdtype == KBD_TYPE_FLEXIS)
flexis();
else if (kbdtype == KBD_TYPE_BENQ_GAMEPAD)
benqgamepad();
else if (kbdtype == KBD_TYPE_POCKETVIK)
pocketvik();
else if (kbdtype == KBD_TYPE_MICRO_FOLDAWAY)
micro_foldaway();
else if (kbdtype == KBD_TYPE_MICRO_DATAPAD)
micro_datapad();
else if (kbdtype == KBD_TYPE_COMPAQ_MICROKBD)
compaq_microkbd();
else if (kbdtype == KBD_TYPE_LIRC)
#ifdef USELIRC
lirc(basename(argv[0]);
#else
{
fprintf(stderr, "keyboard type 'lirc' is not supported in this version\n");
exit(1);
}
#endif
else if (kbdtype == KBD_TYPE_BELKINIR)
belkin_infrared();
else if (kbdtype == KBD_TYPE_TARGUSIR)
targus_infrared();
else if (kbdtype == KBD_TYPE_FREEDOM)
freedom_keyboard();
return 0;
}