/*
Copyright (c) 2007-2013, John Ryland
*/
#include <oslayer.h>
#include <corelayer.h>
#include <keypad.h>
#include <event.h>
#if defined(ARCH_MacOSX64)
#define VMIN 16 /* !ICANON */
#define VTIME 17 /* !ICANON */
#define NCCS 20
typedef unsigned long tcflag_t;
typedef unsigned char cc_t;
typedef unsigned long speed_t;
struct termios {
tcflag_t c_iflag; /* input flags */
tcflag_t c_oflag; /* output flags */
tcflag_t c_cflag; /* control flags */
tcflag_t c_lflag; /* local flags */
cc_t c_cc[NCCS]; /* control chars */
speed_t c_ispeed; /* input speed */
speed_t c_ospeed; /* output speed */
};
// These are in hex
#define ICANON 0x00000100 /* canonicalize input lines */
#define IGNBRK 0x0000001
#define BRKINT 0x0000002
#define IGNPAR 0x0000004
#define PARMRK 0x0000008
#define INPCK 0x0000010
#define ISTRIP 0x0000020
#define INLCR 0x0000040
#define IGNCR 0x0000080
#define ICRNL 0x0000100
#define IXON 0x0000200
#define IXANY 0x0000800
#define IXOFF 0x0000400
#define IMAXBEL 0x0002000
#define CSIZE 0x0000300
#define CS5 0x0000000
#define CS6 0x0000100
#define CS7 0x0000200
#define CS8 0x0000300
#define CSTOPB 0x0000400
#define CREAD 0x0000800
#define IOCTL_GET_FLAGS 0x40487413
#define IOCTL_SET_FLAGS 0x80487416
#else
// These are in octal - some are same, some are different though
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IXON 0002000
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define IOCTL_GET_FLAGS 0x5405
#define IOCTL_SET_FLAGS 0x5406
#endif
const char *keyTab1[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Backspace", 0,
"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", 0, 0,
"Enter", "Fn", "A", "S", "D", "F", "G", "H", "J", "K", "L",
0, 0, 0, 0, 0, "Z", "X", "C", "V", "B", "N", "M", ",", ".",
0, "Shift", 0, 0, "Space", "Sym", 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, "Num", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, "Up", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, "Right", 0, "Select", 0, 0, 0, "Hold", "Down", 0,
0, 0, 0, "Pwr", 0, 0, 0, 0, 0, 0, 0, 0
};
const char *keyTab2[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Info", 0, "Back",
0, "Home", 0, 0, "Options", "Wireless", "Slide", 0, "Backward",
0, 0, 0, 0, 0, "VolUp", "Play", 0, 0, 0, 0, 0, "VolDn", 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, 0, 0, "Up2", 0, 0, "Left2", 0,
"Right2", 0, 0, "Down2", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Forward", 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Left", 0, 0, 0, 0, 0, 0
};
const char *ttyKeyTab[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Select", 0, 0, "Enter", 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Esc", 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, "Insert", "Delete", 0, "PgUp", "PgDn", 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, "Up", "Down", "Right", "Left", 0, "End", 0, "Home", 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, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
extern int keyFd;
int keyFd;
int haveOriginalFlags = 0;
#if defined(ARCH_MacOSX64)
unsigned long savedFlags[9];
#else
unsigned short savedFlags[12];
#endif
static void preserveFlags()
{
if ( !haveOriginalFlags ) {
haveOriginalFlags = 1;
sysIoctl(keyFd, IOCTL_GET_FLAGS, savedFlags); // Get flags
}
}
static void restoreFlags()
{
if ( haveOriginalFlags ) {
sysIoctl(keyFd, IOCTL_SET_FLAGS, savedFlags); // Set flags
}
/*
#if defined(ARCH_MacOSX64)
unsigned long flags[9];
#else
unsigned short flags[12];
#endif
sysIoctl(keyFd, IOCTL_GET_FLAGS, flags); // Get flags
flags[3] = (flags[3] | 0110) & ~03; // Modify flags
sysIoctl(keyFd, IOCTL_SET_FLAGS, flags); // Set flags
*/
}
static void uncook()
{
#if defined(ARCH_MacOSX64)
preserveFlags();
struct termios tflags;
sysIoctl(keyFd, IOCTL_GET_FLAGS, &tflags);
tflags.c_lflag &= ~(ICANON);
tflags.c_cc[VMIN] = 1;
tflags.c_cc[VTIME] = 0;
//tflags.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
tflags.c_oflag = 0;
//tflags.c_cflag = CREAD | CS8;
tflags.c_lflag = 0;
sysIoctl(keyFd, IOCTL_SET_FLAGS, &tflags);
#else
unsigned short flags[12];
preserveFlags();
//sysIoctl(keyFd, IOCTL_GET_FLAGS, flags); // Get flags
memcpy(flags, savedFlags, 12*sizeof(short));
flags[0] = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
flags[1] = 0;
flags[2] = CREAD | CS8;
flags[3] = 0;
// flags[0] &= ~0002753;
// flags[1] &= ~0000001;
// flags[2] = (flags[2] & ~0000460) | 0000060;
// flags[3] &= ~0100113;
sysIoctl(keyFd, IOCTL_SET_FLAGS, flags); // Set flags
// sysIoctl(0, 0x4B45, 0);
#endif
}
void openKeypad()
{
#if defined(ARCH_ARM)
keyFd = fsOpen("/dev/vc/0", O_RDWR | O_NONBLOCK);
#else
keyFd = fsOpen("/dev/tty", O_RDWR | O_NONBLOCK);
uncook();
#endif
}
void closeKeypad()
{
restoreFlags();
fsClose(keyFd);
}
void readKeyData()
{
unsigned int ch = 0;
while (fsRead(keyFd, &ch, 1) != -1) {
const char *key = 0;
#if defined(ARCH_ARM)
if ((ch & 127) != 96) {
key = keyTab1[ch & 127];
} else {
fsRead(keyFd, &ch, 1);
key = keyTab2[ch & 127];
}
#else
// strPrintf("Got key: %i (%c)\n", ch, ch);
if ( ch == 3 ) {
strPrintf("Got CTRL-C, exiting\n");
restoreFlags();
sysExit(0);
}
char keyBuf[2];
keyBuf[0] = ch;
keyBuf[1] = '\0';
key = ttyKeyTab[ch & 127];
if ( !key )
key = keyBuf;
if (ch == 27) {
key = 0;
fsRead(keyFd, &ch, 1);
fsRead(keyFd, &ch, 1);
key = ttyKeyTab[ch & 127];
if ( !key )
{
strPrintf("Got key: %x (%c)\n", ch, ch);
break;
}
}
#endif
if ( key ) {
Event keyEv;
keyEv.type = KeyEventType;
keyEv.event.keyEvent.desc = key;
keyEv.event.keyEvent.code = ch; // XXX
keyEv.event.keyEvent.pressed = (ch & 128) ? 0 : 1;
eventQueue_AppendEvent(keyEv);
break;
}
}
}