* make sure we have still a compiling GE with scons/mingw
[blender.git] / intern / ghost / intern / GHOST_SystemX11.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 /**
33  * $Id$
34  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
35  *
36  * This program is free software; you can redistribute it and/or
37  * modify it under the terms of the GNU General Public License
38  * as published by the Free Software Foundation; either version 2
39  * of the License, or (at your option) any later version. The Blender
40  * Foundation also sells licenses for use in proprietary software under
41  * the Blender License.  See http://www.blender.org/BL/ for information
42  * about this.
43  *
44  * This program is distributed in the hope that it will be useful,
45  * but WITHOUT ANY WARRANTY; without even the implied warranty of
46  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
47  * GNU General Public License for more details.
48  *
49  * You should have received a copy of the GNU General Public License
50  * along with this program; if not, write to the Free Software Foundation,
51  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
52  *
53  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
54  * All rights reserved.
55  *
56  * The Original Code is: all of this file.
57  *
58  * Contributor(s): none yet.
59  *
60  * ***** END GPL/BL DUAL LICENSE BLOCK *****
61  */
62
63 #ifdef HAVE_CONFIG_H
64 #include <config.h>
65 #endif
66
67 #include "GHOST_SystemX11.h"
68 #include "GHOST_WindowX11.h"
69 #include "GHOST_WindowManager.h"
70 #include "GHOST_TimerManager.h"
71 #include "GHOST_EventCursor.h"
72 #include "GHOST_EventKey.h"
73 #include "GHOST_EventButton.h"
74 #include "GHOST_EventWheel.h"
75 #include "GHOST_DisplayManagerX11.h"
76
77 #include "GHOST_Debug.h"
78
79 #include <X11/Xatom.h>
80 #include <X11/keysym.h>
81
82 #ifdef __sgi
83
84 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
85 #include <X11/SGIFastAtom.h>
86 #else
87 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
88 #endif
89
90 #endif
91
92 // For timing
93
94 #include <sys/time.h>
95 #include <unistd.h>
96
97 #include <vector>
98
99 using namespace std;
100
101 GHOST_SystemX11::
102 GHOST_SystemX11(
103 ) : 
104         GHOST_System(),
105         m_start_time(0)
106 {
107         m_display = XOpenDisplay(NULL);
108         
109         if (!m_display) return;
110         
111 #ifdef __sgi
112         m_delete_window_atom 
113           = XSGIFastInternAtom(m_display,
114                                "WM_DELETE_WINDOW", 
115                                SGI_XA_WM_DELETE_WINDOW, False);
116 #else
117         m_delete_window_atom 
118           = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
119 #endif
120
121         // compute the initial time
122         timeval tv;
123         if (gettimeofday(&tv,NULL) == -1) {
124                 GHOST_ASSERT(false,"Could not instantiate timer!");
125         }
126
127         m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000);
128 }
129
130         GHOST_TSuccess 
131 GHOST_SystemX11::
132 init(
133 ){
134         GHOST_TSuccess success = GHOST_System::init();
135
136         if (success) {
137                 m_keyboard_vector = new char[32];
138
139                 m_displayManager = new GHOST_DisplayManagerX11(this);
140
141                 if (m_keyboard_vector && m_displayManager) {
142                         return GHOST_kSuccess;
143                 }
144         }
145
146         return GHOST_kFailure;
147 }
148         
149
150
151         GHOST_TUns64
152 GHOST_SystemX11::
153 getMilliSeconds(
154 ) const {
155         timeval tv;
156         if (gettimeofday(&tv,NULL) == -1) {
157                 GHOST_ASSERT(false,"Could not compute time!");
158         }
159
160         return  GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time;
161 }
162         
163         GHOST_TUns8 
164 GHOST_SystemX11::
165 getNumDisplays(
166 ) const {
167         return GHOST_TUns8(1);
168 }
169
170         /**
171          * Returns the dimensions of the main display on this system.
172          * @return The dimension of the main display.
173          */
174         void 
175 GHOST_SystemX11::
176 getMainDisplayDimensions(
177         GHOST_TUns32& width,
178         GHOST_TUns32& height
179 ) const {       
180         if (m_display) {
181                 width  = DisplayWidth(m_display, DefaultScreen(m_display));
182                 height = DisplayHeight(m_display, DefaultScreen(m_display));
183         }
184 }
185
186         /**
187          * Create a new window.
188          * The new window is added to the list of windows managed.
189          * Never explicitly delete the window, use disposeWindow() instead.
190          * @param       title   The name of the window (displayed in the title bar of the window if the OS supports it).
191          * @param       left    The coordinate of the left edge of the window.
192          * @param       top             The coordinate of the top edge of the window.
193          * @param       width   The width the window.
194          * @param       height  The height the window.
195          * @param       state   The state of the window when opened.
196          * @param       type    The type of drawing context installed in this window.
197          * @return      The new window (or 0 if creation failed).
198          */
199         GHOST_IWindow* 
200 GHOST_SystemX11::
201 createWindow(
202         const STR_String& title,
203         GHOST_TInt32 left,
204         GHOST_TInt32 top,
205         GHOST_TUns32 width,
206         GHOST_TUns32 height,
207         GHOST_TWindowState state,
208         GHOST_TDrawingContextType type,
209         bool stereoVisual
210 ){
211         GHOST_WindowX11 * window = 0;
212         
213         if (!m_display) return 0;
214         
215         window = new GHOST_WindowX11 (
216                 this,m_display,title, left, top, width, height, state, type, stereoVisual
217         );
218
219         if (window) {
220
221                 // Install a new protocol for this window - so we can overide
222                 // the default window closure mechanism.
223
224                 XSetWMProtocols(m_display, window->getXWindow(), &m_delete_window_atom, 1);
225
226                 if (window->getValid()) {
227                         // Store the pointer to the window 
228                         m_windowManager->addWindow(window);
229                         
230                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
231                 }
232                 else {
233                         delete window;
234                         window = 0;
235                 }
236         }
237         return window;
238
239 }
240
241         GHOST_WindowX11 * 
242 GHOST_SystemX11::
243 findGhostWindow(
244         Window xwind
245 ) const {
246         
247         if (xwind == 0) return NULL;
248
249         // It is not entirely safe to do this as the backptr may point
250         // to a window that has recently been removed. 
251         // We should always check the window manager's list of windows 
252         // and only process events on these windows.
253
254         vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows();
255
256         vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
257         vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
258         
259         for (; win_it != win_end; ++win_it) {
260                 GHOST_WindowX11 * window = static_cast<GHOST_WindowX11 *>(*win_it);
261                 if (window->getXWindow() == xwind) {
262                         return window;
263                 }
264         }
265         return NULL;
266         
267 }
268
269 static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) {
270         int fd = ConnectionNumber(display);
271         fd_set fds;
272         
273         FD_ZERO(&fds);
274         FD_SET(fd, &fds);
275
276         if (maxSleep == -1) {
277             select(fd + 1, &fds, NULL, NULL, NULL);
278         } else {
279                 timeval tv;
280
281                 tv.tv_sec = maxSleep/1000;
282                 tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000;
283         
284             select(fd + 1, &fds, NULL, NULL, &tv);
285         }
286 }
287
288         bool 
289 GHOST_SystemX11::
290 processEvents(
291         bool waitForEvent
292 ){
293         // Get all the current events -- translate them into 
294         // ghost events and call base class pushEvent() method.
295         
296         bool anyProcessed = false;
297         
298         do {
299                 GHOST_TimerManager* timerMgr = getTimerManager();
300                 
301                 if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
302                         GHOST_TUns64 next = timerMgr->nextFireTime();
303                         
304                         if (next==GHOST_kFireTimeNever) {
305                                 SleepTillEvent(m_display, -1);
306                         } else {
307                                 SleepTillEvent(m_display, next - getMilliSeconds());
308                         }
309                 }
310                 
311                 if (timerMgr->fireTimers(getMilliSeconds())) {
312                         anyProcessed = true;
313                 }
314                 
315                 while (XPending(m_display)) {
316                         XEvent xevent;
317                         XNextEvent(m_display, &xevent);
318                         processEvent(&xevent);
319                         anyProcessed = true;
320                 }
321                 
322                 if (generateWindowExposeEvents()) {
323                         anyProcessed = true;
324                 }
325         } while (waitForEvent && !anyProcessed);
326         
327         return anyProcessed;
328 }
329
330         void
331 GHOST_SystemX11::processEvent(XEvent *xe)
332 {
333         GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);    
334         GHOST_Event * g_event = NULL;
335
336         if (!window) {
337                 return;
338         }
339
340         switch (xe->type) {
341                 case Expose:
342                 {
343                         XExposeEvent & xee = xe->xexpose;
344
345                         if (xee.count == 0) {
346                                 // Only generate a single expose event
347                                 // per read of the event queue.
348
349                                 g_event = new 
350                                 GHOST_Event(
351                                         getMilliSeconds(),
352                                         GHOST_kEventWindowUpdate,
353                                         window
354                                 );                      
355                         }
356                         break;
357                 }
358
359                 case MotionNotify:
360                 {
361                         XMotionEvent &xme = xe->xmotion;
362                         
363                         g_event = new 
364                         GHOST_EventCursor(
365                                 getMilliSeconds(),
366                                 GHOST_kEventCursorMove,
367                                 window,
368                                 xme.x_root,
369                                 xme.y_root
370                         );
371                         break;
372                 }
373
374                 case KeyPress:
375                 case KeyRelease:
376                 {
377                         XKeyEvent *xke = &(xe->xkey);
378                 
379                         KeySym key_sym = XLookupKeysym(xke,0);
380                         char ascii;
381                         
382                         GHOST_TKey gkey = convertXKey(key_sym);
383                         GHOST_TEventType type = (xke->type == KeyPress) ? 
384                                 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
385                         
386                         if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
387                                 ascii = '\0';
388                         }
389                         
390                         g_event = new
391                         GHOST_EventKey(
392                                 getMilliSeconds(),
393                                 type,
394                                 window,
395                                 gkey,
396                                 ascii
397                         );
398                         
399                 break;
400                 }
401
402                 case ButtonPress:
403                 {
404                         /* process wheel mouse events and break */
405                         if (xe->xbutton.button == 4) {
406                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
407                                 break;
408                         }
409                         if (xe->xbutton.button == 5) {
410                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
411                                 break;
412                         }
413                 }
414                 case ButtonRelease:
415                 {
416
417                         XButtonEvent & xbe = xe->xbutton;
418                         GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
419
420                         switch (xbe.button) {
421                                 case Button1 : gbmask = GHOST_kButtonMaskLeft; break;
422                                 case Button3 : gbmask = GHOST_kButtonMaskRight; break;
423                                 default:
424                                 case Button2 : gbmask = GHOST_kButtonMaskMiddle; break;
425                         }
426                         
427                         GHOST_TEventType type = (xbe.type == ButtonPress) ? 
428                                 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
429                         
430                         g_event = new
431                         GHOST_EventButton(
432                                 getMilliSeconds(),
433                                 type,
434                                 window,
435                                 gbmask
436                         );
437                         break;
438                 }
439                         
440                         // change of size, border, layer etc.
441                 case ConfigureNotify:
442                 {
443                         /* XConfigureEvent & xce = xe->xconfigure; */
444
445                         g_event = new 
446                         GHOST_Event(
447                                 getMilliSeconds(),
448                                 GHOST_kEventWindowSize,
449                                 window
450                         );                      
451                         break;
452                 }
453
454                 case FocusIn:
455                 case FocusOut:
456                 {
457                         XFocusChangeEvent &xfe = xe->xfocus;
458                 
459                         // May have to look at the type of event and filter some
460                         // out.
461                                                                         
462                         GHOST_TEventType gtype = (xfe.type == FocusIn) ? 
463                                 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
464
465                         g_event = new 
466                         GHOST_Event(    
467                                 getMilliSeconds(),
468                                 gtype,
469                                 window
470                         );
471                         break;
472
473                 }
474                 case ClientMessage:
475                 {
476                         XClientMessageEvent & xcme = xe->xclient;
477
478 #ifndef __sgi                   
479                         if (xcme.data.l[0] == m_delete_window_atom) {
480                                 g_event = new 
481                                 GHOST_Event(    
482                                         getMilliSeconds(),
483                                         GHOST_kEventWindowClose,
484                                         window
485                                 );
486                         } else {
487                                 /* Unknown client message, ignore */
488                         }
489 #endif
490                         break;
491                 }
492                         
493                 // We're not interested in the following things.(yet...)
494                 case NoExpose : 
495                 case GraphicsExpose :
496                 
497                 case EnterNotify:
498                 case LeaveNotify:
499                         // XCrossingEvents pointer leave enter window.
500                         break;
501                 case MapNotify:
502                 case UnmapNotify:
503                         break;
504                 case MappingNotify:
505                 case ReparentNotify:
506                         break;
507
508         default: {
509                         if(xe->type == window->GetXTablet().MotionEvent) 
510                         {
511                                 XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe;
512                                 window->GetXTablet().CommonData.Pressure= 
513                                         data->axis_data[2]/((float)window->GetXTablet().PressureLevels);
514                         
515                         /* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
516                          * but I got garbage data without it. Found it in the xidump.c source --matt */
517                                 window->GetXTablet().CommonData.Xtilt= 
518                                         (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels);
519                                 window->GetXTablet().CommonData.Ytilt= 
520                                         (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels);
521                         }
522                         else if(xe->type == window->GetXTablet().ProxInEvent) 
523                         {
524                                 XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe;
525                                 if(data->deviceid == window->GetXTablet().StylusID)
526                                         window->GetXTablet().CommonData.Active= 1;
527                                 else if(data->deviceid == window->GetXTablet().EraserID)
528                                         window->GetXTablet().CommonData.Active= 2;
529                         }
530                         else if(xe->type == window->GetXTablet().ProxOutEvent)
531                                 window->GetXTablet().CommonData.Active= 0;
532
533                         break;
534                 }
535         }
536
537         if (g_event) {
538                 pushEvent(g_event);
539         }
540 }
541
542
543         GHOST_TSuccess 
544 GHOST_SystemX11::
545 getModifierKeys(
546         GHOST_ModifierKeys& keys
547 ) const {
548
549         // analyse the masks retuned from XQueryPointer.
550
551         memset(m_keyboard_vector,0,sizeof(m_keyboard_vector));
552
553         XQueryKeymap(m_display,m_keyboard_vector);
554
555         // now translate key symobols into keycodes and
556         // test with vector.
557
558         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
559         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
560         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
561         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
562         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
563         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
564
565         // Shift
566         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
567                 keys.set(GHOST_kModifierKeyLeftShift,true);
568         } else {
569                 keys.set(GHOST_kModifierKeyLeftShift,false);
570         }
571         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
572
573                 keys.set(GHOST_kModifierKeyRightShift,true);
574         } else {
575                 keys.set(GHOST_kModifierKeyRightShift,false);
576         }
577
578         // control (weep)
579         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
580                 keys.set(GHOST_kModifierKeyLeftControl,true);
581         } else {
582                 keys.set(GHOST_kModifierKeyLeftControl,false);
583         }
584         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
585                 keys.set(GHOST_kModifierKeyRightControl,true);
586         } else {
587                 keys.set(GHOST_kModifierKeyRightControl,false);
588         }
589
590         // Alt (yawn)
591         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
592                 keys.set(GHOST_kModifierKeyLeftAlt,true);
593         } else {
594                 keys.set(GHOST_kModifierKeyLeftAlt,false);
595         }       
596         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
597                 keys.set(GHOST_kModifierKeyRightAlt,true);
598         } else {
599                 keys.set(GHOST_kModifierKeyRightAlt,false);
600         }
601         return GHOST_kSuccess;
602 }
603
604         GHOST_TSuccess 
605 GHOST_SystemX11::
606 getButtons(
607         GHOST_Buttons& buttons
608 ) const {
609
610         Window root_return, child_return;
611         int rx,ry,wx,wy;
612         unsigned int mask_return;
613
614         if (XQueryPointer(
615                 m_display,
616                 RootWindow(m_display,DefaultScreen(m_display)),
617                 &root_return,
618                 &child_return,
619                 &rx,&ry,
620                 &wx,&wy,
621                 &mask_return
622         ) == False) {
623                 return GHOST_kFailure;
624         } else {
625
626                 if (mask_return & Button1Mask) {
627                         buttons.set(GHOST_kButtonMaskLeft,true);
628                 } else {
629                         buttons.set(GHOST_kButtonMaskLeft,false);
630                 }
631
632                 if (mask_return & Button2Mask) {
633                         buttons.set(GHOST_kButtonMaskMiddle,true);
634                 } else {
635                         buttons.set(GHOST_kButtonMaskMiddle,false);
636                 }
637
638                 if (mask_return & Button3Mask) {
639                         buttons.set(GHOST_kButtonMaskRight,true);
640                 } else {
641                         buttons.set(GHOST_kButtonMaskRight,false);
642                 }
643         }       
644
645         return GHOST_kSuccess;
646 }
647
648
649         GHOST_TSuccess 
650 GHOST_SystemX11::
651 getCursorPosition(
652         GHOST_TInt32& x,
653         GHOST_TInt32& y
654 ) const {
655
656         Window root_return, child_return;
657         int rx,ry,wx,wy;
658         unsigned int mask_return;
659
660         if (XQueryPointer(
661                 m_display,
662                 RootWindow(m_display,DefaultScreen(m_display)),
663                 &root_return,
664                 &child_return,
665                 &rx,&ry,
666                 &wx,&wy,
667                 &mask_return
668         ) == False) {
669                 return GHOST_kFailure;
670         } else {
671                 x = rx;
672                 y = ry;
673         }       
674         return GHOST_kSuccess;
675 }
676
677
678         GHOST_TSuccess 
679 GHOST_SystemX11::
680 setCursorPosition(
681         GHOST_TInt32 x,
682         GHOST_TInt32 y
683 ) const {
684
685         // This is a brute force move in screen coordinates
686         // XWarpPointer does relative moves so first determine the
687         // current pointer position.
688
689         int cx,cy;
690         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
691                 return GHOST_kFailure;
692         }
693
694         int relx = x-cx;
695         int rely = y-cy;
696
697         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
698         XFlush(m_display);
699         
700         return GHOST_kSuccess;
701 }
702
703
704         void
705 GHOST_SystemX11::
706 addDirtyWindow(
707         GHOST_WindowX11 * bad_wind
708 ){
709
710         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
711         
712         m_dirty_windows.push_back(bad_wind);
713 }
714
715
716         bool
717 GHOST_SystemX11::
718 generateWindowExposeEvents(
719 ){
720
721         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
722         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
723         bool anyProcessed = false;
724         
725         for (;w_start != w_end; ++w_start) {
726                 GHOST_Event * g_event = new 
727                         GHOST_Event(
728                                 getMilliSeconds(),
729                                 GHOST_kEventWindowUpdate,
730                                 *w_start
731                         );                      
732
733                 (*w_start)->validate(); 
734                 
735                 if (g_event) {
736                         pushEvent(g_event);
737                         anyProcessed = true;
738                 }
739         }
740
741         m_dirty_windows.clear();
742         return anyProcessed;
743 }
744
745 #define GXMAP(k,x,y) case x: k = y; break; 
746
747         GHOST_TKey
748 GHOST_SystemX11::
749 convertXKey(
750         KeySym key
751 ){
752         GHOST_TKey type;
753
754         if ((key >= XK_A) && (key <= XK_Z)) {
755                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
756         } else if ((key >= XK_a) && (key <= XK_z)) {
757                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
758         } else if ((key >= XK_0) && (key <= XK_9)) {
759                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
760         } else if ((key >= XK_F1) && (key <= XK_F24)) {
761                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
762 #if defined(__sun) || defined(__sun__) 
763                 /* This is a bit of a hack, but it looks like sun
764                    Used F11 and friends for its special keys Stop,again etc..
765                    So this little patch enables F11 and F12 to work as expected
766                    following link has documentation on it: 
767                    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408
768                    also from /usr/include/X11/Sunkeysym.h 
769 #define SunXK_F36               0x1005FF10      // Labeled F11
770 #define SunXK_F37               0x1005FF11      // Labeled F12 
771
772                                 mein@cs.umn.edu
773                  */
774                 
775         } else if (key == 268828432) {
776                 type = GHOST_kKeyF11;
777         } else if (key == 268828433) {
778                 type = GHOST_kKeyF12;
779 #endif
780         } else {
781                 switch(key) {
782                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
783                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
784                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
785                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
786                         GXMAP(type,XK_space,            GHOST_kKeySpace);
787                         
788                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
789                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
790                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
791                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
792                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
793                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
794                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
795                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
796                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
797                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
798                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
799                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
800                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
801                         
802                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
803                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
804                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
805                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
806                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
807                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
808
809                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
810                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
811                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
812                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
813                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
814                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
815
816                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
817                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
818                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
819                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
820
821                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
822                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
823                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
824                         
825                                 /* keypad events */
826                                 
827                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
828                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
829                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
830                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
831                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
832                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
833                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
834                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
835                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
836                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
837                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
838
839                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
840                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
841                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
842                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
843                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
844                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
845                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
846                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
847                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
848                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
849                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
850
851                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
852                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
853                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
854                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
855                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
856
857                                 /* some extra sun cruft (NICE KEYBOARD!) */
858 #ifdef __sun__
859                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
860                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
861                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
862                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
863                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
864
865                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
866                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
867 #endif
868
869                         default :
870                                 type = GHOST_kKeyUnknown;
871                                 break;
872                 }
873         }
874
875         return type;
876 }
877
878 #undef GXMAP