summaryrefslogtreecommitdiffstats
path: root/src/glut/fbdev/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glut/fbdev/input.c')
-rw-r--r--src/glut/fbdev/input.c759
1 files changed, 759 insertions, 0 deletions
diff --git a/src/glut/fbdev/input.c b/src/glut/fbdev/input.c
new file mode 100644
index 00000000000..b1362245f2f
--- /dev/null
+++ b/src/glut/fbdev/input.c
@@ -0,0 +1,759 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ * Copyright (C) 1995-2006 Brian Paul
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Library for glut using mesa fbdev driver
+ *
+ * Written by Sean D'Epagnier (c) 2006
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <inttypes.h>
+
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/kd.h>
+
+#include <linux/keyboard.h>
+#include <linux/fb.h>
+#include <linux/vt.h>
+
+#include <GL/glut.h>
+
+#include "internal.h"
+
+#define MOUSEDEV "/dev/gpmdata"
+
+#ifdef HAVE_GPM
+#include <gpm.h>
+int GpmMouse;
+#endif
+
+int CurrentVT;
+int ConsoleFD = -1;
+
+int KeyboardModifiers;
+
+int MouseX, MouseY;
+int NumMouseButtons;
+
+double MouseSpeed = 0;
+
+int KeyRepeatMode = GLUT_KEY_REPEAT_DEFAULT;
+
+/* only display the mouse if there is a registered callback for it */
+int MouseEnabled = 0;
+
+static int OldKDMode = -1;
+static int OldMode = KD_TEXT;
+static struct vt_mode OldVTMode;
+static struct termios OldTermios;
+
+static int KeyboardLedState;
+
+static int MouseFD;
+
+static int kbdpipe[2];
+
+#define MODIFIER(mod) \
+ KeyboardModifiers = release ? KeyboardModifiers & ~mod \
+ : KeyboardModifiers | mod;
+
+/* signal handler attached to SIGIO on keyboard input, vt
+ switching and modifiers is handled in the signal handler
+ other keypresses read from a pipe that leaves the handler
+ if a program locks up the glut loop, you can still switch
+ vts and kill it without Alt-SysRq hack */
+static void KeyboardHandler(int sig)
+{
+ int release, labelval;
+ unsigned char code;
+ struct kbentry entry;
+ static int lalt; /* only left alt does vt switch */
+
+ 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;
+
+ switch(labelval) {
+ case K_SHIFT:
+ case K_SHIFTL:
+ MODIFIER(GLUT_ACTIVE_SHIFT);
+ return;
+ case K_CTRL:
+ MODIFIER(GLUT_ACTIVE_CTRL);
+ return;
+ case K_ALT:
+ lalt = !release;
+ case K_ALTGR:
+ MODIFIER(GLUT_ACTIVE_ALT);
+ return;
+ }
+
+ if(lalt && !release) {
+ /* VT switch, we must do it */
+ 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");
+ return;
+ }
+ }
+ write(kbdpipe[1], &code, 1);
+}
+
+static void LedModifier(int led, int release)
+{
+ static int releaseflag = K_CAPS | K_NUM | K_HOLD;
+ if(release)
+ releaseflag |= led;
+ else
+ if(releaseflag & led) {
+ KeyboardLedState ^= led;
+ releaseflag &= ~led;
+ }
+ ioctl(ConsoleFD, KDSKBLED, KeyboardLedState);
+ ioctl(ConsoleFD, KDSETLED, 0x80);
+}
+
+#define READKEY read(kbdpipe[0], &code, 1)
+static int ReadKey(void)
+{
+ int release, labelval, labelvalnoshift;
+ unsigned char code;
+ int specialkey = 0;
+ struct kbentry entry;
+
+ if(READKEY != 1)
+ return 0;
+ if(code == 0)
+ return 0;
+
+ /* stdin input escape code based */
+ if(ConsoleFD == 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:
+ KeyboardModifiers |= GLUT_ACTIVE_ALT;
+ goto altset;
+ }
+ }
+ stdkey:
+ if(specialkey) {
+ if(SpecialFunc)
+ SpecialFunc(specialkey, MouseX, MouseY);
+ } else {
+ if(code >= 1 && code <= 26 && code != '\r') {
+ KeyboardModifiers |= GLUT_ACTIVE_CTRL;
+ code += 'a' - 1;
+ }
+ if((code >= 43 && code <= 34) || (code == 60)
+ || (code >= 62 && code <= 90) || (code == 94)
+ || (code == 95) || (code >= 123 && code <= 126))
+ KeyboardModifiers |= GLUT_ACTIVE_SHIFT;
+
+ if(KeyboardFunc)
+ KeyboardFunc(code, MouseX, MouseY);
+ }
+ return 1;
+ }
+
+ /* linux kbd reading */
+ release = code & 0x80;
+ code &= 0x7F;
+
+ if(KeyRepeatMode == GLUT_KEY_REPEAT_OFF) {
+ static char keystates[128];
+ if(release)
+ keystates[code] = 0;
+ else {
+ if(keystates[code])
+ return 1;
+ keystates[code] = 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;
+
+ if (ioctl(ConsoleFD, KDGKBENT, &entry) < 0) {
+ sprintf(exiterror, "ioctl(KDGKBENT) failed.\n");
+ exit(0);
+ }
+
+ labelval = entry.kb_value;
+
+ switch(labelvalnoshift) {
+ case K_CAPS:
+ LedModifier(LED_CAP, release);
+ return 0;
+ case K_NUM:
+ LedModifier(LED_NUM, release);
+ return 0;
+ case K_HOLD: /* scroll lock suspends glut */
+ LedModifier(LED_SCR, release);
+ while(KeyboardLedState & LED_SCR) {
+ usleep(10000);
+ ReadKey();
+ }
+ return 0;
+ }
+
+ /* we could queue keypresses here */
+ if(KeyboardLedState & LED_SCR)
+ return 0;
+
+ if(labelvalnoshift >= K_F1 && labelvalnoshift <= K_F12)
+ specialkey = GLUT_KEY_F1 + labelvalnoshift - K_F1;
+ else
+ switch(labelvalnoshift) {
+ case K_LEFT:
+ specialkey = GLUT_KEY_LEFT; break;
+ case K_UP:
+ specialkey = GLUT_KEY_UP; break;
+ case K_RIGHT:
+ specialkey = GLUT_KEY_RIGHT; break;
+ case K_DOWN:
+ specialkey = GLUT_KEY_DOWN; break;
+ case K_PGUP:
+ specialkey = GLUT_KEY_PAGE_UP; break;
+ case K_PGDN:
+ specialkey = GLUT_KEY_PAGE_DOWN; break;
+ case K_FIND:
+ specialkey = GLUT_KEY_HOME; break;
+ case K_SELECT:
+ specialkey = GLUT_KEY_END; break;
+ case K_INSERT:
+ specialkey = GLUT_KEY_INSERT; break;
+ case K_REMOVE:
+ labelval = '\b';
+ break;
+ case K_ENTER:
+ case K_ENTER - 1: /* keypad enter */
+ labelval = '\n'; break;
+ }
+
+ /* dispatch callback */
+ if(specialkey) {
+ if(release) {
+ if(SpecialUpFunc)
+ SpecialUpFunc(specialkey, MouseX, MouseY);
+ } else
+ if(SpecialFunc)
+ SpecialFunc(specialkey, MouseX, MouseY);
+ } else {
+ char c = labelval;
+
+ if(KeyboardLedState & LED_CAP) {
+ if(c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ else
+ if(c >= 'a' && c <= 'z')
+ c += 'A' - 'a';
+ }
+ if(release) {
+ if(KeyboardUpFunc)
+ KeyboardUpFunc(c, MouseX, MouseY);
+ } else
+ if(KeyboardFunc)
+ KeyboardFunc(c, MouseX, MouseY);
+ }
+ return 1;
+}
+
+void glutIgnoreKeyRepeat(int ignore)
+{
+ KeyRepeatMode = ignore ? GLUT_KEY_REPEAT_OFF : GLUT_KEY_REPEAT_ON;
+}
+
+void glutSetKeyRepeat(int repeatMode)
+{
+ KeyRepeatMode = repeatMode;
+}
+
+void glutForceJoystickFunc(void)
+{
+}
+
+static void HandleMousePress(int button, int pressed)
+{
+ if(TryMenu(button, pressed))
+ return;
+
+ if(MouseFunc)
+ MouseFunc(button, pressed ? GLUT_DOWN : GLUT_UP, MouseX, MouseY);
+}
+
+static int ReadMouse(void)
+{
+ int l, r, m;
+ static int ll, lm, lr;
+ signed char dx, dy;
+
+#ifdef HAVE_GPM
+ if(GpmMouse) {
+ Gpm_Event event;
+ struct pollfd pfd;
+ pfd.fd = gpm_fd;
+ pfd.events = POLLIN;
+ if(poll(&pfd, 1, 1) != 1)
+ return 0;
+
+ if(Gpm_GetEvent(&event) != 1)
+ return 0;
+
+ l = event.buttons & GPM_B_LEFT;
+ m = event.buttons & GPM_B_MIDDLE;
+ r = event.buttons & GPM_B_RIGHT;
+
+ /* gpm is weird in that it gives a button number when the button
+ is released, with type set to GPM_UP, this is only a problem
+ if it is the last button released */
+
+ if(event.type & GPM_UP)
+ if(event.buttons == GPM_B_LEFT || event.buttons == GPM_B_MIDDLE ||
+ event.buttons == GPM_B_RIGHT || event.buttons == GPM_B_FOURTH)
+ l = m = r = 0;
+
+ dx = event.dx;
+ dy = event.dy;
+ } else
+#endif
+ {
+ char data[4];
+
+ 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;
+
+ 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));
+ }
+
+ MouseX += dx * MouseSpeed;
+ if(MouseX < 0)
+ MouseX = 0;
+ else
+ if(MouseX >= VarInfo.xres)
+ MouseX = VarInfo.xres - 1;
+
+ MouseY += dy * MouseSpeed;
+ if(MouseY < 0)
+ MouseY = 0;
+ else
+ if(MouseY >= VarInfo.yres)
+ MouseY = VarInfo.yres - 1;
+
+ if(l != ll)
+ HandleMousePress(GLUT_LEFT_BUTTON, l);
+ if(m != lm)
+ HandleMousePress(GLUT_MIDDLE_BUTTON, m);
+ if(r != lr)
+ HandleMousePress(GLUT_RIGHT_BUTTON, r);
+
+ ll = l, lm = m, lr = r;
+
+ if(dx || dy) {
+ if(l || m || r) {
+ if(MotionFunc)
+ MotionFunc(MouseX, MouseY);
+ } else
+ if(PassiveMotionFunc)
+ PassiveMotionFunc(MouseX, MouseY);
+
+ EraseCursor();
+
+ if(ActiveMenu)
+ Redisplay = 1;
+ else
+ SwapCursor();
+ }
+
+ return 1;
+}
+
+void ReceiveInput(void)
+{
+ if(ConsoleFD != -1)
+ while(ReadKey());
+
+ if(MouseEnabled)
+ while(ReadMouse());
+}
+
+static void VTSwitchHandler(int sig)
+{
+ struct vt_stat st;
+ switch(sig) {
+ case SIGUSR1:
+ ioctl(ConsoleFD, VT_RELDISP, 1);
+ Active = 0;
+#ifdef MULTIHEAD
+ VisiblePoll = 1;
+ TestVisible();
+#else
+ VisibleSwitch = 1;
+ Visible = 0;
+#endif
+ break;
+ case SIGUSR2:
+ ioctl(ConsoleFD, VT_GETSTATE, &st);
+ 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;
+ Visible = 1;
+ VisibleSwitch = 1;
+
+ Redisplay = 1;
+
+ break;
+ }
+}
+
+void InitializeVT(int usestdin)
+{
+ struct termios tio;
+ struct vt_mode vt;
+ char console[128];
+
+ 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;
+ }
+
+ /* detect the current vt if it was not specified */
+ if(CurrentVT == 0) {
+ int fd = open("/dev/tty", O_RDWR | O_NDELAY, 0);
+ struct vt_stat st;
+ if(fd == -1) {
+ 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;
+
+ close(fd);
+ }
+
+ /* open the console tty */
+ sprintf(console, "/dev/tty%d", CurrentVT);
+ ConsoleFD = open(console, O_RDWR | O_NDELAY, 0);
+ if (ConsoleFD < 0) {
+ sprintf(exiterror, "error couldn't open %s,"
+ " defaulting to stdin \n", console);
+ ConsoleFD = 0;
+ return;
+ }
+
+ signal(SIGUSR1, VTSwitchHandler);
+ signal(SIGUSR2, VTSwitchHandler);
+
+ if (ioctl(ConsoleFD, VT_GETMODE, &OldVTMode) < 0) {
+ sprintf(exiterror,"Failed to grab %s, defaulting to stdin\n", console);
+ close(ConsoleFD);
+ ConsoleFD = 0;
+ return;
+ }
+
+ vt = OldVTMode;
+
+ vt.mode = VT_PROCESS;
+ vt.waitv = 0;
+ vt.relsig = SIGUSR1;
+ vt.acqsig = SIGUSR2;
+ if (ioctl(ConsoleFD, VT_SETMODE, &vt) < 0) {
+ sprintf(exiterror, "error: ioctl(VT_SETMODE) failed: %s\n",
+ strerror(errno));
+ close(ConsoleFD);
+ ConsoleFD = 0;
+ exit(1);
+ }
+
+ if (ioctl(ConsoleFD, KDGKBMODE, &OldKDMode) < 0) {
+ sprintf(exiterror, "Warning: ioctl KDGKBMODE failed!\n");
+ OldKDMode = K_XLATE;
+ }
+
+ /* use SIGIO so VT switching can work if the program is locked */
+ signal(SIGIO, KeyboardHandler);
+
+ pipe(kbdpipe);
+
+ if(fcntl(kbdpipe[0], F_SETFL, O_NONBLOCK | O_ASYNC) < 0) {
+ sprintf(exiterror, "Failed to set keyboard to non-blocking\n");
+ exit(0);
+ }
+
+ fcntl(0, F_SETOWN, getpid());
+
+ if(ioctl(ConsoleFD, KDGETMODE, &OldMode) < 0)
+ sprintf(exiterror, "Warning: Failed to get terminal mode\n");
+
+#ifdef HAVE_GPM
+ if(!GpmMouse)
+#endif
+ if(ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0)
+ sprintf(exiterror,"Warning: Failed to set terminal to graphics\n");
+
+ 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) {
+ sprintf(exiterror, "ioctl KDGKBLED failed!\n");
+ exit(0);
+ }
+}
+
+void RestoreVT(void)
+{
+ if(ConsoleFD < 0)
+ return;
+
+ if (tcsetattr(0, TCSANOW, &OldTermios) < 0)
+ fprintf(stderr, "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) {
+ sprintf(exiterror,"Warning: Failed to set terminal to graphics\n");
+ goto skipioctl; /* no need to fail twice */
+ }
+
+ if(ioctl(ConsoleFD, KDSETMODE, OldMode) < 0)
+ fprintf(stderr, "ioctl KDSETMODE failed!\n");
+
+ skipioctl:
+
+ if(ConsoleFD == 0)
+ return;
+
+ /* restore keyboard state */
+ if (ioctl(ConsoleFD, VT_SETMODE, &OldVTMode) < 0)
+ fprintf(stderr, "Failed to set vtmode\n");
+
+ if (ioctl(ConsoleFD, KDSKBMODE, OldKDMode) < 0)
+ fprintf(stderr, "ioctl KDSKBMODE failed!\n");
+
+ close(ConsoleFD);
+}
+
+void InitializeMouse(void)
+{
+#ifdef HAVE_GPM
+ if(!GpmMouse)
+#endif
+ {
+ const char *mousedev = getenv("MOUSE");
+ if(!mousedev)
+ mousedev = MOUSEDEV;
+ if((MouseFD = open(mousedev, O_RDONLY)) >= 0) {
+ if(!MouseSpeed)
+ MouseSpeed = 1;
+ NumMouseButtons = 3;
+ return;
+ }
+ }
+#ifdef HAVE_GPM
+ {
+ Gpm_Connect conn;
+ int c;
+ conn.eventMask = ~0; /* Want to know about all the events */
+ conn.defaultMask = 0; /* don't handle anything by default */
+ conn.minMod = 0; /* want everything */
+ conn.maxMod = ~0; /* all modifiers included */
+ if(Gpm_Open(&conn, 0) != -1) {
+ if(!MouseSpeed)
+ MouseSpeed = 8;
+ NumMouseButtons = 3;
+ return;
+ }
+ fprintf(stderr, "Cannot open gpmctl.\n");
+ }
+#endif
+ fprintf(stderr,"Cannot open %s.\n"
+ "Continuing without Mouse\n", MOUSEDEV);
+}
+
+void CloseMouse(void)
+{
+#ifdef HAVE_GPM
+ if(GpmMouse) {
+ if(NumMouseButtons)
+ Gpm_Close();
+ } else
+#endif
+ if(MouseFD >= 0)
+ close(MouseFD);
+}