int GpmMouse;
#endif
-int CurrentVT;
+int CurrentVT = 0;
int ConsoleFD = -1;
int KeyboardModifiers;
int KeyRepeatMode = GLUT_KEY_REPEAT_DEFAULT;
-/* only display the mouse if there is a registered callback for it */
-int MouseEnabled = 0;
+int MouseVisible = 0;
+int LastMouseTime = 0;
static int OldKDMode = -1;
-static int OldMode;
+static int OldMode = KD_TEXT;
static struct vt_mode OldVTMode;
static struct termios OldTermios;
static int kbdpipe[2];
+static int LastStdinKeyTime, LastStdinSpecialKey = -1, LastStdinCode = -1;
+
#define MODIFIER(mod) \
KeyboardModifiers = release ? KeyboardModifiers & ~mod \
: KeyboardModifiers | mod;
vts and kill it without Alt-SysRq hack */
static void KeyboardHandler(int sig)
{
- int release, labelval;
unsigned char code;
- struct kbentry entry;
-
- if(read(ConsoleFD, &code, 1) != 1)
- return;
-
- release = code & 0x80;
-
- entry.kb_index = code & 0x7F;
- entry.kb_table = 0;
-
- if (ioctl(ConsoleFD, KDGKBENT, &entry) < 0) {
- sprintf(exiterror, "ioctl(KDGKBENT) failed.\n");
- exit(0);
- }
- labelval = entry.kb_value;
+ while(read(ConsoleFD, &code, 1) == 1) {
+ int release, labelval;
+ struct kbentry entry;
+ static int lalt; /* only left alt does vt switch */
+
+ release = code & 0x80;
+
+ entry.kb_index = code & 0x7F;
+ entry.kb_table = 0;
+
+ if (ioctl(ConsoleFD, KDGKBENT, &entry) < 0) {
+ sprintf(exiterror, "ioctl(KDGKBENT) failed.\n");
+ exit(0);
+ }
- switch(labelval) {
- case K_SHIFT:
- case K_SHIFTL:
- MODIFIER(GLUT_ACTIVE_SHIFT);
- return;
- case K_CTRL:
- MODIFIER(GLUT_ACTIVE_CTRL);
- return;
- case K_ALT:
- case K_ALTGR:
- MODIFIER(GLUT_ACTIVE_ALT);
- return;
- }
+ labelval = entry.kb_value;
+
+ switch(labelval) {
+ case K_SHIFT:
+ case K_SHIFTL:
+ MODIFIER(GLUT_ACTIVE_SHIFT);
+ continue;
+ case K_CTRL:
+ MODIFIER(GLUT_ACTIVE_CTRL);
+ continue;
+ case K_ALT:
+ lalt = !release;
+ case K_ALTGR:
+ MODIFIER(GLUT_ACTIVE_ALT);
+ continue;
+ }
- if(!release && labelval >= K_F1 && labelval <= K_F12)
- if(KeyboardModifiers & GLUT_ACTIVE_ALT) {
+ if(lalt && !release) {
/* VT switch, we must do it */
- if(Swapping)
- VTSwitch = labelval - K_F1 + 1;
- else
- if(ioctl(ConsoleFD, VT_ACTIVATE, labelval - K_F1 + 1) < 0)
- sprintf(exiterror, "Error switching console\n");
- return;
+ int vt = -1;
+ struct vt_stat st;
+ if(labelval >= K_F1 && labelval <= K_F12)
+ vt = labelval - K_F1 + 1;
+
+ if(labelval == K_LEFT)
+ if(ioctl(ConsoleFD, VT_GETSTATE, &st) >= 0)
+ vt = st.v_active - 1;
+
+ if(labelval == K_RIGHT)
+ if(ioctl(ConsoleFD, VT_GETSTATE, &st) >= 0)
+ vt = st.v_active + 1;
+
+ if(vt != -1) {
+ if(Swapping)
+ VTSwitch = vt;
+ else
+ if(ioctl(ConsoleFD, VT_ACTIVATE, vt) < 0)
+ sprintf(exiterror, "Error switching console\n");
+ continue;
+ }
}
- write(kbdpipe[1], &code, 1);
+ write(kbdpipe[1], &code, 1);
+ }
}
static void LedModifier(int led, int release)
KeyboardLedState ^= led;
releaseflag &= ~led;
}
+
ioctl(ConsoleFD, KDSKBLED, KeyboardLedState);
ioctl(ConsoleFD, KDSETLED, 0x80);
}
+static void HandleKeyPress(unsigned char key, int up)
+{
+ if(up) {
+ if(KeyboardUpFunc)
+ KeyboardUpFunc(key, MouseX, MouseY);
+ } else
+ if(KeyboardFunc)
+ KeyboardFunc(key, MouseX, MouseY);
+ else
+ if(key == 27)
+ exit(0); /* no handler, to provide a way to exit */
+}
+
+static void HandleSpecialPress(int key, int up)
+{
+ if(up) {
+ if(SpecialUpFunc)
+ SpecialUpFunc(key, MouseX, MouseY);
+ } else
+ if(SpecialFunc)
+ SpecialFunc(key, MouseX, MouseY);
+}
+
+static void ReleaseStdinKey(void)
+{
+ if(LastStdinSpecialKey != -1) {
+ HandleSpecialPress(LastStdinSpecialKey, 1);
+ LastStdinSpecialKey = -1;
+ }
+ if(LastStdinCode != -1) {
+ HandleKeyPress(LastStdinCode, 1);
+ LastStdinCode = -1;
+ }
+}
+
#define READKEY read(kbdpipe[0], &code, 1)
static int ReadKey(void)
{
- int release, labelval;
+ int release, labelval, labelvalnoshift;
unsigned char code;
int specialkey = 0;
struct kbentry entry;
- if(READKEY != 1)
+ if(READKEY != 1) {
+ /* if we are reading from stdin, we detect key releases when the key
+ does not repeat after a given timeout */
+ if(ConsoleFD == 0 && LastStdinKeyTime + 100 < glutGet(GLUT_ELAPSED_TIME))
+ ReleaseStdinKey();
return 0;
+ }
+
if(code == 0)
return 0;
KeyboardModifiers = 0;
altset:
if(code == 27 && READKEY == 1) {
- switch(code) {
- case 79: /* function key */
- READKEY;
- if(code == 50) {
- READKEY;
- shiftfunc:
- KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
- specialkey = GLUT_KEY_F1 + code - 53;
- READKEY;
- } else {
- READKEY;
- specialkey = GLUT_KEY_F1 + code - 80;
- }
- break;
- case 91:
- READKEY;
- switch(code) {
- case 68:
- specialkey = GLUT_KEY_LEFT; break;
- case 65:
- specialkey = GLUT_KEY_UP; break;
- case 67:
- specialkey = GLUT_KEY_RIGHT; break;
- case 66:
- specialkey = GLUT_KEY_DOWN; break;
- case 53:
- specialkey = GLUT_KEY_PAGE_UP; READKEY; break;
- case 54:
- specialkey = GLUT_KEY_PAGE_DOWN; READKEY; break;
- case 49:
- specialkey = GLUT_KEY_HOME; READKEY; break;
- case 52:
- specialkey = GLUT_KEY_END; READKEY; break;
- case 50:
- READKEY;
- if(code != 126)
- goto shiftfunc;
- specialkey = GLUT_KEY_INSERT;
- break;
- case 51:
- code = '\b'; goto stdkey;
- case 91:
- READKEY;
- specialkey = GLUT_KEY_F1 + code - 65;
- break;
- default:
- return 0;
- }
- break;
- default:
+ if(code != 91) {
KeyboardModifiers |= GLUT_ACTIVE_ALT;
goto altset;
}
+ READKEY;
+ switch(code) {
+ case 68:
+ specialkey = GLUT_KEY_LEFT; break;
+ case 65:
+ specialkey = GLUT_KEY_UP; break;
+ case 67:
+ specialkey = GLUT_KEY_RIGHT; break;
+ case 66:
+ specialkey = GLUT_KEY_DOWN; break;
+ case 52:
+ specialkey = GLUT_KEY_END; READKEY; break;
+ case 53:
+ specialkey = GLUT_KEY_PAGE_UP; READKEY; break;
+ case 54:
+ specialkey = GLUT_KEY_PAGE_DOWN; READKEY; break;
+ case 49:
+ READKEY;
+ if(code == 126)
+ specialkey = GLUT_KEY_HOME;
+ else {
+ specialkey = GLUT_KEY_F1 + code - 50;
+ READKEY;
+ }
+ break;
+ case 50:
+ READKEY;
+ if(code == 126)
+ specialkey = GLUT_KEY_INSERT;
+ else {
+ if(code > '1')
+ code--;
+ if(code > '6')
+ code--;
+ if(code > '3') {
+ KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
+ code -= 12;
+ }
+ specialkey = GLUT_KEY_F1 + code - 40;
+ READKEY;
+ }
+ break;
+ case 51:
+ READKEY;
+ if(code == 126) {
+ code = '\b';
+ goto stdkey;
+ }
+ KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
+ specialkey = GLUT_KEY_F1 + code - 45;
+ READKEY;
+ break;
+ case 91:
+ READKEY;
+ specialkey = GLUT_KEY_F1 + code - 65;
+ break;
+ default:
+ return 0;
+ }
}
- stdkey:
+
if(specialkey) {
- if(SpecialFunc)
- SpecialFunc(specialkey, MouseX, MouseY);
+ LastStdinKeyTime = glutGet(GLUT_ELAPSED_TIME);
+
+ if(LastStdinSpecialKey != specialkey) {
+ ReleaseStdinKey();
+ HandleSpecialPress(specialkey, 0);
+ LastStdinSpecialKey = specialkey;
+ LastStdinKeyTime += 200; /* initial repeat */
+ } else
+ if(KeyRepeatMode != GLUT_KEY_REPEAT_OFF)
+ HandleSpecialPress(specialkey, 0);
} else {
- if(code >= 1 && code <= 26) {
+ if(code >= 1 && code <= 26 && code != '\r') {
KeyboardModifiers |= GLUT_ACTIVE_CTRL;
code += 'a' - 1;
}
|| (code == 95) || (code >= 123 && code <= 126))
KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
- if(KeyboardFunc)
- KeyboardFunc(code, MouseX, MouseY);
+ stdkey:
+ LastStdinKeyTime = glutGet(GLUT_ELAPSED_TIME);
+ if(LastStdinCode != code) {
+ ReleaseStdinKey();
+ HandleKeyPress(code, 0);
+ LastStdinCode = code;
+ LastStdinKeyTime += 200; /* initial repeat */
+ } else
+ if(KeyRepeatMode != GLUT_KEY_REPEAT_OFF)
+ HandleSpecialPress(code, 0);
}
return 1;
}
entry.kb_index = code;
entry.kb_table = 0;
+ if (ioctl(ConsoleFD, KDGKBENT, &entry) < 0) {
+ sprintf(exiterror, "ioctl(KDGKBENT) failed.\n");
+ exit(0);
+ }
+
+ labelvalnoshift = entry.kb_value;
+
if(KeyboardModifiers & GLUT_ACTIVE_SHIFT)
entry.kb_table |= K_SHIFTTAB;
labelval = entry.kb_value;
- switch(labelval) {
+ switch(labelvalnoshift) {
case K_CAPS:
LedModifier(LED_CAP, release);
return 0;
if(KeyboardLedState & LED_SCR)
return 0;
- if(labelval >= K_F1 && labelval <= K_F12)
- specialkey = GLUT_KEY_F1 + labelval - K_F1;
+ if(labelvalnoshift >= K_F1 && labelvalnoshift <= K_F12)
+ specialkey = GLUT_KEY_F1 + labelvalnoshift - K_F1;
else
- switch(labelval) {
+ switch(labelvalnoshift) {
case K_LEFT:
specialkey = GLUT_KEY_LEFT; break;
case K_UP:
case K_INSERT:
specialkey = GLUT_KEY_INSERT; break;
case K_REMOVE:
- labelval = '\b'; break;
+ labelval = '\b';
+ break;
case K_ENTER:
- labelval = '\n'; break;
+ labelval = '\r'; break;
}
+ /* likely a keypad input, but depends on keyboard mapping, ignore */
+ if(labelval == 512)
+ return 1;
+
/* dispatch callback */
- if(specialkey) {
- if(release) {
- if(SpecialUpFunc)
- SpecialUpFunc(specialkey, MouseX, MouseY);
- } else
- if(SpecialFunc)
- SpecialFunc(specialkey, MouseX, MouseY);
- } else {
+ if(specialkey)
+ HandleSpecialPress(specialkey, release);
+ else {
char c = labelval;
if(KeyboardLedState & LED_CAP) {
if(c >= 'a' && c <= 'z')
c += 'A' - 'a';
}
- if(release) {
- if(KeyboardUpFunc)
- KeyboardUpFunc(c, MouseX, MouseY);
- } else
- if(KeyboardFunc)
- KeyboardFunc(c, MouseX, MouseY);
+ HandleKeyPress(c, release);
}
return 1;
}
dy = event.dy;
} else
#endif
- {
- char data[4];
+ {
+ char data[4];
- if(MouseFD == -1)
- return 0;
+ if(MouseFD == -1)
+ return 0;
- if(fcntl(MouseFD, F_SETFL, O_NONBLOCK) == -1) {
- close(MouseFD);
- MouseFD = -1;
- return 0;
- }
-
- if(read(MouseFD, data, 4) != 4)
- return 0;
+ if(read(MouseFD, data, 4) != 4)
+ return 0;
- l = ((data[0] & 0x20) >> 3);
- m = ((data[3] & 0x10) >> 3);
- r = ((data[0] & 0x10) >> 4);
+ l = ((data[0] & 0x20) >> 3);
+ m = ((data[3] & 0x10) >> 3);
+ r = ((data[0] & 0x10) >> 4);
- dx = (((data[0] & 0x03) << 6) | (data[1] & 0x3F));
- dy = (((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
- }
+ dx = (((data[0] & 0x03) << 6) | (data[1] & 0x3F));
+ dy = (((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
+ }
MouseX += dx * MouseSpeed;
if(MouseX < 0)
ll = l, lm = m, lr = r;
- if(dx || dy) {
+ if(dx || dy || !MouseVisible) {
if(l || m || r) {
if(MotionFunc)
MotionFunc(MouseX, MouseY);
EraseCursor();
+ MouseVisible = 1;
+
if(ActiveMenu)
Redisplay = 1;
else
SwapCursor();
}
+ LastMouseTime = glutGet(GLUT_ELAPSED_TIME);
+
return 1;
}
if(ConsoleFD != -1)
while(ReadKey());
- if(MouseEnabled)
- while(ReadMouse());
+ while(ReadMouse());
+
+ /* implement a 2 second timeout on the mouse */
+ if(MouseVisible && glutGet(GLUT_ELAPSED_TIME) - LastMouseTime > 2000) {
+ EraseCursor();
+ MouseVisible = 0;
+ SwapCursor();
+ }
}
static void VTSwitchHandler(int sig)
if(st.v_active)
ioctl(ConsoleFD, VT_RELDISP, VT_ACKACQ);
- /* this is a hack to turn the cursor off */
- ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo);
-
RestoreColorMap();
Active = 1;
VisibleSwitch = 1;
Redisplay = 1;
-
break;
}
}
signal(SIGIO, SIG_IGN);
- /* save old terminos settings */
- if (tcgetattr(0, &OldTermios) < 0) {
- sprintf(exiterror, "tcgetattr failed\n");
- exit(0);
- }
-
- tio = OldTermios;
-
- /* terminos settings for straight-through mode */
- tio.c_lflag &= ~(ICANON | ECHO | ISIG);
- tio.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
- tio.c_iflag |= IGNBRK;
-
- tio.c_cc[VMIN] = 0;
- tio.c_cc[VTIME] = 0;
-
- if (tcsetattr(0, TCSANOW, &tio) < 0) {
- sprintf(exiterror, "tcsetattr failed\n");
- exit(0);
- }
-
- if(fcntl(0, F_SETFL, O_NONBLOCK | O_ASYNC) < 0) {
- sprintf(exiterror, "Failed to set keyboard to non-blocking\n");
- exit(0);
- }
-
Active = 1;
if(usestdin) {
ConsoleFD = 0;
- return;
+ goto setattribs;
}
/* detect the current vt if it was not specified */
sprintf(exiterror, "Failed to open /dev/tty\n");
exit(0);
}
+
if(ioctl(fd, VT_GETSTATE, &st) == -1) {
fprintf(stderr, "Could not detect current vt, specify with -vt\n");
fprintf(stderr, "Defaulting to stdin input\n");
ConsoleFD = 0;
close(fd);
- return;
- } else
- CurrentVT = st.v_active;
+ goto setattribs;
+ }
+ CurrentVT = st.v_active;
close(fd);
}
+ /* if we close with the modifier set in glutIconifyWindow, we won't
+ get the signal when they are released, so set to zero here */
+ KeyboardModifiers = 0;
+
/* open the console tty */
sprintf(console, "/dev/tty%d", CurrentVT);
ConsoleFD = open(console, O_RDWR | O_NDELAY, 0);
sprintf(exiterror, "error couldn't open %s,"
" defaulting to stdin \n", console);
ConsoleFD = 0;
- return;
+ goto setattribs;
}
signal(SIGUSR1, VTSwitchHandler);
sprintf(exiterror,"Failed to grab %s, defaulting to stdin\n", console);
close(ConsoleFD);
ConsoleFD = 0;
- return;
+ goto setattribs;
}
vt = OldVTMode;
exit(0);
}
- fcntl(0, F_SETOWN, getpid());
+ fcntl(ConsoleFD, F_SETOWN, getpid());
if(ioctl(ConsoleFD, KDGETMODE, &OldMode) < 0)
sprintf(exiterror, "Warning: Failed to get terminal mode\n");
if(ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0)
sprintf(exiterror,"Warning: Failed to set terminal to graphics\n");
-
- if (ioctl(ConsoleFD, KDSKBMODE, K_MEDIUMRAW) < 0) {
+ if(ioctl(ConsoleFD, KDSKBMODE, K_MEDIUMRAW) < 0) {
sprintf(exiterror, "ioctl KDSKBMODE failed!\n");
- tcsetattr(0, TCSANOW, &OldTermios);
exit(0);
}
- if( ioctl(ConsoleFD, KDGKBLED, &KeyboardLedState) < 0) {
+ if(ioctl(ConsoleFD, KDGKBLED, &KeyboardLedState) < 0) {
sprintf(exiterror, "ioctl KDGKBLED failed!\n");
exit(0);
}
+
+ setattribs:
+ /* enable async input input */
+ if(fcntl(ConsoleFD, F_SETFL, O_ASYNC) < 0) {
+ sprintf(exiterror, "Failed to set O_ASYNC mode on fd %d\n", ConsoleFD);
+ exit(0);
+ }
+
+ /* save old terminos settings */
+ if (tcgetattr(ConsoleFD, &OldTermios) < 0) {
+ sprintf(exiterror, "tcgetattr failed\n");
+ exit(0);
+ }
+
+ tio = OldTermios;
+
+ /* terminos settings for straight-through mode */
+ tio.c_lflag &= ~(ICANON | ECHO | ISIG);
+ tio.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
+ tio.c_iflag |= IGNBRK;
+
+ tio.c_cc[VMIN] = 0;
+ tio.c_cc[VTIME] = 0;
+
+ if (tcsetattr(ConsoleFD, TCSANOW, &tio) < 0) {
+ sprintf(exiterror, "tcsetattr failed\n");
+ exit(0);
+ }
}
void RestoreVT(void)
if(ConsoleFD < 0)
return;
- if (tcsetattr(0, TCSANOW, &OldTermios) < 0)
- fprintf(stderr, "tcsetattr failed\n");
+ if (tcsetattr(ConsoleFD, TCSANOW, &OldTermios) < 0)
+ sprintf(exiterror, "tcsetattr failed\n");
+
+ /* setting the mode to text from graphics restores the colormap */
+ if(
+#ifdef HAVE_GPM
+ !GpmMouse ||
+#endif
+ ConsoleFD == 0)
+ if(ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0)
+ goto skipioctl; /* no need to fail twice */
+
+ if(ioctl(ConsoleFD, KDSETMODE, OldMode) < 0)
+ fprintf(stderr, "ioctl KDSETMODE failed!\n");
+
+ skipioctl:
if(ConsoleFD == 0)
return;
if (ioctl(ConsoleFD, KDSKBMODE, OldKDMode) < 0)
fprintf(stderr, "ioctl KDSKBMODE failed!\n");
-
- if(ioctl(ConsoleFD, KDSETMODE, OldMode) < 0)
- fprintf(stderr, "ioctl KDSETMODE failed!\n");
-
+
close(ConsoleFD);
+
+ close(kbdpipe[0]);
+ close(kbdpipe[1]);
}
void InitializeMouse(void)
const char *mousedev = getenv("MOUSE");
if(!mousedev)
mousedev = MOUSEDEV;
- if((MouseFD = open(mousedev, O_RDONLY)) >= 0) {
- if(!MouseSpeed)
- MouseSpeed = 1;
- NumMouseButtons = 3;
- return;
+ if((MouseFD = open(mousedev, O_RDONLY | O_NONBLOCK)) >= 0) {
+ if(!MouseSpeed)
+ MouseSpeed = 1;
+ NumMouseButtons = 3;
+ return;
}
}
#ifdef HAVE_GPM