b1362245f2f176d264803d3ac238b73e1a05c15e
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
;
231 specialkey
= GLUT_KEY_F1
+ code
- 65;
238 KeyboardModifiers
|= GLUT_ACTIVE_ALT
;
245 SpecialFunc(specialkey
, MouseX
, MouseY
);
247 if(code
>= 1 && code
<= 26 && code
!= '\r') {
248 KeyboardModifiers
|= GLUT_ACTIVE_CTRL
;
251 if((code
>= 43 && code
<= 34) || (code
== 60)
252 || (code
>= 62 && code
<= 90) || (code
== 94)
253 || (code
== 95) || (code
>= 123 && code
<= 126))
254 KeyboardModifiers
|= GLUT_ACTIVE_SHIFT
;
257 KeyboardFunc(code
, MouseX
, MouseY
);
262 /* linux kbd reading */
263 release
= code
& 0x80;
266 if(KeyRepeatMode
== GLUT_KEY_REPEAT_OFF
) {
267 static char keystates
[128];
277 entry
.kb_index
= code
;
280 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
281 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
285 labelvalnoshift
= entry
.kb_value
;
287 if(KeyboardModifiers
& GLUT_ACTIVE_SHIFT
)
288 entry
.kb_table
|= K_SHIFTTAB
;
290 if (ioctl(ConsoleFD
, KDGKBENT
, &entry
) < 0) {
291 sprintf(exiterror
, "ioctl(KDGKBENT) failed.\n");
295 labelval
= entry
.kb_value
;
297 switch(labelvalnoshift
) {
299 LedModifier(LED_CAP
, release
);
302 LedModifier(LED_NUM
, release
);
304 case K_HOLD
: /* scroll lock suspends glut */
305 LedModifier(LED_SCR
, release
);
306 while(KeyboardLedState
& LED_SCR
) {
313 /* we could queue keypresses here */
314 if(KeyboardLedState
& LED_SCR
)
317 if(labelvalnoshift
>= K_F1
&& labelvalnoshift
<= K_F12
)
318 specialkey
= GLUT_KEY_F1
+ labelvalnoshift
- K_F1
;
320 switch(labelvalnoshift
) {
322 specialkey
= GLUT_KEY_LEFT
; break;
324 specialkey
= GLUT_KEY_UP
; break;
326 specialkey
= GLUT_KEY_RIGHT
; break;
328 specialkey
= GLUT_KEY_DOWN
; break;
330 specialkey
= GLUT_KEY_PAGE_UP
; break;
332 specialkey
= GLUT_KEY_PAGE_DOWN
; break;
334 specialkey
= GLUT_KEY_HOME
; break;
336 specialkey
= GLUT_KEY_END
; break;
338 specialkey
= GLUT_KEY_INSERT
; break;
343 case K_ENTER
- 1: /* keypad enter */
344 labelval
= '\n'; break;
347 /* dispatch callback */
351 SpecialUpFunc(specialkey
, MouseX
, MouseY
);
354 SpecialFunc(specialkey
, MouseX
, MouseY
);
358 if(KeyboardLedState
& LED_CAP
) {
359 if(c
>= 'A' && c
<= 'Z')
362 if(c
>= 'a' && c
<= 'z')
367 KeyboardUpFunc(c
, MouseX
, MouseY
);
370 KeyboardFunc(c
, MouseX
, MouseY
);
375 void glutIgnoreKeyRepeat(int ignore
)
377 KeyRepeatMode
= ignore
? GLUT_KEY_REPEAT_OFF
: GLUT_KEY_REPEAT_ON
;
380 void glutSetKeyRepeat(int repeatMode
)
382 KeyRepeatMode
= repeatMode
;
385 void glutForceJoystickFunc(void)
389 static void HandleMousePress(int button
, int pressed
)
391 if(TryMenu(button
, pressed
))
395 MouseFunc(button
, pressed
? GLUT_DOWN
: GLUT_UP
, MouseX
, MouseY
);
398 static int ReadMouse(void)
401 static int ll
, lm
, lr
;
410 if(poll(&pfd
, 1, 1) != 1)
413 if(Gpm_GetEvent(&event
) != 1)
416 l
= event
.buttons
& GPM_B_LEFT
;
417 m
= event
.buttons
& GPM_B_MIDDLE
;
418 r
= event
.buttons
& GPM_B_RIGHT
;
420 /* gpm is weird in that it gives a button number when the button
421 is released, with type set to GPM_UP, this is only a problem
422 if it is the last button released */
424 if(event
.type
& GPM_UP
)
425 if(event
.buttons
== GPM_B_LEFT
|| event
.buttons
== GPM_B_MIDDLE
||
426 event
.buttons
== GPM_B_RIGHT
|| event
.buttons
== GPM_B_FOURTH
)
439 if(fcntl(MouseFD
, F_SETFL
, O_NONBLOCK
) == -1) {
445 if(read(MouseFD
, data
, 4) != 4)
448 l
= ((data
[0] & 0x20) >> 3);
449 m
= ((data
[3] & 0x10) >> 3);
450 r
= ((data
[0] & 0x10) >> 4);
452 dx
= (((data
[0] & 0x03) << 6) | (data
[1] & 0x3F));
453 dy
= (((data
[0] & 0x0C) << 4) | (data
[2] & 0x3F));
456 MouseX
+= dx
* MouseSpeed
;
460 if(MouseX
>= VarInfo
.xres
)
461 MouseX
= VarInfo
.xres
- 1;
463 MouseY
+= dy
* MouseSpeed
;
467 if(MouseY
>= VarInfo
.yres
)
468 MouseY
= VarInfo
.yres
- 1;
471 HandleMousePress(GLUT_LEFT_BUTTON
, l
);
473 HandleMousePress(GLUT_MIDDLE_BUTTON
, m
);
475 HandleMousePress(GLUT_RIGHT_BUTTON
, r
);
477 ll
= l
, lm
= m
, lr
= r
;
482 MotionFunc(MouseX
, MouseY
);
484 if(PassiveMotionFunc
)
485 PassiveMotionFunc(MouseX
, MouseY
);
498 void ReceiveInput(void)
507 static void VTSwitchHandler(int sig
)
512 ioctl(ConsoleFD
, VT_RELDISP
, 1);
523 ioctl(ConsoleFD
, VT_GETSTATE
, &st
);
525 ioctl(ConsoleFD
, VT_RELDISP
, VT_ACKACQ
);
527 /* this is a hack to turn the cursor off */
528 ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
);
542 void InitializeVT(int usestdin
)
548 signal(SIGIO
, SIG_IGN
);
550 /* save old terminos settings */
551 if (tcgetattr(0, &OldTermios
) < 0) {
552 sprintf(exiterror
, "tcgetattr failed\n");
558 /* terminos settings for straight-through mode */
559 tio
.c_lflag
&= ~(ICANON
| ECHO
| ISIG
);
560 tio
.c_iflag
&= ~(ISTRIP
| IGNCR
| ICRNL
| INLCR
| IXOFF
| IXON
);
561 tio
.c_iflag
|= IGNBRK
;
566 if (tcsetattr(0, TCSANOW
, &tio
) < 0) {
567 sprintf(exiterror
, "tcsetattr failed\n");
571 if(fcntl(0, F_SETFL
, O_NONBLOCK
| O_ASYNC
) < 0) {
572 sprintf(exiterror
, "Failed to set keyboard to non-blocking\n");
583 /* detect the current vt if it was not specified */
585 int fd
= open("/dev/tty", O_RDWR
| O_NDELAY
, 0);
588 sprintf(exiterror
, "Failed to open /dev/tty\n");
591 if(ioctl(fd
, VT_GETSTATE
, &st
) == -1) {
592 fprintf(stderr
, "Could not detect current vt, specify with -vt\n");
593 fprintf(stderr
, "Defaulting to stdin input\n");
598 CurrentVT
= st
.v_active
;
603 /* open the console tty */
604 sprintf(console
, "/dev/tty%d", CurrentVT
);
605 ConsoleFD
= open(console
, O_RDWR
| O_NDELAY
, 0);
607 sprintf(exiterror
, "error couldn't open %s,"
608 " defaulting to stdin \n", console
);
613 signal(SIGUSR1
, VTSwitchHandler
);
614 signal(SIGUSR2
, VTSwitchHandler
);
616 if (ioctl(ConsoleFD
, VT_GETMODE
, &OldVTMode
) < 0) {
617 sprintf(exiterror
,"Failed to grab %s, defaulting to stdin\n", console
);
625 vt
.mode
= VT_PROCESS
;
629 if (ioctl(ConsoleFD
, VT_SETMODE
, &vt
) < 0) {
630 sprintf(exiterror
, "error: ioctl(VT_SETMODE) failed: %s\n",
637 if (ioctl(ConsoleFD
, KDGKBMODE
, &OldKDMode
) < 0) {
638 sprintf(exiterror
, "Warning: ioctl KDGKBMODE failed!\n");
642 /* use SIGIO so VT switching can work if the program is locked */
643 signal(SIGIO
, KeyboardHandler
);
647 if(fcntl(kbdpipe
[0], F_SETFL
, O_NONBLOCK
| O_ASYNC
) < 0) {
648 sprintf(exiterror
, "Failed to set keyboard to non-blocking\n");
652 fcntl(0, F_SETOWN
, getpid());
654 if(ioctl(ConsoleFD
, KDGETMODE
, &OldMode
) < 0)
655 sprintf(exiterror
, "Warning: Failed to get terminal mode\n");
660 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0)
661 sprintf(exiterror
,"Warning: Failed to set terminal to graphics\n");
663 if (ioctl(ConsoleFD
, KDSKBMODE
, K_MEDIUMRAW
) < 0) {
664 sprintf(exiterror
, "ioctl KDSKBMODE failed!\n");
665 tcsetattr(0, TCSANOW
, &OldTermios
);
669 if( ioctl(ConsoleFD
, KDGKBLED
, &KeyboardLedState
) < 0) {
670 sprintf(exiterror
, "ioctl KDGKBLED failed!\n");
680 if (tcsetattr(0, TCSANOW
, &OldTermios
) < 0)
681 fprintf(stderr
, "tcsetattr failed\n");
683 /* setting the mode to text from graphics restores the colormap*/
689 if(ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0) {
690 sprintf(exiterror
,"Warning: Failed to set terminal to graphics\n");
691 goto skipioctl
; /* no need to fail twice */
694 if(ioctl(ConsoleFD
, KDSETMODE
, OldMode
) < 0)
695 fprintf(stderr
, "ioctl KDSETMODE failed!\n");
702 /* restore keyboard state */
703 if (ioctl(ConsoleFD
, VT_SETMODE
, &OldVTMode
) < 0)
704 fprintf(stderr
, "Failed to set vtmode\n");
706 if (ioctl(ConsoleFD
, KDSKBMODE
, OldKDMode
) < 0)
707 fprintf(stderr
, "ioctl KDSKBMODE failed!\n");
712 void InitializeMouse(void)
718 const char *mousedev
= getenv("MOUSE");
721 if((MouseFD
= open(mousedev
, O_RDONLY
)) >= 0) {
732 conn
.eventMask
= ~0; /* Want to know about all the events */
733 conn
.defaultMask
= 0; /* don't handle anything by default */
734 conn
.minMod
= 0; /* want everything */
735 conn
.maxMod
= ~0; /* all modifiers included */
736 if(Gpm_Open(&conn
, 0) != -1) {
742 fprintf(stderr
, "Cannot open gpmctl.\n");
745 fprintf(stderr
,"Cannot open %s.\n"
746 "Continuing without Mouse\n", MOUSEDEV
);
749 void CloseMouse(void)