2 * Mesa 3-D graphics library
4 * Copyright (C) 1995-2006 Brian Paul
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Library for glut using mesa fbdev driver
24 * Written by Sean D'Epagnier (c) 2006
37 #include <sys/ioctl.h>
41 #include <linux/keyboard.h>
49 #define MOUSEDEV "/dev/gpmdata"
59 int KeyboardModifiers
;
64 double MouseSpeed
= 0;
66 int KeyRepeatMode
= GLUT_KEY_REPEAT_DEFAULT
;
69 int LastMouseTime
= 0;
71 static int OldKDMode
= -1;
72 static int OldMode
= KD_TEXT
;
73 static struct vt_mode OldVTMode
;
74 static struct termios OldTermios
;
76 static int KeyboardLedState
;
80 static int kbdpipe
[2];
82 static int LastStdinKeyTime
, LastStdinSpecialKey
= -1, LastStdinCode
= -1;
84 #define MODIFIER(mod) \
85 KeyboardModifiers = release ? KeyboardModifiers & ~mod \
86 : KeyboardModifiers | mod;
88 /* signal handler attached to SIGIO on keyboard input, vt
89 switching and modifiers is handled in the signal handler
90 other keypresses read from a pipe that leaves the handler
91 if a program locks up the glut loop, you can still switch
92 vts and kill it without Alt-SysRq hack */
93 static void KeyboardHandler(int sig
)
97 while(read(ConsoleFD
, &code
, 1) == 1) {
98 int release
, labelval
;
100 static int lalt
; /* only left alt does vt switch */
102 release
= code
& 0x80;
104 entry
.kb_index
= code
& 0x7F;
107 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
108 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
112 labelval
= entry
.kb_value
;
117 MODIFIER(GLUT_ACTIVE_SHIFT
);
120 MODIFIER(GLUT_ACTIVE_CTRL
);
125 MODIFIER(GLUT_ACTIVE_ALT
);
129 if(lalt
&& !release
) {
130 /* VT switch, we must do it */
133 if(labelval
>= K_F1
&& labelval
<= K_F12
)
134 vt
= labelval
- K_F1
+ 1;
136 if(labelval
== K_LEFT
)
137 if(ioctl(ConsoleFD
, VT_GETSTATE
, &st
) >= 0)
138 vt
= st
.v_active
- 1;
140 if(labelval
== K_RIGHT
)
141 if(ioctl(ConsoleFD
, VT_GETSTATE
, &st
) >= 0)
142 vt
= st
.v_active
+ 1;
148 if(ioctl(ConsoleFD
, VT_ACTIVATE
, vt
) < 0)
149 sprintf(exiterror
, "Error switching console\n");
153 write(kbdpipe
[1], &code
, 1);
157 static void LedModifier(int led
, int release
)
159 static int releaseflag
= K_CAPS
| K_NUM
| K_HOLD
;
163 if(releaseflag
& led
) {
164 KeyboardLedState
^= led
;
168 ioctl(ConsoleFD
, KDSKBLED
, KeyboardLedState
);
169 ioctl(ConsoleFD
, KDSETLED
, 0x80);
172 static void HandleKeyPress(unsigned char key
, int up
)
176 KeyboardUpFunc(key
, MouseX
, MouseY
);
179 KeyboardFunc(key
, MouseX
, MouseY
);
181 /* there was no keyboard handler to provide a way to exit the program */
186 static void HandleSpecialPress(int key
, int up
)
190 SpecialUpFunc(key
, MouseX
, MouseY
);
193 SpecialFunc(key
, MouseX
, MouseY
);
196 static void ReleaseStdinKey(void)
198 if(LastStdinSpecialKey
!= -1) {
199 HandleSpecialPress(LastStdinSpecialKey
, 1);
200 LastStdinSpecialKey
= -1;
202 if(LastStdinCode
!= -1) {
203 HandleKeyPress(LastStdinCode
, 1);
208 #define READKEY read(kbdpipe[0], &code, 1)
209 static int ReadKey(void)
211 int release
, labelval
, labelvalnoshift
;
214 struct kbentry entry
;
217 /* if we are reading from stdin, we detect key releases when the key
218 does not repeat after a given timeout */
219 if(ConsoleFD
== 0 && LastStdinKeyTime
+ 100 < glutGet(GLUT_ELAPSED_TIME
))
227 /* stdin input escape code based */
229 KeyboardModifiers
= 0;
231 if(code
== 27 && READKEY
== 1) {
233 KeyboardModifiers
|= GLUT_ACTIVE_ALT
;
239 specialkey
= GLUT_KEY_LEFT
; break;
241 specialkey
= GLUT_KEY_UP
; break;
243 specialkey
= GLUT_KEY_RIGHT
; break;
245 specialkey
= GLUT_KEY_DOWN
; break;
247 specialkey
= GLUT_KEY_END
; READKEY
; break;
249 specialkey
= GLUT_KEY_PAGE_UP
; READKEY
; break;
251 specialkey
= GLUT_KEY_PAGE_DOWN
; READKEY
; break;
255 specialkey
= GLUT_KEY_HOME
;
257 specialkey
= GLUT_KEY_F1
+ code
- 50;
264 specialkey
= GLUT_KEY_INSERT
;
271 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
274 specialkey
= GLUT_KEY_F1
+ code
- 40;
284 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
285 specialkey
= GLUT_KEY_F1
+ code
- 45;
290 specialkey
= GLUT_KEY_F1
+ code
- 65;
298 LastStdinKeyTime
= glutGet(GLUT_ELAPSED_TIME
);
300 if(LastStdinSpecialKey
!= specialkey
) {
302 HandleSpecialPress(specialkey
, 0);
303 LastStdinSpecialKey
= specialkey
;
304 LastStdinKeyTime
+= 200; /* initial repeat */
306 if(KeyRepeatMode
!= GLUT_KEY_REPEAT_OFF
)
307 HandleSpecialPress(specialkey
, 0);
309 if(code
>= 1 && code
<= 26 && code
!= '\r') {
310 KeyboardModifiers
|= GLUT_ACTIVE_CTRL
;
313 if((code
>= 43 && code
<= 34) || (code
== 60)
314 || (code
>= 62 && code
<= 90) || (code
== 94)
315 || (code
== 95) || (code
>= 123 && code
<= 126))
316 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
319 LastStdinKeyTime
= glutGet(GLUT_ELAPSED_TIME
);
320 if(LastStdinCode
!= code
) {
322 HandleKeyPress(code
, 0);
323 LastStdinCode
= code
;
324 LastStdinKeyTime
+= 200; /* initial repeat */
326 if(KeyRepeatMode
!= GLUT_KEY_REPEAT_OFF
)
327 HandleSpecialPress(code
, 0);
332 /* linux kbd reading */
333 release
= code
& 0x80;
336 if(KeyRepeatMode
== GLUT_KEY_REPEAT_OFF
) {
337 static char keystates
[128];
347 entry
.kb_index
= code
;
350 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
351 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
355 labelvalnoshift
= entry
.kb_value
;
357 if(KeyboardModifiers
& GLUT_ACTIVE_SHIFT
)
358 entry
.kb_table
|= K_SHIFTTAB
;
360 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
361 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
365 labelval
= entry
.kb_value
;
367 switch(labelvalnoshift
) {
369 LedModifier(LED_CAP
, release
);
372 LedModifier(LED_NUM
, release
);
374 case K_HOLD
: /* scroll lock suspends glut */
375 LedModifier(LED_SCR
, release
);
376 while(KeyboardLedState
& LED_SCR
) {
383 /* we could queue keypresses here */
384 if(KeyboardLedState
& LED_SCR
)
387 if(labelvalnoshift
>= K_F1
&& labelvalnoshift
<= K_F12
)
388 specialkey
= GLUT_KEY_F1
+ labelvalnoshift
- K_F1
;
390 switch(labelvalnoshift
) {
392 specialkey
= GLUT_KEY_LEFT
; break;
394 specialkey
= GLUT_KEY_UP
; break;
396 specialkey
= GLUT_KEY_RIGHT
; break;
398 specialkey
= GLUT_KEY_DOWN
; break;
400 specialkey
= GLUT_KEY_PAGE_UP
; break;
402 specialkey
= GLUT_KEY_PAGE_DOWN
; break;
404 specialkey
= GLUT_KEY_HOME
; break;
406 specialkey
= GLUT_KEY_END
; break;
408 specialkey
= GLUT_KEY_INSERT
; break;
413 case K_ENTER
- 1: /* keypad enter */
414 labelval
= '\r'; break;
417 /* dispatch callback */
419 HandleSpecialPress(specialkey
, release
);
423 if(KeyboardLedState
& LED_CAP
) {
424 if(c
>= 'A' && c
<= 'Z')
427 if(c
>= 'a' && c
<= 'z')
430 HandleKeyPress(c
, release
);
435 void glutIgnoreKeyRepeat(int ignore
)
437 KeyRepeatMode
= ignore
? GLUT_KEY_REPEAT_OFF
: GLUT_KEY_REPEAT_ON
;
440 void glutSetKeyRepeat(int repeatMode
)
442 KeyRepeatMode
= repeatMode
;
445 void glutForceJoystickFunc(void)
449 static void HandleMousePress(int button
, int pressed
)
451 if(TryMenu(button
, pressed
))
455 MouseFunc(button
, pressed
? GLUT_DOWN
: GLUT_UP
, MouseX
, MouseY
);
458 static int ReadMouse(void)
461 static int ll
, lm
, lr
;
470 if(poll(&pfd
, 1, 1) != 1)
473 if(Gpm_GetEvent(&event
) != 1)
476 l
= event
.buttons
& GPM_B_LEFT
;
477 m
= event
.buttons
& GPM_B_MIDDLE
;
478 r
= event
.buttons
& GPM_B_RIGHT
;
480 /* gpm is weird in that it gives a button number when the button
481 is released, with type set to GPM_UP, this is only a problem
482 if it is the last button released */
484 if(event
.type
& GPM_UP
)
485 if(event
.buttons
== GPM_B_LEFT
|| event
.buttons
== GPM_B_MIDDLE
||
486 event
.buttons
== GPM_B_RIGHT
|| event
.buttons
== GPM_B_FOURTH
)
499 if(read(MouseFD
, data
, 4) != 4)
502 l
= ((data
[0] & 0x20) >> 3);
503 m
= ((data
[3] & 0x10) >> 3);
504 r
= ((data
[0] & 0x10) >> 4);
506 dx
= (((data
[0] & 0x03) << 6) | (data
[1] & 0x3F));
507 dy
= (((data
[0] & 0x0C) << 4) | (data
[2] & 0x3F));
510 MouseX
+= dx
* MouseSpeed
;
514 if(MouseX
>= VarInfo
.xres
)
515 MouseX
= VarInfo
.xres
- 1;
517 MouseY
+= dy
* MouseSpeed
;
521 if(MouseY
>= VarInfo
.yres
)
522 MouseY
= VarInfo
.yres
- 1;
525 HandleMousePress(GLUT_LEFT_BUTTON
, l
);
527 HandleMousePress(GLUT_MIDDLE_BUTTON
, m
);
529 HandleMousePress(GLUT_RIGHT_BUTTON
, r
);
531 ll
= l
, lm
= m
, lr
= r
;
533 if(dx
|| dy
|| !MouseVisible
) {
536 MotionFunc(MouseX
, MouseY
);
538 if(PassiveMotionFunc
)
539 PassiveMotionFunc(MouseX
, MouseY
);
551 LastMouseTime
= glutGet(GLUT_ELAPSED_TIME
);
556 void ReceiveInput(void)
563 /* implement a 2 second timeout on the mouse */
564 if(MouseVisible
&& glutGet(GLUT_ELAPSED_TIME
) - LastMouseTime
> 2000) {
571 static void VTSwitchHandler(int sig
)
576 ioctl(ConsoleFD
, VT_RELDISP
, 1);
587 ioctl(ConsoleFD
, VT_GETSTATE
, &st
);
589 ioctl(ConsoleFD
, VT_RELDISP
, VT_ACKACQ
);
602 void InitializeVT(int usestdin
)
608 signal(SIGIO
, SIG_IGN
);
610 /* save old terminos settings */
611 if (tcgetattr(0, &OldTermios
) < 0) {
612 sprintf(exiterror
, "tcgetattr failed\n");
618 /* terminos settings for straight-through mode */
619 tio
.c_lflag
&= ~(ICANON
| ECHO
| ISIG
);
620 tio
.c_iflag
&= ~(ISTRIP
| IGNCR
| ICRNL
| INLCR
| IXOFF
| IXON
);
621 tio
.c_iflag
|= IGNBRK
;
626 if (tcsetattr(0, TCSANOW
, &tio
) < 0) {
627 sprintf(exiterror
, "tcsetattr failed\n");
638 /* enable sigio for input */
639 if(fcntl(0, F_SETFL
, O_ASYNC
) < 0) {
640 sprintf(exiterror
, "Failed to set O_ASYNC mode on fd 0\n");
644 /* detect the current vt if it was not specified */
646 int fd
= open("/dev/tty", O_RDWR
| O_NDELAY
, 0);
649 sprintf(exiterror
, "Failed to open /dev/tty\n");
653 if(ioctl(fd
, VT_GETSTATE
, &st
) == -1) {
654 fprintf(stderr
, "Could not detect current vt, specify with -vt\n");
655 fprintf(stderr
, "Defaulting to stdin input\n");
661 CurrentVT
= st
.v_active
;
665 /* if we close with the modifier set in glutIconifyWindow, we won't
666 get the signal when they are released, so set to zero here */
667 KeyboardModifiers
= 0;
669 /* open the console tty */
670 sprintf(console
, "/dev/tty%d", CurrentVT
);
671 ConsoleFD
= open(console
, O_RDWR
| O_NDELAY
, 0);
673 sprintf(exiterror
, "error couldn't open %s,"
674 " defaulting to stdin \n", console
);
679 signal(SIGUSR1
, VTSwitchHandler
);
680 signal(SIGUSR2
, VTSwitchHandler
);
682 if (ioctl(ConsoleFD
, VT_GETMODE
, &OldVTMode
) < 0) {
683 sprintf(exiterror
,"Failed to grab %s, defaulting to stdin\n", console
);
691 vt
.mode
= VT_PROCESS
;
695 if (ioctl(ConsoleFD
, VT_SETMODE
, &vt
) < 0) {
696 sprintf(exiterror
, "error: ioctl(VT_SETMODE) failed: %s\n",
703 if (ioctl(ConsoleFD
, KDGKBMODE
, &OldKDMode
) < 0) {
704 sprintf(exiterror
, "Warning: ioctl KDGKBMODE failed!\n");
708 /* use SIGIO so VT switching can work if the program is locked */
709 signal(SIGIO
, KeyboardHandler
);
713 if(fcntl(kbdpipe
[0], F_SETFL
, O_NONBLOCK
| O_ASYNC
) < 0) {
714 sprintf(exiterror
, "Failed to set keyboard to non-blocking\n");
718 fcntl(0, F_SETOWN
, getpid());
720 if(ioctl(ConsoleFD
, KDGETMODE
, &OldMode
) < 0)
721 sprintf(exiterror
, "Warning: Failed to get terminal mode\n");
726 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0)
727 sprintf(exiterror
,"Warning: Failed to set terminal to graphics\n");
729 if(ioctl(ConsoleFD
, KDSKBMODE
, K_MEDIUMRAW
) < 0) {
730 sprintf(exiterror
, "ioctl KDSKBMODE failed!\n");
731 tcsetattr(0, TCSANOW
, &OldTermios
);
735 if(ioctl(ConsoleFD
, KDGKBLED
, &KeyboardLedState
) < 0) {
736 sprintf(exiterror
, "ioctl KDGKBLED failed!\n");
746 if (tcsetattr(0, TCSANOW
, &OldTermios
) < 0)
747 fprintf(stderr
, "tcsetattr failed\n");
749 /* setting the mode to text from graphics restores the colormap */
755 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0)
756 goto skipioctl
; /* no need to fail twice */
758 if(ioctl(ConsoleFD
, KDSETMODE
, OldMode
) < 0)
759 fprintf(stderr
, "ioctl KDSETMODE failed!\n");
766 /* restore keyboard state */
767 if (ioctl(ConsoleFD
, VT_SETMODE
, &OldVTMode
) < 0)
768 fprintf(stderr
, "Failed to set vtmode\n");
770 if (ioctl(ConsoleFD
, KDSKBMODE
, OldKDMode
) < 0)
771 fprintf(stderr
, "ioctl KDSKBMODE failed!\n");
779 void InitializeMouse(void)
785 const char *mousedev
= getenv("MOUSE");
788 if((MouseFD
= open(mousedev
, O_RDONLY
| O_NONBLOCK
)) >= 0) {
799 conn
.eventMask
= ~0; /* Want to know about all the events */
800 conn
.defaultMask
= 0; /* don't handle anything by default */
801 conn
.minMod
= 0; /* want everything */
802 conn
.maxMod
= ~0; /* all modifiers included */
803 if(Gpm_Open(&conn
, 0) != -1) {
809 fprintf(stderr
, "Cannot open gpmctl.\n");
812 fprintf(stderr
,"Cannot open %s.\n"
813 "Continuing without Mouse\n", MOUSEDEV
);
816 void CloseMouse(void)