Ignore WM_DELETE_WINDOW on IRIX (somebody smarter than me please
[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
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::
332 processEvent(
333         XEvent *xe
334 ){
335         GHOST_WindowX11 * window = findGhostWindow(xe->xany.window);    
336         GHOST_Event * g_event = NULL;
337
338         if (!window) {
339                 return;
340         }
341                 
342         switch (xe->type) {
343                 case Expose:
344                 {
345                         XExposeEvent & xee = xe->xexpose;
346
347                         if (xee.count == 0) {
348                                 // Only generate a single expose event
349                                 // per read of the event queue.
350
351                                 g_event = new 
352                                 GHOST_Event(
353                                         getMilliSeconds(),
354                                         GHOST_kEventWindowUpdate,
355                                         window
356                                 );                      
357                         }
358                         break;
359                 }
360                 case MotionNotify:
361                 {
362                         XMotionEvent &xme = xe->xmotion;
363                         
364                         g_event = new 
365                         GHOST_EventCursor(
366                                 getMilliSeconds(),
367                                 GHOST_kEventCursorMove,
368                                 window,
369                                 xme.x_root,
370                                 xme.y_root
371                         );
372                         break;
373                 }
374
375                 case KeyPress:
376                 case KeyRelease:
377                 {
378                         XKeyEvent *xke = &(xe->xkey);
379                 
380                         KeySym key_sym = XLookupKeysym(xke,0);
381                         char ascii;
382                         
383                         GHOST_TKey gkey = convertXKey(key_sym);
384                         GHOST_TEventType type = (xke->type == KeyPress) ? 
385                                 GHOST_kEventKeyDown : GHOST_kEventKeyUp;
386                         
387                         if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
388                                 ascii = '\0';
389                         }
390                         
391                         g_event = new
392                         GHOST_EventKey(
393                                 getMilliSeconds(),
394                                 type,
395                                 window,
396                                 gkey,
397                                 ascii
398                         );
399                         
400                 break;
401                 }
402
403                 case ButtonPress:
404                 {
405                         /* process wheel mouse events and break */
406                         if (xe->xbutton.button == 4) {
407                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
408                                 break;
409                         }
410                         if (xe->xbutton.button == 5) {
411                                 g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
412                                 break;
413                         }
414                 }
415                 case ButtonRelease:
416                 {
417
418                         XButtonEvent & xbe = xe->xbutton;
419                         GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
420
421                         switch (xbe.button) {
422                                 case Button1 : gbmask = GHOST_kButtonMaskLeft; break;
423                                 case Button3 : gbmask = GHOST_kButtonMaskRight; break;
424                                 default:
425                                 case Button2 : gbmask = GHOST_kButtonMaskMiddle; break;
426                         }
427                         
428                         GHOST_TEventType type = (xbe.type == ButtonPress) ? 
429                                 GHOST_kEventButtonDown : GHOST_kEventButtonUp;
430                         
431                         g_event = new
432                         GHOST_EventButton(
433                                 getMilliSeconds(),
434                                 type,
435                                 window,
436                                 gbmask
437                         );
438                         break;
439                 }
440                         
441                         // change of size, border, layer etc.
442                 case ConfigureNotify:
443                 {
444                         /* XConfigureEvent & xce = xe->xconfigure; */
445
446                         g_event = new 
447                         GHOST_Event(
448                                 getMilliSeconds(),
449                                 GHOST_kEventWindowSize,
450                                 window
451                         );                      
452                         break;
453                 }
454
455                 case FocusIn:
456                 case FocusOut:
457                 {
458                         XFocusChangeEvent &xfe = xe->xfocus;
459                 
460                         // May have to look at the type of event and filter some
461                         // out.
462                                                                         
463                         GHOST_TEventType gtype = (xfe.type == FocusIn) ? 
464                                 GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
465
466                         g_event = new 
467                         GHOST_Event(    
468                                 getMilliSeconds(),
469                                 gtype,
470                                 window
471                         );
472                         break;
473
474                 }
475                 case ClientMessage:
476                 {
477                         XClientMessageEvent & xcme = xe->xclient;
478
479 #ifndef __sgi                   
480                         if (xcme.data.l[0] == m_delete_window_atom) {
481                                 g_event = new 
482                                 GHOST_Event(    
483                                         getMilliSeconds(),
484                                         GHOST_kEventWindowClose,
485                                         window
486                                 );
487                         } else {
488                                 /* Unknown client message, ignore */
489                         }
490 #endif
491                         break;
492                 }
493                         
494                 // We're not interested in the following things.(yet...)
495                 case NoExpose : 
496                 case GraphicsExpose :
497                 
498                 case EnterNotify:
499                 case LeaveNotify:
500                         // XCrossingEvents pointer leave enter window.
501                         break;
502                 case MapNotify:
503                 case UnmapNotify:
504                         break;
505                 case MappingNotify:
506                 case ReparentNotify:
507                         break;
508
509                 default:
510                         break;
511         }
512
513         if (g_event) {
514                 pushEvent(g_event);
515         }
516 }
517
518
519         GHOST_TSuccess 
520 GHOST_SystemX11::
521 getModifierKeys(
522         GHOST_ModifierKeys& keys
523 ) const {
524
525         // analyse the masks retuned from XQueryPointer.
526
527         memset(m_keyboard_vector,32,0);
528
529         XQueryKeymap(m_display,m_keyboard_vector);
530
531         // now translate key symobols into keycodes and
532         // test with vector.
533
534         const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L);
535         const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R);
536         const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L);
537         const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R);
538         const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L);
539         const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R);
540
541         // Shift
542         if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) {
543                 keys.set(GHOST_kModifierKeyLeftShift,true);
544         } else {
545                 keys.set(GHOST_kModifierKeyLeftShift,false);
546         }
547         if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) {
548
549                 keys.set(GHOST_kModifierKeyRightShift,true);
550         } else {
551                 keys.set(GHOST_kModifierKeyRightShift,false);
552         }
553
554         // control (weep)
555         if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) {
556                 keys.set(GHOST_kModifierKeyLeftControl,true);
557         } else {
558                 keys.set(GHOST_kModifierKeyLeftControl,false);
559         }
560         if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) {
561                 keys.set(GHOST_kModifierKeyRightControl,true);
562         } else {
563                 keys.set(GHOST_kModifierKeyRightControl,false);
564         }
565
566         // Alt (yawn)
567         if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) {
568                 keys.set(GHOST_kModifierKeyLeftAlt,true);
569         } else {
570                 keys.set(GHOST_kModifierKeyLeftAlt,false);
571         }       
572         if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) {
573                 keys.set(GHOST_kModifierKeyRightAlt,true);
574         } else {
575                 keys.set(GHOST_kModifierKeyRightAlt,false);
576         }
577         return GHOST_kSuccess;
578 }
579
580         GHOST_TSuccess 
581 GHOST_SystemX11::
582 getButtons(
583         GHOST_Buttons& buttons
584 ) const {
585
586         Window root_return, child_return;
587         int rx,ry,wx,wy;
588         unsigned int mask_return;
589
590         if (XQueryPointer(
591                 m_display,
592                 RootWindow(m_display,DefaultScreen(m_display)),
593                 &root_return,
594                 &child_return,
595                 &rx,&ry,
596                 &wx,&wy,
597                 &mask_return
598         ) == False) {
599                 return GHOST_kFailure;
600         } else {
601
602                 if (mask_return & Button1Mask) {
603                         buttons.set(GHOST_kButtonMaskLeft,true);
604                 } else {
605                         buttons.set(GHOST_kButtonMaskLeft,false);
606                 }
607
608                 if (mask_return & Button2Mask) {
609                         buttons.set(GHOST_kButtonMaskMiddle,true);
610                 } else {
611                         buttons.set(GHOST_kButtonMaskMiddle,false);
612                 }
613
614                 if (mask_return & Button3Mask) {
615                         buttons.set(GHOST_kButtonMaskRight,true);
616                 } else {
617                         buttons.set(GHOST_kButtonMaskRight,false);
618                 }
619         }       
620
621         return GHOST_kSuccess;
622 }
623
624
625         GHOST_TSuccess 
626 GHOST_SystemX11::
627 getCursorPosition(
628         GHOST_TInt32& x,
629         GHOST_TInt32& y
630 ) const {
631
632         Window root_return, child_return;
633         int rx,ry,wx,wy;
634         unsigned int mask_return;
635
636         if (XQueryPointer(
637                 m_display,
638                 RootWindow(m_display,DefaultScreen(m_display)),
639                 &root_return,
640                 &child_return,
641                 &rx,&ry,
642                 &wx,&wy,
643                 &mask_return
644         ) == False) {
645                 return GHOST_kFailure;
646         } else {
647                 x = rx;
648                 y = ry;
649         }       
650         return GHOST_kSuccess;
651 }
652
653
654         GHOST_TSuccess 
655 GHOST_SystemX11::
656 setCursorPosition(
657         GHOST_TInt32 x,
658         GHOST_TInt32 y
659 ) const {
660
661         // This is a brute force move in screen coordinates
662         // XWarpPointer does relative moves so first determine the
663         // current pointer position.
664
665         int cx,cy;
666         if (getCursorPosition(cx,cy) == GHOST_kFailure) {
667                 return GHOST_kFailure;
668         }
669
670         int relx = x-cx;
671         int rely = y-cy;
672
673         XWarpPointer(m_display,None,None,0,0,0,0,relx,rely);
674         XFlush(m_display);
675         
676         return GHOST_kSuccess;
677 }
678
679
680         void
681 GHOST_SystemX11::
682 addDirtyWindow(
683         GHOST_WindowX11 * bad_wind
684 ){
685
686         GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
687         
688         m_dirty_windows.push_back(bad_wind);
689 }
690
691
692         bool
693 GHOST_SystemX11::
694 generateWindowExposeEvents(
695 ){
696
697         vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
698         vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
699         bool anyProcessed = false;
700         
701         for (;w_start != w_end; ++w_start) {
702                 GHOST_Event * g_event = new 
703                         GHOST_Event(
704                                 getMilliSeconds(),
705                                 GHOST_kEventWindowUpdate,
706                                 *w_start
707                         );                      
708
709                 (*w_start)->validate(); 
710                 
711                 if (g_event) {
712                         pushEvent(g_event);
713                         anyProcessed = true;
714                 }
715         }
716
717         m_dirty_windows.clear();
718         return anyProcessed;
719 }
720
721 #define GXMAP(k,x,y) case x: k = y; break; 
722
723         GHOST_TKey
724 GHOST_SystemX11::
725 convertXKey(
726         unsigned int key
727 ){
728         GHOST_TKey type;
729
730         if ((key >= XK_A) && (key <= XK_Z)) {
731                 type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA));
732         } else if ((key >= XK_a) && (key <= XK_z)) {
733                 type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
734         } else if ((key >= XK_0) && (key <= XK_9)) {
735                 type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
736         } else if ((key >= XK_F1) && (key <= XK_F24)) {
737                 type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
738         } else {
739                 switch(key) {
740                         GXMAP(type,XK_BackSpace,        GHOST_kKeyBackSpace);
741                         GXMAP(type,XK_Tab,              GHOST_kKeyTab);
742                         GXMAP(type,XK_Return,           GHOST_kKeyEnter);
743                         GXMAP(type,XK_Escape,           GHOST_kKeyEsc);
744                         GXMAP(type,XK_space,            GHOST_kKeySpace);
745                         
746                         GXMAP(type,XK_Linefeed,         GHOST_kKeyLinefeed);
747                         GXMAP(type,XK_semicolon,        GHOST_kKeySemicolon);
748                         GXMAP(type,XK_period,           GHOST_kKeyPeriod);
749                         GXMAP(type,XK_comma,            GHOST_kKeyComma);
750                         GXMAP(type,XK_quoteright,       GHOST_kKeyQuote);
751                         GXMAP(type,XK_quoteleft,        GHOST_kKeyAccentGrave);
752                         GXMAP(type,XK_minus,            GHOST_kKeyMinus);
753                         GXMAP(type,XK_slash,            GHOST_kKeySlash);
754                         GXMAP(type,XK_backslash,        GHOST_kKeyBackslash);
755                         GXMAP(type,XK_equal,            GHOST_kKeyEqual);
756                         GXMAP(type,XK_bracketleft,      GHOST_kKeyLeftBracket);
757                         GXMAP(type,XK_bracketright,     GHOST_kKeyRightBracket);
758                         GXMAP(type,XK_Pause,            GHOST_kKeyPause);
759                         
760                         GXMAP(type,XK_Shift_L,          GHOST_kKeyLeftShift);
761                         GXMAP(type,XK_Shift_R,          GHOST_kKeyRightShift);
762                         GXMAP(type,XK_Control_L,        GHOST_kKeyLeftControl);
763                         GXMAP(type,XK_Control_R,        GHOST_kKeyRightControl);
764                         GXMAP(type,XK_Alt_L,            GHOST_kKeyLeftAlt);
765                         GXMAP(type,XK_Alt_R,            GHOST_kKeyRightAlt);
766
767                         GXMAP(type,XK_Insert,           GHOST_kKeyInsert);
768                         GXMAP(type,XK_Delete,           GHOST_kKeyDelete);
769                         GXMAP(type,XK_Home,                     GHOST_kKeyHome);
770                         GXMAP(type,XK_End,                      GHOST_kKeyEnd);
771                         GXMAP(type,XK_Page_Up,          GHOST_kKeyUpPage);
772                         GXMAP(type,XK_Page_Down,        GHOST_kKeyDownPage);
773
774                         GXMAP(type,XK_Left,                     GHOST_kKeyLeftArrow);
775                         GXMAP(type,XK_Right,            GHOST_kKeyRightArrow);
776                         GXMAP(type,XK_Up,                       GHOST_kKeyUpArrow);
777                         GXMAP(type,XK_Down,                     GHOST_kKeyDownArrow);
778
779                         GXMAP(type,XK_Caps_Lock,        GHOST_kKeyCapsLock);
780                         GXMAP(type,XK_Scroll_Lock,      GHOST_kKeyScrollLock);
781                         GXMAP(type,XK_Num_Lock,         GHOST_kKeyNumLock);
782                         
783                                 /* keypad events */
784                                 
785                         GXMAP(type,XK_KP_0,                     GHOST_kKeyNumpad0);
786                         GXMAP(type,XK_KP_1,                     GHOST_kKeyNumpad1);
787                         GXMAP(type,XK_KP_2,                     GHOST_kKeyNumpad2);
788                         GXMAP(type,XK_KP_3,                     GHOST_kKeyNumpad3);
789                         GXMAP(type,XK_KP_4,                     GHOST_kKeyNumpad4);
790                         GXMAP(type,XK_KP_5,                     GHOST_kKeyNumpad5);
791                         GXMAP(type,XK_KP_6,                     GHOST_kKeyNumpad6);
792                         GXMAP(type,XK_KP_7,                     GHOST_kKeyNumpad7);
793                         GXMAP(type,XK_KP_8,                     GHOST_kKeyNumpad8);
794                         GXMAP(type,XK_KP_9,                     GHOST_kKeyNumpad9);
795                         GXMAP(type,XK_KP_Decimal,       GHOST_kKeyNumpadPeriod);
796
797                         GXMAP(type,XK_KP_Insert,        GHOST_kKeyNumpad0);
798                         GXMAP(type,XK_KP_End,           GHOST_kKeyNumpad1);
799                         GXMAP(type,XK_KP_Down,          GHOST_kKeyNumpad2);
800                         GXMAP(type,XK_KP_Page_Down,     GHOST_kKeyNumpad3);
801                         GXMAP(type,XK_KP_Left,          GHOST_kKeyNumpad4);
802                         GXMAP(type,XK_KP_Begin,         GHOST_kKeyNumpad5);
803                         GXMAP(type,XK_KP_Right,         GHOST_kKeyNumpad6);
804                         GXMAP(type,XK_KP_Home,          GHOST_kKeyNumpad7);
805                         GXMAP(type,XK_KP_Up,            GHOST_kKeyNumpad8);
806                         GXMAP(type,XK_KP_Page_Up,       GHOST_kKeyNumpad9);
807                         GXMAP(type,XK_KP_Delete,        GHOST_kKeyNumpadPeriod);
808
809                         GXMAP(type,XK_KP_Enter,         GHOST_kKeyNumpadEnter);
810                         GXMAP(type,XK_KP_Add,           GHOST_kKeyNumpadPlus);
811                         GXMAP(type,XK_KP_Subtract,      GHOST_kKeyNumpadMinus);
812                         GXMAP(type,XK_KP_Multiply,      GHOST_kKeyNumpadAsterisk);
813                         GXMAP(type,XK_KP_Divide,        GHOST_kKeyNumpadSlash);
814
815                                 /* some extra sun cruft (NICE KEYBOARD!) */
816 #ifdef __sun__
817                         GXMAP(type,0xffde,                      GHOST_kKeyNumpad1);
818                         GXMAP(type,0xffe0,                      GHOST_kKeyNumpad3);
819                         GXMAP(type,0xffdc,                      GHOST_kKeyNumpad5);
820                         GXMAP(type,0xffd8,                      GHOST_kKeyNumpad7);
821                         GXMAP(type,0xffda,                      GHOST_kKeyNumpad9);
822
823                         GXMAP(type,0xffd6,                      GHOST_kKeyNumpadSlash);
824                         GXMAP(type,0xffd7,                      GHOST_kKeyNumpadAsterisk);
825 #endif
826
827                         default :
828                                 type = GHOST_kKeyUnknown;
829                                 break;
830                 }
831         }
832
833         return type;
834 }
835
836 #undef GXMAP
837
838