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
;
68 /* only display the mouse if there is a registered callback for it */
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 #define MODIFIER(mod) \
83 KeyboardModifiers = release ? KeyboardModifiers & ~mod \
84 : KeyboardModifiers | mod;
86 /* signal handler attached to SIGIO on keyboard input, vt
87 switching and modifiers is handled in the signal handler
88 other keypresses read from a pipe that leaves the handler
89 if a program locks up the glut loop, you can still switch
90 vts and kill it without Alt-SysRq hack */
91 static void KeyboardHandler(int sig
)
93 int release
, labelval
;
96 static int lalt
; /* only left alt does vt switch */
98 if(read(ConsoleFD
, &code
, 1) != 1)
101 release
= code
& 0x80;
103 entry
.kb_index
= code
& 0x7F;
106 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
107 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
111 labelval
= entry
.kb_value
;
116 MODIFIER(GLUT_ACTIVE_SHIFT
);
119 MODIFIER(GLUT_ACTIVE_CTRL
);
124 MODIFIER(GLUT_ACTIVE_ALT
);
128 if(lalt
&& !release
) {
129 /* VT switch, we must do it */
132 if(labelval
>= K_F1
&& labelval
<= K_F12
)
133 vt
= labelval
- K_F1
+ 1;
135 if(labelval
== K_LEFT
)
136 if(ioctl(ConsoleFD
, VT_GETSTATE
, &st
) >= 0)
137 vt
= st
.v_active
- 1;
139 if(labelval
== K_RIGHT
)
140 if(ioctl(ConsoleFD
, VT_GETSTATE
, &st
) >= 0)
141 vt
= st
.v_active
- 1;
147 if(ioctl(ConsoleFD
, VT_ACTIVATE
, vt
) < 0)
148 sprintf(exiterror
, "Error switching console\n");
152 write(kbdpipe
[1], &code
, 1);
155 static void LedModifier(int led
, int release
)
157 static int releaseflag
= K_CAPS
| K_NUM
| K_HOLD
;
161 if(releaseflag
& led
) {
162 KeyboardLedState
^= led
;
165 ioctl(ConsoleFD
, KDSKBLED
, KeyboardLedState
);
166 ioctl(ConsoleFD
, KDSETLED
, 0x80);
169 #define READKEY read(kbdpipe[0], &code, 1)
170 static int ReadKey(void)
172 int release
, labelval
, labelvalnoshift
;
175 struct kbentry entry
;
182 /* stdin input escape code based */
184 KeyboardModifiers
= 0;
186 if(code
== 27 && READKEY
== 1) {
188 case 79: /* function key */
193 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
194 specialkey
= GLUT_KEY_F1
+ code
- 53;
198 specialkey
= GLUT_KEY_F1
+ code
- 80;
205 specialkey
= GLUT_KEY_LEFT
; break;
207 specialkey
= GLUT_KEY_UP
; break;
209 specialkey
= GLUT_KEY_RIGHT
; break;
211 specialkey
= GLUT_KEY_DOWN
; break;
213 specialkey
= GLUT_KEY_PAGE_UP
; READKEY
; break;
215 specialkey
= GLUT_KEY_PAGE_DOWN
; READKEY
; break;
217 specialkey
= GLUT_KEY_HOME
; READKEY
; break;
219 specialkey
= GLUT_KEY_END
; READKEY
; break;
224 specialkey
= GLUT_KEY_INSERT
;
227 code
= '\b'; goto stdkey
;
230 specialkey
= GLUT_KEY_F1
+ code
- 65;
237 KeyboardModifiers
|= GLUT_ACTIVE_ALT
;
244 SpecialFunc(specialkey
, MouseX
, MouseY
);
246 if(code
>= 1 && code
<= 26 && code
!= '\r') {
247 KeyboardModifiers
|= GLUT_ACTIVE_CTRL
;
250 if((code
>= 43 && code
<= 34) || (code
== 60)
251 || (code
>= 62 && code
<= 90) || (code
== 94)
252 || (code
== 95) || (code
>= 123 && code
<= 126))
253 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
256 KeyboardFunc(code
, MouseX
, MouseY
);
261 /* linux kbd reading */
262 release
= code
& 0x80;
265 if(KeyRepeatMode
== GLUT_KEY_REPEAT_OFF
) {
266 static char keystates
[128];
276 entry
.kb_index
= code
;
279 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
280 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
284 labelvalnoshift
= entry
.kb_value
;
286 if(KeyboardModifiers
& GLUT_ACTIVE_SHIFT
)
287 entry
.kb_table
|= K_SHIFTTAB
;
289 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
290 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
294 labelval
= entry
.kb_value
;
296 switch(labelvalnoshift
) {
298 LedModifier(LED_CAP
, release
);
301 LedModifier(LED_NUM
, release
);
303 case K_HOLD
: /* scroll lock suspends glut */
304 LedModifier(LED_SCR
, release
);
305 while(KeyboardLedState
& LED_SCR
) {
312 /* we could queue keypresses here */
313 if(KeyboardLedState
& LED_SCR
)
316 if(labelval
>= K_F1
&& labelval
<= K_F12
)
317 specialkey
= GLUT_KEY_F1
+ labelval
- K_F1
;
319 switch(labelvalnoshift
) {
321 specialkey
= GLUT_KEY_LEFT
; break;
323 specialkey
= GLUT_KEY_UP
; break;
325 specialkey
= GLUT_KEY_RIGHT
; break;
327 specialkey
= GLUT_KEY_DOWN
; break;
329 specialkey
= GLUT_KEY_PAGE_UP
; break;
331 specialkey
= GLUT_KEY_PAGE_DOWN
; break;
333 specialkey
= GLUT_KEY_HOME
; break;
335 specialkey
= GLUT_KEY_END
; break;
337 specialkey
= GLUT_KEY_INSERT
; break;
339 labelval
= '\b'; break;
341 case K_ENTER
- 1: /* keypad enter */
342 labelval
= '\n'; break;
345 /* dispatch callback */
349 SpecialUpFunc(specialkey
, MouseX
, MouseY
);
352 SpecialFunc(specialkey
, MouseX
, MouseY
);
356 if(KeyboardLedState
& LED_CAP
) {
357 if(c
>= 'A' && c
<= 'Z')
360 if(c
>= 'a' && c
<= 'z')
365 KeyboardUpFunc(c
, MouseX
, MouseY
);
368 KeyboardFunc(c
, MouseX
, MouseY
);
373 void glutIgnoreKeyRepeat(int ignore
)
375 KeyRepeatMode
= ignore
? GLUT_KEY_REPEAT_OFF
: GLUT_KEY_REPEAT_ON
;
378 void glutSetKeyRepeat(int repeatMode
)
380 KeyRepeatMode
= repeatMode
;
383 void glutForceJoystickFunc(void)
387 static void HandleMousePress(int button
, int pressed
)
389 if(TryMenu(button
, pressed
))
393 MouseFunc(button
, pressed
? GLUT_DOWN
: GLUT_UP
, MouseX
, MouseY
);
396 static int ReadMouse(void)
399 static int ll
, lm
, lr
;
408 if(poll(&pfd
, 1, 1) != 1)
411 if(Gpm_GetEvent(&event
) != 1)
414 l
= event
.buttons
& GPM_B_LEFT
;
415 m
= event
.buttons
& GPM_B_MIDDLE
;
416 r
= event
.buttons
& GPM_B_RIGHT
;
418 /* gpm is weird in that it gives a button number when the button
419 is released, with type set to GPM_UP, this is only a problem
420 if it is the last button released */
422 if(event
.type
& GPM_UP
)
423 if(event
.buttons
== GPM_B_LEFT
|| event
.buttons
== GPM_B_MIDDLE
||
424 event
.buttons
== GPM_B_RIGHT
|| event
.buttons
== GPM_B_FOURTH
)
437 if(fcntl(MouseFD
, F_SETFL
, O_NONBLOCK
) == -1) {
443 if(read(MouseFD
, data
, 4) != 4)
446 l
= ((data
[0] & 0x20) >> 3);
447 m
= ((data
[3] & 0x10) >> 3);
448 r
= ((data
[0] & 0x10) >> 4);
450 dx
= (((data
[0] & 0x03) << 6) | (data
[1] & 0x3F));
451 dy
= (((data
[0] & 0x0C) << 4) | (data
[2] & 0x3F));
454 MouseX
+= dx
* MouseSpeed
;
458 if(MouseX
>= VarInfo
.xres
)
459 MouseX
= VarInfo
.xres
- 1;
461 MouseY
+= dy
* MouseSpeed
;
465 if(MouseY
>= VarInfo
.yres
)
466 MouseY
= VarInfo
.yres
- 1;
469 HandleMousePress(GLUT_LEFT_BUTTON
, l
);
471 HandleMousePress(GLUT_MIDDLE_BUTTON
, m
);
473 HandleMousePress(GLUT_RIGHT_BUTTON
, r
);
475 ll
= l
, lm
= m
, lr
= r
;
480 MotionFunc(MouseX
, MouseY
);
482 if(PassiveMotionFunc
)
483 PassiveMotionFunc(MouseX
, MouseY
);
496 void ReceiveInput(void)
505 static void VTSwitchHandler(int sig
)
510 ioctl(ConsoleFD
, VT_RELDISP
, 1);
521 ioctl(ConsoleFD
, VT_GETSTATE
, &st
);
523 ioctl(ConsoleFD
, VT_RELDISP
, VT_ACKACQ
);
525 /* this is a hack to turn the cursor off */
526 ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
);
540 void InitializeVT(int usestdin
)
546 signal(SIGIO
, SIG_IGN
);
548 /* save old terminos settings */
549 if (tcgetattr(0, &OldTermios
) < 0) {
550 sprintf(exiterror
, "tcgetattr failed\n");
556 /* terminos settings for straight-through mode */
557 tio
.c_lflag
&= ~(ICANON
| ECHO
| ISIG
);
558 tio
.c_iflag
&= ~(ISTRIP
| IGNCR
| ICRNL
| INLCR
| IXOFF
| IXON
);
559 tio
.c_iflag
|= IGNBRK
;
564 if (tcsetattr(0, TCSANOW
, &tio
) < 0) {
565 sprintf(exiterror
, "tcsetattr failed\n");
569 if(fcntl(0, F_SETFL
, O_NONBLOCK
| O_ASYNC
) < 0) {
570 sprintf(exiterror
, "Failed to set keyboard to non-blocking\n");
581 /* detect the current vt if it was not specified */
583 int fd
= open("/dev/tty", O_RDWR
| O_NDELAY
, 0);
586 sprintf(exiterror
, "Failed to open /dev/tty\n");
589 if(ioctl(fd
, VT_GETSTATE
, &st
) == -1) {
590 fprintf(stderr
, "Could not detect current vt, specify with -vt\n");
591 fprintf(stderr
, "Defaulting to stdin input\n");
596 CurrentVT
= st
.v_active
;
601 /* open the console tty */
602 sprintf(console
, "/dev/tty%d", CurrentVT
);
603 ConsoleFD
= open(console
, O_RDWR
| O_NDELAY
, 0);
605 sprintf(exiterror
, "error couldn't open %s,"
606 " defaulting to stdin \n", console
);
611 signal(SIGUSR1
, VTSwitchHandler
);
612 signal(SIGUSR2
, VTSwitchHandler
);
614 if (ioctl(ConsoleFD
, VT_GETMODE
, &OldVTMode
) < 0) {
615 sprintf(exiterror
,"Failed to grab %s, defaulting to stdin\n", console
);
623 vt
.mode
= VT_PROCESS
;
627 if (ioctl(ConsoleFD
, VT_SETMODE
, &vt
) < 0) {
628 sprintf(exiterror
, "error: ioctl(VT_SETMODE) failed: %s\n",
635 if (ioctl(ConsoleFD
, KDGKBMODE
, &OldKDMode
) < 0) {
636 sprintf(exiterror
, "Warning: ioctl KDGKBMODE failed!\n");
640 /* use SIGIO so VT switching can work if the program is locked */
641 signal(SIGIO
, KeyboardHandler
);
645 if(fcntl(kbdpipe
[0], F_SETFL
, O_NONBLOCK
| O_ASYNC
) < 0) {
646 sprintf(exiterror
, "Failed to set keyboard to non-blocking\n");
650 fcntl(0, F_SETOWN
, getpid());
652 if(ioctl(ConsoleFD
, KDGETMODE
, &OldMode
) < 0)
653 sprintf(exiterror
, "Warning: Failed to get terminal mode\n");
658 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0)
659 sprintf(exiterror
,"Warning: Failed to set terminal to graphics\n");
661 if (ioctl(ConsoleFD
, KDSKBMODE
, K_MEDIUMRAW
) < 0) {
662 sprintf(exiterror
, "ioctl KDSKBMODE failed!\n");
663 tcsetattr(0, TCSANOW
, &OldTermios
);
667 if( ioctl(ConsoleFD
, KDGKBLED
, &KeyboardLedState
) < 0) {
668 sprintf(exiterror
, "ioctl KDGKBLED failed!\n");
678 if (tcsetattr(0, TCSANOW
, &OldTermios
) < 0)
679 fprintf(stderr
, "tcsetattr failed\n");
681 /* setting the mode to text from graphics restores the colormap*/
687 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0) {
688 sprintf(exiterror
,"Warning: Failed to set terminal to graphics\n");
689 goto skipioctl
; /* no need to fail twice */
692 if(ioctl(ConsoleFD
, KDSETMODE
, OldMode
) < 0)
693 fprintf(stderr
, "ioctl KDSETMODE failed!\n");
700 /* restore keyboard state */
701 if (ioctl(ConsoleFD
, VT_SETMODE
, &OldVTMode
) < 0)
702 fprintf(stderr
, "Failed to set vtmode\n");
704 if (ioctl(ConsoleFD
, KDSKBMODE
, OldKDMode
) < 0)
705 fprintf(stderr
, "ioctl KDSKBMODE failed!\n");
710 void InitializeMouse(void)
716 const char *mousedev
= getenv("MOUSE");
719 if((MouseFD
= open(mousedev
, O_RDONLY
)) >= 0) {
730 conn
.eventMask
= ~0; /* Want to know about all the events */
731 conn
.defaultMask
= 0; /* don't handle anything by default */
732 conn
.minMod
= 0; /* want everything */
733 conn
.maxMod
= ~0; /* all modifiers included */
734 if(Gpm_Open(&conn
, 0) != -1) {
740 fprintf(stderr
, "Cannot open gpmctl.\n");
743 fprintf(stderr
,"Cannot open %s.\n"
744 "Continuing without Mouse\n", MOUSEDEV
);
747 void CloseMouse(void)