7cff5a0b8d59c58b3dff81d64bb6c13ea32698f8
[freeglut] / src / Common / freeglut_input_devices.c
1 /*\r
2  * freeglut_input_devices.c\r
3  *\r
4  * Handles miscellaneous input devices via direct serial-port access.\r
5  * Proper X11 XInput device support is not yet supported.\r
6  * Also lacks Mac support.\r
7  *\r
8  * Written by Joe Krahn <krahn@niehs.nih.gov> 2005\r
9  *\r
10  * Copyright (c) 2005 Stephen J. Baker. All Rights Reserved.\r
11  *\r
12  * Permission is hereby granted, free of charge, to any person obtaining a\r
13  * copy of this software and associated documentation files (the "Software"),\r
14  * to deal in the Software without restriction, including without limitation\r
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
16  * and/or sell copies of the Software, and to permit persons to whom the\r
17  * Software is furnished to do so, subject to the following conditions:\r
18  *\r
19  * The above copyright notice and this permission notice shall be included\r
20  * in all copies or substantial portions of the Software.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
25  * PAWEL W. OLSZTA OR STEPHEN J. BAKER BE LIABLE FOR ANY CLAIM, DAMAGES OR\r
26  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\r
27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
28  * DEALINGS IN THE SOFTWARE.\r
29  */\r
30 \r
31 #ifdef HAVE_CONFIG_H\r
32 #    include "config.h"\r
33 #endif\r
34 \r
35 #include <GL/freeglut.h>\r
36 #include "freeglut_internal.h"\r
37 \r
38 typedef struct _serialport SERIALPORT;\r
39 \r
40 \r
41 /********************* Dialbox definitions ***********************/\r
42 \r
43 #define DIAL_NUM_VALUATORS 8\r
44 \r
45 /* dial parser state machine states */\r
46 #define DIAL_NEW                (-1)\r
47 #define DIAL_WHICH_DEVICE       0\r
48 #define DIAL_VALUE_HIGH         1\r
49 #define DIAL_VALUE_LOW          2\r
50 \r
51 /* dial/button box commands */\r
52 #define DIAL_INITIALIZE                 0x20\r
53 #define DIAL_SET_LEDS                   0x75\r
54 #define DIAL_SET_TEXT                   0x61\r
55 #define DIAL_SET_AUTO_DIALS             0x50\r
56 #define DIAL_SET_AUTO_DELTA_DIALS       0x51\r
57 #define DIAL_SET_FILTER                 0x53\r
58 #define DIAL_SET_BUTTONS_MOM_TYPE       0x71\r
59 #define DIAL_SET_AUTO_MOM_BUTTONS       0x73\r
60 #define DIAL_SET_ALL_LEDS               0x4b\r
61 #define DIAL_CLEAR_ALL_LEDS             0x4c\r
62 \r
63 /* dial/button box replies and events */\r
64 #define DIAL_INITIALIZED        0x20\r
65 #define DIAL_BASE               0x30\r
66 #define DIAL_DELTA_BASE         0x40\r
67 #define DIAL_PRESS_BASE         0xc0\r
68 #define DIAL_RELEASE_BASE       0xe0\r
69 \r
70 /* macros to determine reply type */\r
71 #define IS_DIAL_EVENT(ch)       (((ch)>=DIAL_BASE)&&((ch)<DIAL_BASE+DIAL_NUM_VALUATORS))\r
72 #define IS_KEY_PRESS(ch)        (((ch)>=DIAL_PRESS_BASE)&&((ch)<DIAL_PRESS_BASE+DIAL_NUM_BUTTONS))\r
73 #define IS_KEY_RELEASE(ch)      (((ch)>=DIAL_RELEASE_BASE)&&((ch)<DIAL_RELEASE_BASE+DIAL_NUM_BUTTONS))\r
74 #define IS_INIT_EVENT(ch)       ((ch)==DIAL_INITIALIZED)\r
75 \r
76 /*****************************************************************/\r
77 \r
78 extern SERIALPORT *serial_open ( const char *device );\r
79 extern void serial_close ( SERIALPORT *port );\r
80 extern int serial_getchar ( SERIALPORT *port );\r
81 extern int serial_putchar ( SERIALPORT *port, unsigned char ch );\r
82 extern void serial_flush ( SERIALPORT *port );\r
83 \r
84 extern void fgPlatformRegisterDialDevice ( const char *dial_device );\r
85 static void send_dial_event(int dial, int value);\r
86 static void poll_dials(int id);\r
87 \r
88 /* local variables */\r
89 static SERIALPORT *dialbox_port=NULL;\r
90 \r
91 /*****************************************************************/\r
92 \r
93 /*\r
94  * Implementation for glutDeviceGet(GLUT_HAS_DIAL_AND_BUTTON_BOX)\r
95  */\r
96 int fgInputDeviceDetect( void )\r
97 {\r
98     fgInitialiseInputDevices ();\r
99 \r
100     if ( !dialbox_port )\r
101         return 0;\r
102 \r
103     if ( !fgState.InputDevsInitialised )\r
104         return 0;\r
105 \r
106     return 1;\r
107 }\r
108 \r
109 /*\r
110  * Try initializing the input device(s)\r
111  */\r
112 void fgInitialiseInputDevices ( void )\r
113 {\r
114     if( !fgState.InputDevsInitialised )\r
115     {\r
116         const char *dial_device=NULL;\r
117         dial_device = getenv ( "GLUT_DIALS_SERIAL" );\r
118                 fgPlatformRegisterDialDevice ( dial_device );\r
119 \r
120         if ( !dial_device ) return;\r
121         if ( !( dialbox_port = serial_open ( dial_device ) ) ) return;\r
122         serial_putchar(dialbox_port,DIAL_INITIALIZE);\r
123         glutTimerFunc ( 10, poll_dials, 0 );\r
124         fgState.InputDevsInitialised = GL_TRUE;\r
125     }\r
126 }\r
127 \r
128 /*\r
129  *\r
130  */\r
131 void fgInputDeviceClose( void )\r
132 {\r
133     if ( fgState.InputDevsInitialised )\r
134     {\r
135         serial_close ( dialbox_port );\r
136         dialbox_port = NULL;\r
137         fgState.InputDevsInitialised = GL_FALSE;\r
138     }\r
139 }\r
140 \r
141 /********************************************************************/\r
142 \r
143 /* Check all windows for dialbox callbacks */\r
144 static void fghcbEnumDialCallbacks ( SFG_Window *window, SFG_Enumerator *enumerator )\r
145 {\r
146     /* Built-in to INVOKE_WCB():  if window->Callbacks[CB_Dials] */\r
147     INVOKE_WCB ( *window,Dials, ( ((int*)enumerator->data)[0], ((int*)enumerator->data)[1]) );\r
148     fgEnumSubWindows ( window, fghcbEnumDialCallbacks, enumerator );\r
149 }\r
150 \r
151 static void send_dial_event ( int num, int value )\r
152 {\r
153     SFG_Enumerator enumerator;\r
154     int data[2];\r
155     data[0] = num;\r
156     data[1] = value;\r
157     enumerator.found = GL_FALSE;\r
158     enumerator.data  =  data;\r
159     fgEnumWindows ( fghcbEnumDialCallbacks, &enumerator );\r
160 }\r
161 \r
162 /********************************************************************/\r
163 static void poll_dials ( int id )\r
164 {\r
165     int data;\r
166     static int dial_state = DIAL_NEW;\r
167     static int dial_which;\r
168     static int dial_value;\r
169     static int dials[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };\r
170 \r
171     if ( !dialbox_port ) return;\r
172 \r
173     while ( (data=serial_getchar(dialbox_port)) != EOF )\r
174     {\r
175         if ( ( dial_state > DIAL_WHICH_DEVICE ) || IS_DIAL_EVENT ( data ) )\r
176         {\r
177             switch ( dial_state )\r
178             {\r
179             case DIAL_WHICH_DEVICE:\r
180                 dial_which = data - DIAL_BASE;\r
181                 dial_state++;\r
182                 break;\r
183             case DIAL_VALUE_HIGH:\r
184                 dial_value = ( data << 8 );\r
185                 dial_state++;\r
186                 break;\r
187             case DIAL_VALUE_LOW:\r
188                 dial_value |= data;\r
189                 if ( dial_value & 0x8000 ) dial_value -= 0x10000;\r
190                 dials[dial_which] = dial_value;\r
191                 send_dial_event ( dial_which + 1, dial_value * 360 / 256 );\r
192                 dial_state = DIAL_WHICH_DEVICE;\r
193                 break;\r
194             default:\r
195                 /* error: Impossible state value! */\r
196                 break;\r
197             }\r
198         }\r
199         else if ( data == DIAL_INITIALIZED )\r
200         {\r
201             fgState.InputDevsInitialised = GL_TRUE;\r
202             dial_state = DIAL_WHICH_DEVICE;\r
203             serial_putchar(dialbox_port,DIAL_SET_AUTO_DIALS);\r
204             serial_putchar(dialbox_port,0xff);\r
205             serial_putchar(dialbox_port,0xff);\r
206         }\r
207         else  /* Unknown data; try flushing. */\r
208             serial_flush(dialbox_port);\r
209     }\r
210 \r
211     glutTimerFunc ( 2, poll_dials, 0 );\r
212 }\r
213 \r