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
);
182 exit(0); /* no handler, to provide a way to exit */
185 static void HandleSpecialPress(int key
, int up
)
189 SpecialUpFunc(key
, MouseX
, MouseY
);
192 SpecialFunc(key
, MouseX
, MouseY
);
195 static void ReleaseStdinKey(void)
197 if(LastStdinSpecialKey
!= -1) {
198 HandleSpecialPress(LastStdinSpecialKey
, 1);
199 LastStdinSpecialKey
= -1;
201 if(LastStdinCode
!= -1) {
202 HandleKeyPress(LastStdinCode
, 1);
207 #define READKEY read(kbdpipe[0], &code, 1)
208 static int ReadKey(void)
210 int release
, labelval
, labelvalnoshift
;
213 struct kbentry entry
;
216 /* if we are reading from stdin, we detect key releases when the key
217 does not repeat after a given timeout */
218 if(ConsoleFD
== 0 && LastStdinKeyTime
+ 100 < glutGet(GLUT_ELAPSED_TIME
))
226 /* stdin input escape code based */
228 KeyboardModifiers
= 0;
230 if(code
== 27 && READKEY
== 1) {
232 KeyboardModifiers
|= GLUT_ACTIVE_ALT
;
238 specialkey
= GLUT_KEY_LEFT
; break;
240 specialkey
= GLUT_KEY_UP
; break;
242 specialkey
= GLUT_KEY_RIGHT
; break;
244 specialkey
= GLUT_KEY_DOWN
; break;
246 specialkey
= GLUT_KEY_END
; READKEY
; break;
248 specialkey
= GLUT_KEY_PAGE_UP
; READKEY
; break;
250 specialkey
= GLUT_KEY_PAGE_DOWN
; READKEY
; break;
254 specialkey
= GLUT_KEY_HOME
;
256 specialkey
= GLUT_KEY_F1
+ code
- 50;
263 specialkey
= GLUT_KEY_INSERT
;
270 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
273 specialkey
= GLUT_KEY_F1
+ code
- 40;
283 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
284 specialkey
= GLUT_KEY_F1
+ code
- 45;
289 specialkey
= GLUT_KEY_F1
+ code
- 65;
297 LastStdinKeyTime
= glutGet(GLUT_ELAPSED_TIME
);
299 if(LastStdinSpecialKey
!= specialkey
) {
301 HandleSpecialPress(specialkey
, 0);
302 LastStdinSpecialKey
= specialkey
;
303 LastStdinKeyTime
+= 200; /* initial repeat */
305 if(KeyRepeatMode
!= GLUT_KEY_REPEAT_OFF
)
306 HandleSpecialPress(specialkey
, 0);
308 if(code
>= 1 && code
<= 26 && code
!= '\r') {
309 KeyboardModifiers
|= GLUT_ACTIVE_CTRL
;
312 if((code
>= 43 && code
<= 34) || (code
== 60)
313 || (code
>= 62 && code
<= 90) || (code
== 94)
314 || (code
== 95) || (code
>= 123 && code
<= 126))
315 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
318 LastStdinKeyTime
= glutGet(GLUT_ELAPSED_TIME
);
319 if(LastStdinCode
!= code
) {
321 HandleKeyPress(code
, 0);
322 LastStdinCode
= code
;
323 LastStdinKeyTime
+= 200; /* initial repeat */
325 if(KeyRepeatMode
!= GLUT_KEY_REPEAT_OFF
)
326 HandleSpecialPress(code
, 0);
331 /* linux kbd reading */
332 release
= code
& 0x80;
335 if(KeyRepeatMode
== GLUT_KEY_REPEAT_OFF
) {
336 static char keystates
[128];
346 entry
.kb_index
= code
;
349 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
350 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
354 labelvalnoshift
= entry
.kb_value
;
356 if(KeyboardModifiers
& GLUT_ACTIVE_SHIFT
)
357 entry
.kb_table
|= K_SHIFTTAB
;
359 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
360 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
364 labelval
= entry
.kb_value
;
366 switch(labelvalnoshift
) {
368 LedModifier(LED_CAP
, release
);
371 LedModifier(LED_NUM
, release
);
373 case K_HOLD
: /* scroll lock suspends glut */
374 LedModifier(LED_SCR
, release
);
375 while(KeyboardLedState
& LED_SCR
) {
382 /* we could queue keypresses here */
383 if(KeyboardLedState
& LED_SCR
)
386 if(labelvalnoshift
>= K_F1
&& labelvalnoshift
<= K_F12
)
387 specialkey
= GLUT_KEY_F1
+ labelvalnoshift
- K_F1
;
389 switch(labelvalnoshift
) {
391 specialkey
= GLUT_KEY_LEFT
; break;
393 specialkey
= GLUT_KEY_UP
; break;
395 specialkey
= GLUT_KEY_RIGHT
; break;
397 specialkey
= GLUT_KEY_DOWN
; break;
399 specialkey
= GLUT_KEY_PAGE_UP
; break;
401 specialkey
= GLUT_KEY_PAGE_DOWN
; break;
403 specialkey
= GLUT_KEY_HOME
; break;
405 specialkey
= GLUT_KEY_END
; break;
407 specialkey
= GLUT_KEY_INSERT
; break;
412 labelval
= '\r'; break;
415 /* likely a keypad input, but depends on keyboard mapping, ignore */
419 /* dispatch callback */
421 HandleSpecialPress(specialkey
, release
);
425 if(KeyboardLedState
& LED_CAP
) {
426 if(c
>= 'A' && c
<= 'Z')
429 if(c
>= 'a' && c
<= 'z')
432 HandleKeyPress(c
, release
);
437 void glutIgnoreKeyRepeat(int ignore
)
439 KeyRepeatMode
= ignore
? GLUT_KEY_REPEAT_OFF
: GLUT_KEY_REPEAT_ON
;
442 void glutSetKeyRepeat(int repeatMode
)
444 KeyRepeatMode
= repeatMode
;
447 void glutForceJoystickFunc(void)
451 static void HandleMousePress(int button
, int pressed
)
453 if(TryMenu(button
, pressed
))
457 MouseFunc(button
, pressed
? GLUT_DOWN
: GLUT_UP
, MouseX
, MouseY
);
460 static int ReadMouse(void)
463 static int ll
, lm
, lr
;
472 if(poll(&pfd
, 1, 1) != 1)
475 if(Gpm_GetEvent(&event
) != 1)
478 l
= event
.buttons
& GPM_B_LEFT
;
479 m
= event
.buttons
& GPM_B_MIDDLE
;
480 r
= event
.buttons
& GPM_B_RIGHT
;
482 /* gpm is weird in that it gives a button number when the button
483 is released, with type set to GPM_UP, this is only a problem
484 if it is the last button released */
486 if(event
.type
& GPM_UP
)
487 if(event
.buttons
== GPM_B_LEFT
|| event
.buttons
== GPM_B_MIDDLE
||
488 event
.buttons
== GPM_B_RIGHT
|| event
.buttons
== GPM_B_FOURTH
)
501 if(read(MouseFD
, data
, 4) != 4)
504 l
= ((data
[0] & 0x20) >> 3);
505 m
= ((data
[3] & 0x10) >> 3);
506 r
= ((data
[0] & 0x10) >> 4);
508 dx
= (((data
[0] & 0x03) << 6) | (data
[1] & 0x3F));
509 dy
= (((data
[0] & 0x0C) << 4) | (data
[2] & 0x3F));
512 MouseX
+= dx
* MouseSpeed
;
516 if(MouseX
>= VarInfo
.xres
)
517 MouseX
= VarInfo
.xres
- 1;
519 MouseY
+= dy
* MouseSpeed
;
523 if(MouseY
>= VarInfo
.yres
)
524 MouseY
= VarInfo
.yres
- 1;
527 HandleMousePress(GLUT_LEFT_BUTTON
, l
);
529 HandleMousePress(GLUT_MIDDLE_BUTTON
, m
);
531 HandleMousePress(GLUT_RIGHT_BUTTON
, r
);
533 ll
= l
, lm
= m
, lr
= r
;
535 if(dx
|| dy
|| !MouseVisible
) {
538 MotionFunc(MouseX
, MouseY
);
540 if(PassiveMotionFunc
)
541 PassiveMotionFunc(MouseX
, MouseY
);
553 LastMouseTime
= glutGet(GLUT_ELAPSED_TIME
);
558 void ReceiveInput(void)
565 /* implement a 2 second timeout on the mouse */
566 if(MouseVisible
&& glutGet(GLUT_ELAPSED_TIME
) - LastMouseTime
> 2000) {
573 static void VTSwitchHandler(int sig
)
578 ioctl(ConsoleFD
, VT_RELDISP
, 1);
589 ioctl(ConsoleFD
, VT_GETSTATE
, &st
);
591 ioctl(ConsoleFD
, VT_RELDISP
, VT_ACKACQ
);
604 void InitializeVT(int usestdin
)
610 signal(SIGIO
, SIG_IGN
);
619 /* detect the current vt if it was not specified */
621 int fd
= open("/dev/tty", O_RDWR
| O_NDELAY
, 0);
624 sprintf(exiterror
, "Failed to open /dev/tty\n");
628 if(ioctl(fd
, VT_GETSTATE
, &st
) == -1) {
629 fprintf(stderr
, "Could not detect current vt, specify with -vt\n");
630 fprintf(stderr
, "Defaulting to stdin input\n");
636 CurrentVT
= st
.v_active
;
640 /* if we close with the modifier set in glutIconifyWindow, we won't
641 get the signal when they are released, so set to zero here */
642 KeyboardModifiers
= 0;
644 /* open the console tty */
645 sprintf(console
, "/dev/tty%d", CurrentVT
);
646 ConsoleFD
= open(console
, O_RDWR
| O_NDELAY
, 0);
648 sprintf(exiterror
, "error couldn't open %s,"
649 " defaulting to stdin \n", console
);
654 signal(SIGUSR1
, VTSwitchHandler
);
655 signal(SIGUSR2
, VTSwitchHandler
);
657 if (ioctl(ConsoleFD
, VT_GETMODE
, &OldVTMode
) < 0) {
658 sprintf(exiterror
,"Failed to grab %s, defaulting to stdin\n", console
);
666 vt
.mode
= VT_PROCESS
;
670 if (ioctl(ConsoleFD
, VT_SETMODE
, &vt
) < 0) {
671 sprintf(exiterror
, "error: ioctl(VT_SETMODE) failed: %s\n",
678 if (ioctl(ConsoleFD
, KDGKBMODE
, &OldKDMode
) < 0) {
679 sprintf(exiterror
, "Warning: ioctl KDGKBMODE failed!\n");
683 /* use SIGIO so VT switching can work if the program is locked */
684 signal(SIGIO
, KeyboardHandler
);
688 if(fcntl(kbdpipe
[0], F_SETFL
, O_NONBLOCK
| O_ASYNC
) < 0) {
689 sprintf(exiterror
, "Failed to set keyboard to non-blocking\n");
693 fcntl(ConsoleFD
, F_SETOWN
, getpid());
695 if(ioctl(ConsoleFD
, KDGETMODE
, &OldMode
) < 0)
696 sprintf(exiterror
, "Warning: Failed to get terminal mode\n");
701 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0)
702 sprintf(exiterror
,"Warning: Failed to set terminal to graphics\n");
704 if(ioctl(ConsoleFD
, KDSKBMODE
, K_MEDIUMRAW
) < 0) {
705 sprintf(exiterror
, "ioctl KDSKBMODE failed!\n");
709 if(ioctl(ConsoleFD
, KDGKBLED
, &KeyboardLedState
) < 0) {
710 sprintf(exiterror
, "ioctl KDGKBLED failed!\n");
715 /* enable async input input */
716 if(fcntl(ConsoleFD
, F_SETFL
, O_ASYNC
) < 0) {
717 sprintf(exiterror
, "Failed to set O_ASYNC mode on fd %d\n", ConsoleFD
);
721 /* save old terminos settings */
722 if (tcgetattr(ConsoleFD
, &OldTermios
) < 0) {
723 sprintf(exiterror
, "tcgetattr failed\n");
729 /* terminos settings for straight-through mode */
730 tio
.c_lflag
&= ~(ICANON
| ECHO
| ISIG
);
731 tio
.c_iflag
&= ~(ISTRIP
| IGNCR
| ICRNL
| INLCR
| IXOFF
| IXON
);
732 tio
.c_iflag
|= IGNBRK
;
737 if (tcsetattr(ConsoleFD
, TCSANOW
, &tio
) < 0) {
738 sprintf(exiterror
, "tcsetattr failed\n");
748 if (tcsetattr(ConsoleFD
, TCSANOW
, &OldTermios
) < 0)
749 sprintf(exiterror
, "tcsetattr failed\n");
751 /* setting the mode to text from graphics restores the colormap */
757 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0)
758 goto skipioctl
; /* no need to fail twice */
760 if(ioctl(ConsoleFD
, KDSETMODE
, OldMode
) < 0)
761 fprintf(stderr
, "ioctl KDSETMODE failed!\n");
768 /* restore keyboard state */
769 if (ioctl(ConsoleFD
, VT_SETMODE
, &OldVTMode
) < 0)
770 fprintf(stderr
, "Failed to set vtmode\n");
772 if (ioctl(ConsoleFD
, KDSKBMODE
, OldKDMode
) < 0)
773 fprintf(stderr
, "ioctl KDSKBMODE failed!\n");
781 void InitializeMouse(void)
787 const char *mousedev
= getenv("MOUSE");
790 if((MouseFD
= open(mousedev
, O_RDONLY
| O_NONBLOCK
)) >= 0) {
801 conn
.eventMask
= ~0; /* Want to know about all the events */
802 conn
.defaultMask
= 0; /* don't handle anything by default */
803 conn
.minMod
= 0; /* want everything */
804 conn
.maxMod
= ~0; /* all modifiers included */
805 if(Gpm_Open(&conn
, 0) != -1) {
811 fprintf(stderr
, "Cannot open gpmctl.\n");
814 fprintf(stderr
,"Cannot open %s.\n"
815 "Continuing without Mouse\n", MOUSEDEV
);
818 void CloseMouse(void)