0031682: Visualization - Prs3d_ShadingAspect::SetTransparency() has no effect with...
[occt.git] / src / Xw / Xw_Window.cxx
1 // Created on: 2013-04-06
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Xw_Window.hxx>
17
18 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
19
20 #include <Aspect_Convert.hxx>
21 #include <Aspect_WindowDefinitionError.hxx>
22 #include <Message.hxx>
23 #include <Message_Messenger.hxx>
24
25 //#include <X11/XF86keysym.h>
26
27 #if defined(HAVE_EGL) || defined(HAVE_GLES2)
28   #include <EGL/egl.h>
29   #ifndef EGL_OPENGL_ES3_BIT
30     #define EGL_OPENGL_ES3_BIT 0x00000040
31   #endif
32 #else
33   #include <GL/glx.h>
34
35 namespace
36 {
37
38   //! Search for RGBA double-buffered visual with stencil buffer.
39   static int TheDoubleBuffVisual[] =
40   {
41     GLX_RGBA,
42     GLX_DEPTH_SIZE, 16,
43     GLX_STENCIL_SIZE, 1,
44     GLX_DOUBLEBUFFER,
45     None
46   };
47
48   //! Search for RGBA double-buffered visual with stencil buffer.
49   static int TheDoubleBuffFBConfig[] =
50   {
51     GLX_X_RENDERABLE,  True,
52     GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
53     GLX_RENDER_TYPE,   GLX_RGBA_BIT,
54     GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
55     GLX_DEPTH_SIZE,    16,
56     GLX_STENCIL_SIZE,  1,
57     GLX_DOUBLEBUFFER,  True,
58     None
59   };
60
61 }
62
63 #endif
64
65 IMPLEMENT_STANDARD_RTTIEXT(Xw_Window, Aspect_Window)
66
67 // =======================================================================
68 // function : Xw_Window
69 // purpose  :
70 // =======================================================================
71 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
72                       const Standard_CString theTitle,
73                       const Standard_Integer thePxLeft,
74                       const Standard_Integer thePxTop,
75                       const Standard_Integer thePxWidth,
76                       const Standard_Integer thePxHeight,
77                       const Aspect_FBConfig  theFBConfig)
78 : Aspect_Window(),
79   myDisplay  (theXDisplay),
80   myXWindow  (0),
81   myFBConfig (theFBConfig),
82   myXLeft    (thePxLeft),
83   myYTop     (thePxTop),
84   myXRight   (thePxLeft + thePxWidth),
85   myYBottom  (thePxTop + thePxHeight),
86   myIsOwnWin (Standard_True)
87 {
88   if (thePxWidth <= 0 || thePxHeight <= 0)
89   {
90     throw Aspect_WindowDefinitionError("Xw_Window, Coordinate(s) out of range");
91   }
92   else if (theXDisplay.IsNull())
93   {
94     throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
95     return;
96   }
97
98   Display* aDisp   = myDisplay->GetDisplay();
99   int      aScreen = DefaultScreen(aDisp);
100   Window   aParent = RootWindow   (aDisp, aScreen);
101   XVisualInfo* aVisInfo = NULL;
102
103 #if defined(HAVE_EGL) || defined(HAVE_GLES2)
104   EGLDisplay anEglDisplay = eglGetDisplay (aDisp);
105   EGLint aVerMajor = 0; EGLint aVerMinor = 0;
106   XVisualInfo aVisInfoTmp; memset (&aVisInfoTmp, 0, sizeof(aVisInfoTmp));
107   if (anEglDisplay != EGL_NO_DISPLAY
108    && eglInitialize (anEglDisplay, &aVerMajor, &aVerMinor) == EGL_TRUE)
109   {
110     EGLint aConfigAttribs[] =
111     {
112       EGL_RED_SIZE,     8,
113       EGL_GREEN_SIZE,   8,
114       EGL_BLUE_SIZE,    8,
115       EGL_ALPHA_SIZE,   0,
116       EGL_DEPTH_SIZE,   24,
117       EGL_STENCIL_SIZE, 8,
118     #if defined(HAVE_GLES2)
119       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
120     #else
121       EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
122     #endif
123       EGL_NONE
124     };
125
126     EGLint aNbConfigs = 0;
127     void* anEglConfig = NULL;
128     for (Standard_Integer aGlesVer = 3; aGlesVer >= 2; --aGlesVer)
129     {
130     #if defined(GL_ES_VERSION_2_0)
131       aConfigAttribs[6 * 2 + 1] = aGlesVer == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
132     #else
133       if (aGlesVer == 2)
134       {
135         break;
136       }
137     #endif
138
139       if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) == EGL_TRUE
140        && anEglConfig != NULL)
141       {
142         break;
143       }
144       eglGetError();
145
146       aConfigAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer
147       if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) == EGL_TRUE
148        && anEglConfig != NULL)
149       {
150         break;
151       }
152       eglGetError();
153     }
154
155     if (anEglConfig != NULL
156      && eglGetConfigAttrib (anEglDisplay, anEglConfig, EGL_NATIVE_VISUAL_ID, (EGLint* )&aVisInfoTmp.visualid) == EGL_TRUE)
157     {
158       int aNbVisuals = 0;
159       aVisInfoTmp.screen = DefaultScreen (aDisp);
160       aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbVisuals);
161     }
162   }
163   if (aVisInfo == NULL)
164   {
165     Message::SendWarning ("Warning: cannot choose Visual using EGL while creating Xw_Window");
166   }
167 #else
168   int aDummy = 0;
169   if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy))
170   {
171     throw Aspect_WindowDefinitionError("Xw_Window, GLX extension is unavailable");
172     return;
173   }
174   if (myFBConfig == NULL)
175   {
176     // FBConfigs were added in GLX version 1.3
177     int aGlxMajor = 0;
178     int aGlxMinor = 0;
179     const bool hasFBCfg = glXQueryVersion (aDisp, &aGlxMajor, &aGlxMinor)
180                        && ((aGlxMajor == 1 && aGlxMinor >= 3) || (aGlxMajor > 1));
181     if (hasFBCfg)
182     {
183       int aFBCount = 0;
184       GLXFBConfig* aFBCfgList = NULL;
185       if (hasFBCfg)
186       {
187         aFBCfgList = glXChooseFBConfig (aDisp, aScreen, TheDoubleBuffFBConfig, &aFBCount);
188       }
189       if(aFBCfgList != NULL
190       && aFBCount >= 1)
191       {
192         myFBConfig = aFBCfgList[0];
193         aVisInfo   = glXGetVisualFromFBConfig (aDisp, myFBConfig);
194       }
195       XFree (aFBCfgList);
196     }
197   }
198
199   if (aVisInfo == NULL)
200   {
201     aVisInfo = glXChooseVisual (aDisp, aScreen, TheDoubleBuffVisual);
202   }
203   if (aVisInfo == NULL)
204   {
205     throw Aspect_WindowDefinitionError("Xw_Window, couldn't find compatible Visual (RGBA, double-buffered)");
206     return;
207   }
208 #endif
209
210   unsigned long aMask = 0;
211   XSetWindowAttributes aWinAttr;
212   memset(&aWinAttr, 0, sizeof(XSetWindowAttributes));
213   aWinAttr.event_mask = ExposureMask | StructureNotifyMask;
214   aMask |= CWEventMask;
215   if (aVisInfo != NULL)
216   {
217     aWinAttr.colormap = XCreateColormap(aDisp, aParent, aVisInfo->visual, AllocNone);
218   }
219   aWinAttr.border_pixel = 0;
220   aWinAttr.override_redirect = False;
221
222   myXWindow = XCreateWindow(aDisp, aParent,
223                             myXLeft, myYTop, thePxWidth, thePxHeight,
224                             0, aVisInfo != NULL ? aVisInfo->depth : CopyFromParent,
225                             InputOutput,
226                             aVisInfo != NULL ? aVisInfo->visual : CopyFromParent,
227                             CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttr);
228   if (aVisInfo != NULL)
229   {
230     XFree (aVisInfo);
231     aVisInfo = NULL;
232   }
233   if (myXWindow == 0)
234   {
235     throw Aspect_WindowDefinitionError("Xw_Window, Unable to create window");
236     return;
237   }
238
239   // if parent - desktop
240   XSizeHints aSizeHints;
241   aSizeHints.x      = myXLeft;
242   aSizeHints.y      = myYTop;
243   aSizeHints.flags  = PPosition;
244   aSizeHints.width  = thePxWidth;
245   aSizeHints.height = thePxHeight;
246   aSizeHints.flags |= PSize;
247   XSetStandardProperties (aDisp, myXWindow, theTitle, theTitle, None,
248                           NULL, 0, &aSizeHints);
249
250   /*XTextProperty aTitleProperty;
251   aTitleProperty.encoding = None;
252   char* aTitle = (char* )theTitle;
253   Xutf8TextListToTextProperty(aDisp, &aTitle, 1, XUTF8StringStyle, &aTitleProperty);
254   XSetWMName      (aDisp, myXWindow, &aTitleProperty);
255   XSetWMProperties(aDisp, myXWindow, &aTitleProperty, &aTitleProperty, NULL, 0, NULL, NULL, NULL);*/
256
257   XFlush (aDisp);
258 }
259
260 // =======================================================================
261 // function : Xw_Window
262 // purpose  :
263 // =======================================================================
264 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
265                       const Window theXWin,
266                       const Aspect_FBConfig theFBConfig)
267 : Aspect_Window(),
268   myDisplay  (theXDisplay),
269   myXWindow  (theXWin),
270   myFBConfig (theFBConfig),
271   myXLeft    (0),
272   myYTop     (0),
273   myXRight   (512),
274   myYBottom  (512),
275   myIsOwnWin (Standard_False)
276 {
277   if (theXWin == 0)
278   {
279     throw Aspect_WindowDefinitionError("Xw_Window, given invalid X window");
280     return;
281   }
282   else if (theXDisplay.IsNull())
283   {
284     throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
285     return;
286   }
287 #if !defined(HAVE_EGL) && !defined(HAVE_GLES2)
288   int aDummy = 0;
289   if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy))
290   {
291     myXWindow = 0;
292     throw Aspect_WindowDefinitionError("Xw_Window, GLX extension is unavailable");
293     return;
294   }
295 #endif
296
297   Display* aDisp = myDisplay->GetDisplay();
298
299   XWindowAttributes aWinAttr;
300   XGetWindowAttributes (aDisp, myXWindow, &aWinAttr);
301   XVisualInfo aVisInfoTmp;
302   aVisInfoTmp.visualid = aWinAttr.visual->visualid;
303   aVisInfoTmp.screen   = DefaultScreen (aDisp);
304   int aNbItems = 0;
305   XVisualInfo* aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbItems);
306   if (aVisInfo == NULL)
307   {
308     throw Aspect_WindowDefinitionError("Xw_Window, Visual is unavailable");
309     return;
310   }
311   XFree (aVisInfo);
312
313   DoResize();
314 }
315
316 // =======================================================================
317 // function : ~Xw_Window
318 // purpose  :
319 // =======================================================================
320 Xw_Window::~Xw_Window()
321 {
322   if (myIsOwnWin && myXWindow != 0 && !myDisplay.IsNull())
323   {
324     XDestroyWindow (myDisplay->GetDisplay(), myXWindow);
325   }
326 }
327
328 // =======================================================================
329 // function : XWindow
330 // purpose  :
331 // =======================================================================
332 Window Xw_Window::XWindow() const
333 {
334   return myXWindow;
335 }
336
337 // =======================================================================
338 // function : IsMapped
339 // purpose  :
340 // =======================================================================
341 Standard_Boolean Xw_Window::IsMapped() const
342 {
343   if (myXWindow == 0)
344   {
345     return false;
346   }
347   else if (IsVirtual())
348   {
349     return Standard_True;
350   }
351
352   XFlush (myDisplay->GetDisplay());
353   XWindowAttributes aWinAttr;
354   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
355   return aWinAttr.map_state == IsUnviewable
356       || aWinAttr.map_state == IsViewable;
357 }
358
359 // =======================================================================
360 // function : Map
361 // purpose  :
362 // =======================================================================
363 void Xw_Window::Map() const
364 {
365   if (IsVirtual() || myXWindow == 0)
366   {
367     return;
368   }
369
370   XMapWindow (myDisplay->GetDisplay(), myXWindow);
371   XFlush (myDisplay->GetDisplay());
372 }
373
374 // =======================================================================
375 // function : Unmap
376 // purpose  :
377 // =======================================================================
378 void Xw_Window::Unmap() const
379 {
380   if (IsVirtual() || myXWindow == 0)
381   {
382     return;
383   }
384
385   XIconifyWindow (myDisplay->GetDisplay(), myXWindow, DefaultScreen(myDisplay->GetDisplay()));
386 }
387
388 // =======================================================================
389 // function : DoResize
390 // purpose  :
391 // =======================================================================
392 Aspect_TypeOfResize Xw_Window::DoResize()
393 {
394   if (myXWindow == 0)
395   {
396     return Aspect_TOR_UNKNOWN;
397   }
398
399   XFlush (myDisplay->GetDisplay());
400   XWindowAttributes aWinAttr;
401   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
402   if (aWinAttr.map_state == IsUnmapped)
403   {
404     return Aspect_TOR_UNKNOWN;
405   }
406
407   Standard_Integer aMask = 0;
408   Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN;
409
410   if (Abs (aWinAttr.x                     - myXLeft  ) > 2) aMask |= 1;
411   if (Abs ((aWinAttr.x + aWinAttr.width)  - myXRight ) > 2) aMask |= 2;
412   if (Abs (aWinAttr.y                     - myYTop   ) > 2) aMask |= 4;
413   if (Abs ((aWinAttr.y + aWinAttr.height) - myYBottom) > 2) aMask |= 8;
414   switch (aMask)
415   {
416     case 0:  aMode = Aspect_TOR_NO_BORDER;               break;
417     case 1:  aMode = Aspect_TOR_LEFT_BORDER;             break;
418     case 2:  aMode = Aspect_TOR_RIGHT_BORDER;            break;
419     case 4:  aMode = Aspect_TOR_TOP_BORDER;              break;
420     case 5:  aMode = Aspect_TOR_LEFT_AND_TOP_BORDER;     break;
421     case 6:  aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER;    break;
422     case 8:  aMode = Aspect_TOR_BOTTOM_BORDER;           break;
423     case 9:  aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER;  break;
424     case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break;
425     default: break;
426   }
427
428   myXLeft   = aWinAttr.x;
429   myXRight  = aWinAttr.x + aWinAttr.width;
430   myYTop    = aWinAttr.y;
431   myYBottom = aWinAttr.y + aWinAttr.height;
432   return aMode;
433 }
434
435 // =======================================================================
436 // function : DoMapping
437 // purpose  :
438 // =======================================================================
439 Standard_Boolean Xw_Window::DoMapping() const
440 {
441   return Standard_True; // IsMapped()
442 }
443
444 // =======================================================================
445 // function : Ratio
446 // purpose  :
447 // =======================================================================
448 Standard_Real Xw_Window::Ratio() const
449 {
450   if (myXWindow == 0)
451   {
452     return 1.0;
453   }
454
455   XFlush (myDisplay->GetDisplay());
456   XWindowAttributes aWinAttr;
457   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
458   return Standard_Real(aWinAttr.width) / Standard_Real(aWinAttr.height);
459 }
460
461 // =======================================================================
462 // function : Position
463 // purpose  :
464 // =======================================================================
465 void Xw_Window::Position (Standard_Integer& X1, Standard_Integer& Y1,
466                           Standard_Integer& X2, Standard_Integer& Y2) const
467 {
468   if (myXWindow == 0)
469   {
470     return;
471   }
472
473   XFlush (myDisplay->GetDisplay());
474   XWindowAttributes anAttributes;
475   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &anAttributes);
476   Window aChild;
477   XTranslateCoordinates (myDisplay->GetDisplay(), anAttributes.root, myXWindow,
478                          0, 0, &anAttributes.x, &anAttributes.y, &aChild);
479
480   X1 = -anAttributes.x;
481   X2 = X1 + anAttributes.width;
482   Y1 = -anAttributes.y;
483   Y2 = Y1 + anAttributes.height;
484 }
485
486 // =======================================================================
487 // function : Size
488 // purpose  :
489 // =======================================================================
490 void Xw_Window::Size (Standard_Integer& theWidth,
491                       Standard_Integer& theHeight) const
492 {
493   if (myXWindow == 0)
494   {
495     return;
496   }
497
498   XFlush (myDisplay->GetDisplay());
499   XWindowAttributes aWinAttr;
500   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
501   theWidth  = aWinAttr.width;
502   theHeight = aWinAttr.height;
503 }
504
505 // =======================================================================
506 // function : SetTitle
507 // purpose  :
508 // =======================================================================
509 void Xw_Window::SetTitle (const TCollection_AsciiString& theTitle)
510 {
511   if (myXWindow != 0)
512   {
513     XStoreName (myDisplay->GetDisplay(), myXWindow, theTitle.ToCString());
514   }
515 }
516
517 // =======================================================================
518 // function : InvalidateContent
519 // purpose  :
520 // =======================================================================
521 void Xw_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp)
522 {
523   if (myXWindow == 0)
524   {
525     return;
526   }
527
528   const Handle(Aspect_DisplayConnection)& aDisp = !theDisp.IsNull() ? theDisp : myDisplay;
529   Display* aDispX = aDisp->GetDisplay();
530
531   XEvent anEvent;
532   memset (&anEvent, 0, sizeof(anEvent));
533   anEvent.type = Expose;
534   anEvent.xexpose.window = myXWindow;
535   XSendEvent (aDispX, myXWindow, False, ExposureMask, &anEvent);
536   XFlush (aDispX);
537 }
538
539 // =======================================================================
540 // function : VirtualKeyFromNative
541 // purpose  :
542 // =======================================================================
543 Aspect_VKey Xw_Window::VirtualKeyFromNative (unsigned long theKey)
544 {
545   if (theKey >= XK_0
546    && theKey <= XK_9)
547   {
548     return Aspect_VKey(theKey - XK_0 + Aspect_VKey_0);
549   }
550
551   if (theKey >= XK_A
552    && theKey <= XK_Z)
553   {
554     return Aspect_VKey(theKey - XK_A + Aspect_VKey_A);
555   }
556
557   if (theKey >= XK_a
558    && theKey <= XK_z)
559   {
560     return Aspect_VKey(theKey - XK_a + Aspect_VKey_A);
561   }
562
563   if (theKey >= XK_F1
564    && theKey <= XK_F24)
565   {
566     if (theKey <= XK_F12)
567     {
568       return Aspect_VKey(theKey - XK_F1 + Aspect_VKey_F1);
569     }
570     return Aspect_VKey_UNKNOWN;
571   }
572
573   switch (theKey)
574   {
575     case XK_space:
576       return Aspect_VKey_Space;
577     case XK_apostrophe:
578       return Aspect_VKey_Apostrophe;
579     case XK_comma:
580       return Aspect_VKey_Comma;
581     case XK_minus:
582       return Aspect_VKey_Minus;
583     case XK_period:
584       return Aspect_VKey_Period;
585     case XK_semicolon:
586       return Aspect_VKey_Semicolon;
587     case XK_equal:
588       return Aspect_VKey_Equal;
589     case XK_bracketleft:
590       return Aspect_VKey_BracketLeft;
591     case XK_backslash:
592       return Aspect_VKey_Backslash;
593     case XK_bracketright:
594       return Aspect_VKey_BracketRight;
595     case XK_BackSpace:
596       return Aspect_VKey_Backspace;
597     case XK_Tab:
598       return Aspect_VKey_Tab;
599     //case XK_Linefeed:
600     case XK_Return:
601     case XK_KP_Enter:
602       return Aspect_VKey_Enter;
603     //case XK_Pause:
604     //  return Aspect_VKey_Pause;
605     case XK_Escape:
606       return Aspect_VKey_Escape;
607     case XK_Home:
608       return Aspect_VKey_Home;
609     case XK_Left:
610       return Aspect_VKey_Left;
611     case XK_Up:
612       return Aspect_VKey_Up;
613     case XK_Right:
614       return Aspect_VKey_Right;
615     case XK_Down:
616       return Aspect_VKey_Down;
617     case XK_Prior:
618       return Aspect_VKey_PageUp;
619     case XK_Next:
620       return Aspect_VKey_PageDown;
621     case XK_End:
622       return Aspect_VKey_End;
623     //case XK_Insert:
624     //  return Aspect_VKey_Insert;
625     case XK_Menu:
626       return Aspect_VKey_Menu;
627     case XK_Num_Lock:
628       return Aspect_VKey_Numlock;
629     //case XK_KP_Delete:
630     //  return Aspect_VKey_NumDelete;
631     case XK_KP_Multiply:
632       return Aspect_VKey_NumpadMultiply;
633     case XK_KP_Add:
634       return Aspect_VKey_NumpadAdd;
635     //case XK_KP_Separator:
636     //  return Aspect_VKey_Separator;
637     case XK_KP_Subtract:
638       return Aspect_VKey_NumpadSubtract;
639     //case XK_KP_Decimal:
640     //  return Aspect_VKey_Decimal;
641     case XK_KP_Divide:
642       return Aspect_VKey_NumpadDivide;
643     case XK_Shift_L:
644     case XK_Shift_R:
645       return Aspect_VKey_Shift;
646     case XK_Control_L:
647     case XK_Control_R:
648       return Aspect_VKey_Control;
649     //case XK_Caps_Lock:
650     //  return Aspect_VKey_CapsLock;
651     case XK_Alt_L:
652     case XK_Alt_R:
653       return Aspect_VKey_Alt;
654     //case XK_Super_L:
655     //case XK_Super_R:
656     //  return Aspect_VKey_Super;
657     case XK_Delete:
658       return Aspect_VKey_Delete;
659
660     case 0x1008FF11: // XF86AudioLowerVolume
661       return Aspect_VKey_VolumeDown;
662     case 0x1008FF12: // XF86AudioMute
663       return Aspect_VKey_VolumeMute;
664     case 0x1008FF13: // XF86AudioRaiseVolume
665       return Aspect_VKey_VolumeUp;
666
667     case 0x1008FF14: // XF86AudioPlay
668       return Aspect_VKey_MediaPlayPause;
669     case 0x1008FF15: // XF86AudioStop
670       return Aspect_VKey_MediaStop;
671     case 0x1008FF16: // XF86AudioPrev
672       return Aspect_VKey_MediaPreviousTrack;
673     case 0x1008FF17: // XF86AudioNext
674       return Aspect_VKey_MediaNextTrack;
675
676     case 0x1008FF18: // XF86HomePage
677       return Aspect_VKey_BrowserHome;
678     case 0x1008FF26: // XF86Back
679       return Aspect_VKey_BrowserBack;
680     case 0x1008FF27: // XF86Forward
681       return Aspect_VKey_BrowserForward;
682     case 0x1008FF28: // XF86Stop
683       return Aspect_VKey_BrowserStop;
684     case 0x1008FF29: // XF86Refresh
685       return Aspect_VKey_BrowserRefresh;
686   }
687   return Aspect_VKey_UNKNOWN;
688 }
689
690 #endif //  Win32 or Mac OS X