]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SWTCanvas.java
Merged trunk@29628 to branches/simantics-1.13 on 2014-06-17 for 1.13.3 release.
[simantics/3d.git] / org.simantics.g3d.jme / src / org / simantics / g3d / jme / system / SWTCanvas.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g3d.jme.system;\r
13 \r
14 \r
15 \r
16 import java.util.ArrayList;\r
17 import java.util.List;\r
18 import java.util.logging.Level;\r
19 import java.util.logging.Logger;\r
20 \r
21 import org.eclipse.swt.SWT;\r
22 import org.eclipse.swt.events.KeyEvent;\r
23 import org.eclipse.swt.events.KeyListener;\r
24 import org.eclipse.swt.events.MouseEvent;\r
25 import org.eclipse.swt.events.MouseListener;\r
26 import org.eclipse.swt.events.MouseMoveListener;\r
27 import org.eclipse.swt.events.MouseTrackListener;\r
28 import org.eclipse.swt.events.MouseWheelListener;\r
29 import org.eclipse.swt.events.PaintEvent;\r
30 import org.eclipse.swt.events.PaintListener;\r
31 import org.eclipse.swt.graphics.Point;\r
32 import org.eclipse.swt.layout.FillLayout;\r
33 import org.eclipse.swt.opengl.GLCanvas;\r
34 import org.eclipse.swt.opengl.GLData;\r
35 import org.eclipse.swt.widgets.Composite;\r
36 import org.lwjgl.LWJGLException;\r
37 import org.lwjgl.Sys;\r
38 import org.lwjgl.input.Keyboard;\r
39 import org.lwjgl.input.Mouse;\r
40 import org.lwjgl.opengl.GLContext;\r
41 import org.lwjgl.opengl.Pbuffer;\r
42 import org.lwjgl.opengl.PixelFormat;\r
43 \r
44 import com.jme3.cursors.plugins.JmeCursor;\r
45 import com.jme3.input.JoyInput;\r
46 import com.jme3.input.KeyInput;\r
47 import com.jme3.input.MouseInput;\r
48 import com.jme3.input.RawInputListener;\r
49 import com.jme3.input.event.InputEvent;\r
50 import com.jme3.input.event.KeyInputEvent;\r
51 import com.jme3.input.event.MouseButtonEvent;\r
52 import com.jme3.input.event.MouseMotionEvent;\r
53 import com.jme3.system.AppSettings;\r
54 import com.jme3.system.JmeSystem;\r
55 import com.jme3.system.Platform;\r
56 import com.jme3.system.lwjgl.LwjglAbstractDisplay;\r
57 import com.jme3.system.lwjgl.LwjglDisplay;\r
58 import com.jme3.system.lwjgl.LwjglTimer;\r
59 \r
60 /**\r
61  * SWT OpenGL canvas for jME\r
62  * \r
63  * Note: this class is experimental, and contains questionable code.\r
64  * \r
65  * \r
66  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
67  *\r
68  */\r
69 public class SWTCanvas extends LwjglAbstractDisplay {\r
70 \r
71         protected static final boolean USE_SHARED_CONTEXT = false;\r
72 \r
73         \r
74         private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName());\r
75         \r
76         GLCanvas canvas;\r
77         \r
78         private int width;\r
79     private int height;\r
80     \r
81     private boolean runningFirstTime = true;\r
82     private boolean mouseWasGrabbed = false;\r
83     \r
84     private boolean mouseWasCreated = false;\r
85     private boolean keyboardWasCreated = false;\r
86 \r
87     private Pbuffer pbuffer;\r
88     private PixelFormat pbufferFormat;\r
89     private PixelFormat canvasFormat;\r
90     \r
91     private boolean disposed = false;\r
92     \r
93         public SWTCanvas(Composite parent) {\r
94                 parent.setLayout(new FillLayout());\r
95                 \r
96                 GLData data = new GLData();\r
97                 data.doubleBuffer = true;\r
98                 data.blueSize = 8;\r
99                 data.redSize = 8;\r
100                 data.greenSize = 8;\r
101                 data.depthSize = 32;\r
102                 data.alphaSize = 8;\r
103                 data.stencilSize = 8;\r
104                 data.stereo = false;\r
105                 data.accumAlphaSize = 0;\r
106                 data.accumBlueSize = 0;\r
107                 data.accumGreenSize = 0;\r
108                 data.accumRedSize = 0;\r
109                 canvas = new GLCanvas(parent, SWT.EMBEDDED|SWT.NO_REDRAW_RESIZE, data);\r
110                 //canvas = new GLCanvas(parent, SWT.NONE, data);\r
111                 \r
112                 \r
113         }\r
114         \r
115         public void dispose() {\r
116                 if (disposed)\r
117                         return;\r
118                 \r
119                 setCurrent();\r
120                 deinitInThread();\r
121 //              pauseCanvas();\r
122                 canvas.dispose();\r
123                 disposed = true;\r
124         }\r
125         \r
126         public boolean isDisposed() {\r
127                 return disposed;\r
128         }\r
129         \r
130         @Override\r
131         public Type getType() {\r
132                 return Type.Canvas; // TODO : is Canvas Correct?\r
133         }\r
134         \r
135         @Override\r
136         public void setTitle(String title) {\r
137                 // do nothing\r
138         }\r
139         \r
140         @Override\r
141         public void restart() {\r
142                  frameRate = settings.getFrameRate();\r
143         }\r
144         \r
145 \r
146         private boolean c = false;\r
147         \r
148         public void create(boolean waitFor){\r
149                 if (c)\r
150                         return;\r
151                 c = true;\r
152                 \r
153                 setCurrent();\r
154                 initInThread();\r
155                 renderable.set(true);\r
156                 //restoreCanvas();\r
157                 \r
158 //              canvas.addPaintListener(new PaintListener() {\r
159 //                      \r
160 //                      @Override\r
161 //                      public void paintControl(PaintEvent arg0) {\r
162 //                              repaint();\r
163 //                      }\r
164 //              });\r
165                 \r
166                 org.eclipse.swt.widgets.Display.getCurrent().asyncExec(new Runnable() {\r
167                         \r
168                         @Override\r
169                         public void run() {\r
170                                 if (canvas.isDisposed())\r
171                                         return;\r
172                                 repaint();\r
173                                 org.eclipse.swt.widgets.Display.getCurrent().asyncExec(this);\r
174                                 \r
175                         }\r
176                 });\r
177 \r
178         }\r
179         \r
180         @Override\r
181         protected void runLoop() {\r
182 \r
183                 if (renderable.get()){\r
184                         Point size = canvas.getSize();\r
185                         //System.out.println("Render " + size);\r
186             int newWidth = Math.max(size.x, 1);\r
187             int newHeight = Math.max(size.y, 1);\r
188             if (width != newWidth || height != newHeight){\r
189                 System.out.println("Render resize " + size);\r
190                 width = newWidth;\r
191                 height = newHeight;\r
192                 if (listener != null){\r
193                     listener.reshape(width, height);\r
194                 }\r
195             }\r
196         }\r
197                  if (!created.get())\r
198                     throw new IllegalStateException();\r
199                  listener.update();\r
200                  if (renderable.get()){\r
201                          assert checkGLError();\r
202                          \r
203                          // calls swap buffers, etc.\r
204                     try {\r
205                         canvas.swapBuffers();\r
206 //                      Display.processMessages();\r
207 //                      if (autoFlush){\r
208 //                          Display.update(false);\r
209 //                      }else{\r
210 //                          Display.processMessages();\r
211 //                          Thread.sleep(50);\r
212 //                          // add a small wait\r
213 //                          // to reduce CPU usage\r
214 //                      }\r
215                     } catch (Throwable ex){\r
216                         listener.handleError("Error while swapping buffers", ex);\r
217                     }\r
218                  }\r
219 //               if (frameRate > 0)\r
220 //                  Display.sync(frameRate);\r
221 \r
222 //              if (renderable.get()){\r
223 //                  if (autoFlush){\r
224 //                      // check input after we synchronize with framerate.\r
225 //                      // this reduces input lag.\r
226 //                      Display.processMessages();\r
227 //                  }\r
228 //              }\r
229         }\r
230         \r
231         public void repaint() {\r
232                 setCurrent();\r
233 //              if (renderable.get()){\r
234 //            if (Display.isCloseRequested())\r
235 //                listener.requestClose(false);\r
236                         \r
237 //            if (wasActive != Display.isActive()) {\r
238 //                if (!wasActive) {\r
239 //                    listener.gainFocus();\r
240 //                    timer.reset();\r
241 //                    wasActive = true;\r
242 //                } else {\r
243 //                    listener.loseFocus();\r
244 //                    wasActive = false;\r
245 //                }\r
246 //            }\r
247 //        }\r
248 \r
249         runLoop();\r
250         }\r
251         \r
252         @Override\r
253         public void run() {\r
254                 // do nothing\r
255                 //super.run();\r
256         }\r
257         \r
258         @Override\r
259         protected void destroyContext() {\r
260                  try {\r
261                     // invalidate the state so renderer can resume operation\r
262                     if (!USE_SHARED_CONTEXT){\r
263                         renderer.cleanup();\r
264                     }\r
265                     \r
266                     //if (Display.isCreated()){\r
267                     if (!canvas.isDisposed()) {\r
268                         /* FIXES:\r
269                          * org.lwjgl.LWJGLException: X Error\r
270                          * BadWindow (invalid Window parameter) request_code: 2 minor_code: 0\r
271                          * \r
272                          * Destroying keyboard early prevents the error above, triggered\r
273                          * by destroying keyboard in by Display.destroy() or Display.setParent(null).\r
274                          * Therefore Keyboard.destroy() should precede any of these calls.\r
275                          */\r
276                         if (Keyboard.isCreated()){\r
277                             // Should only happen if called in \r
278                             // LwjglAbstractDisplay.deinitInThread().\r
279                             Keyboard.destroy();\r
280                         }\r
281 \r
282                         //try {\r
283                             // NOTE: On Windows XP, not calling setParent(null)\r
284                             // freezes the application.\r
285                             // On Mac it freezes the application.\r
286                             // On Linux it fixes a crash with X Window System.\r
287                             if (JmeSystem.getPlatform() == Platform.Windows32\r
288                              || JmeSystem.getPlatform() == Platform.Windows64){\r
289                                 //Display.setParent(null);\r
290                             }\r
291                         //} catch (LWJGLException ex) {\r
292                         //    logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex);\r
293                         //}\r
294 \r
295 //                      Display.destroy();\r
296                     }\r
297                     \r
298                     // The canvas is no longer visible,\r
299                     // but the context thread is still running.\r
300                     if (!needClose.get()){\r
301                         // MUST make sure there's still a context current here ..\r
302                         // Display is dead, make pbuffer available to the system\r
303                         makePbufferAvailable();\r
304                         \r
305                         renderer.invalidateState();\r
306                     }else{\r
307                         // The context thread is no longer running.\r
308                         // Destroy pbuffer.\r
309                         destroyPbuffer();\r
310                     }\r
311                 } catch (LWJGLException ex) {\r
312                     listener.handleError("Failed make pbuffer available", ex);\r
313                 }\r
314                 \r
315         }\r
316         \r
317 \r
318         \r
319         public void setFocus() {\r
320                 canvas.setFocus();              \r
321         }\r
322         \r
323         public void setCurrent(GLCanvas canvas) {\r
324                 // delegate to the GLContext\r
325                 canvas.setCurrent();\r
326                 try {\r
327                         GLContext.useContext(canvas);\r
328                 } catch (LWJGLException e) {\r
329                         e.printStackTrace();\r
330                 }\r
331         }\r
332     \r
333     public void setCurrent() {\r
334         setCurrent(canvas);\r
335     }\r
336     \r
337     \r
338     \r
339     private void pauseCanvas(){\r
340         if (Mouse.isCreated()){\r
341             if (Mouse.isGrabbed()){\r
342                 Mouse.setGrabbed(false);\r
343                 mouseWasGrabbed = true;\r
344             }\r
345             mouseWasCreated = true;\r
346             Mouse.destroy();\r
347         }\r
348         if (Keyboard.isCreated()){\r
349             keyboardWasCreated = true;\r
350             Keyboard.destroy();\r
351         }\r
352 \r
353         renderable.set(false);\r
354         destroyContext();\r
355     }\r
356 \r
357     /**\r
358      * Called to restore the canvas.\r
359      */\r
360     private void restoreCanvas(){\r
361         setCurrent();\r
362         logger.log(Level.INFO, "OGL: Waiting for canvas to become displayable..");\r
363         while (!canvas.getVisible()){\r
364             try {\r
365                 Thread.sleep(10);\r
366             } catch (InterruptedException ex) {\r
367                 logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);\r
368             }\r
369         }\r
370         \r
371         logger.log(Level.INFO, "OGL: Creating display context ..");\r
372 \r
373         // Set renderable to true, since canvas is now displayable.\r
374         renderable.set(true);\r
375         createContext(settings);\r
376 \r
377         logger.log(Level.INFO, "OGL: Display is active!");\r
378 \r
379         try {\r
380             if (mouseWasCreated){\r
381                 Mouse.create();\r
382                 if (mouseWasGrabbed){\r
383                     Mouse.setGrabbed(true);\r
384                     mouseWasGrabbed = false;\r
385                 }\r
386             }\r
387             if (keyboardWasCreated){\r
388                 Keyboard.create();\r
389                 keyboardWasCreated = false;\r
390             }\r
391         } catch (LWJGLException ex){\r
392             logger.log(Level.SEVERE, "Encountered exception when restoring input", ex);\r
393         }\r
394 \r
395         \r
396     }\r
397     /**\r
398      * It seems it is best to use one pixel format for all shared contexts.\r
399      * @see <a href="http://developer.apple.com/library/mac/#qa/qa1248/_index.html">http://developer.apple.com/library/mac/#qa/qa1248/_index.html</a>\r
400      */\r
401     protected PixelFormat acquirePixelFormat(boolean forPbuffer){\r
402         if (forPbuffer){\r
403             // Use 0 samples for pbuffer format, prevents\r
404             // crashes on bad drivers\r
405             if (pbufferFormat == null){\r
406                 pbufferFormat = new PixelFormat(settings.getBitsPerPixel(),\r
407                                                 0,\r
408                                                 settings.getDepthBits(),\r
409                                                 settings.getStencilBits(),\r
410                                                 0);\r
411             }\r
412             return pbufferFormat;\r
413         }else{\r
414             if (canvasFormat == null){\r
415                 int samples = getNumSamplesToUse();\r
416                 canvasFormat = new PixelFormat(settings.getBitsPerPixel(),\r
417                                                0,\r
418                                                settings.getDepthBits(),\r
419                                                settings.getStencilBits(),\r
420                                                samples);\r
421             }\r
422             return canvasFormat;\r
423         }\r
424     }\r
425     \r
426     /**\r
427      * Makes sure the pbuffer is available and ready for use\r
428      */\r
429     protected void makePbufferAvailable() throws LWJGLException{\r
430         if (pbuffer != null && pbuffer.isBufferLost()){\r
431             logger.log(Level.WARNING, "PBuffer was lost!");\r
432             pbuffer.destroy();\r
433             pbuffer = null;\r
434         }\r
435         \r
436         if (pbuffer == null) {\r
437             pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null);\r
438             pbuffer.makeCurrent();\r
439             logger.log(Level.INFO, "OGL: Pbuffer has been created");\r
440             \r
441             // Any created objects are no longer valid\r
442             if (!runningFirstTime){\r
443                 renderer.resetGLObjects();\r
444             }\r
445         }\r
446         \r
447         pbuffer.makeCurrent();\r
448         if (!pbuffer.isCurrent()){\r
449             throw new LWJGLException("Pbuffer cannot be made current");\r
450         }\r
451     }\r
452     \r
453     protected void destroyPbuffer(){\r
454         if (pbuffer != null){\r
455             if (!pbuffer.isBufferLost()){\r
456                 pbuffer.destroy();\r
457             }\r
458             pbuffer = null;\r
459         }\r
460     }\r
461     \r
462     @Override\r
463     protected void createContext(AppSettings settings) {\r
464         setCurrent();\r
465         \r
466         // In case canvas is not visible, we still take framerate\r
467         // from settings to prevent "100% CPU usage"\r
468         frameRate = settings.getFrameRate();\r
469         \r
470         try {\r
471             if (renderable.get()){\r
472                 if (!runningFirstTime){\r
473                     // because the display is a different opengl context\r
474                     // must reset the context state.\r
475                     if (!USE_SHARED_CONTEXT){\r
476                         renderer.cleanup();\r
477                     }\r
478                 }\r
479                 \r
480                 // if the pbuffer is currently active, \r
481                 // make sure to deactivate it\r
482                 destroyPbuffer();\r
483                 \r
484                 if (Keyboard.isCreated()){\r
485                     Keyboard.destroy();\r
486                 }\r
487                 \r
488                 try {\r
489                     Thread.sleep(1000);\r
490                 } catch (InterruptedException ex) {\r
491                 }\r
492                 \r
493 //                Display.setVSyncEnabled(settings.isVSync());\r
494                 //Display.setParent(canvas);\r
495                 \r
496 //                if (USE_SHARED_CONTEXT){\r
497 //                    Display.create(acquirePixelFormat(false), pbuffer);\r
498 //                }else{\r
499 //                    Display.create(acquirePixelFormat(false));\r
500 //                }\r
501                 \r
502                 renderer.invalidateState();\r
503             }else{\r
504                 // First create the pbuffer, if it is needed.\r
505                 makePbufferAvailable();\r
506             }\r
507 \r
508             // At this point, the OpenGL context is active.\r
509             if (runningFirstTime){\r
510                 // THIS is the part that creates the renderer.\r
511                 // It must always be called, now that we have the pbuffer workaround.\r
512                 initContextFirstTime();\r
513                 runningFirstTime = false;\r
514             }\r
515         } catch (LWJGLException ex) {\r
516             listener.handleError("Failed to initialize OpenGL context", ex);\r
517             // TODO: Fix deadlock that happens after the error (throw runtime exception?)\r
518         }\r
519     }\r
520 \r
521     \r
522     public JoyInput getJoyInput() {\r
523        return null;\r
524     }\r
525 \r
526     \r
527     SWTMouseInput mouseInput;\r
528     \r
529     public MouseInput getMouseInput() {\r
530         if (mouseInput == null){\r
531             mouseInput = new SWTMouseInput(this);\r
532         }\r
533         return mouseInput;\r
534     }\r
535 \r
536     \r
537     SWTKeyInput keyInput;\r
538     \r
539     public KeyInput getKeyInput() {\r
540         if (keyInput == null){\r
541             keyInput = new SWTKeyInput(this);\r
542         }\r
543         return keyInput;\r
544     }\r
545     \r
546 \r
547     \r
548     public class SWTMouseInput implements MouseInput, MouseListener, MouseMoveListener, MouseWheelListener, MouseTrackListener {\r
549         SWTCanvas canvas;\r
550         boolean init = false;\r
551         RawInputListener listener;\r
552         \r
553         public SWTMouseInput(SWTCanvas canvas) {\r
554                 this.canvas = canvas;\r
555                 \r
556         }\r
557         \r
558         @Override\r
559         public void destroy() {\r
560                 this.canvas.canvas.removeMouseListener(this);\r
561                 this.canvas.canvas.removeMouseMoveListener(this);\r
562                 this.canvas.canvas.removeMouseWheelListener(this);\r
563                 this.canvas.canvas.removeMouseTrackListener(this);\r
564         }\r
565         \r
566         @Override\r
567         public void initialize() {\r
568                 this.canvas.canvas.addMouseListener(this);\r
569                 this.canvas.canvas.addMouseMoveListener(this);\r
570                 this.canvas.canvas.addMouseWheelListener(this);\r
571                 this.canvas.canvas.addMouseTrackListener(this);\r
572                 init = true;\r
573         }\r
574         \r
575         @Override\r
576         public int getButtonCount() {\r
577                 return 3;\r
578         }\r
579         \r
580         @Override\r
581         public boolean isInitialized() {\r
582                 return init;\r
583         }\r
584         \r
585         @Override\r
586         public void setInputListener(RawInputListener listener) {\r
587                 this.listener = listener;\r
588 \r
589         }\r
590         \r
591         public long getInputTimeNanos() {\r
592             return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS;\r
593         }\r
594         \r
595         @Override\r
596         public void setCursorVisible(boolean visible) {\r
597                 \r
598         }\r
599         \r
600         @Override\r
601         public void setNativeCursor(JmeCursor cursor) {\r
602                 \r
603         }\r
604         \r
605         @Override\r
606         public void update() {\r
607                 if (listener == null || events.size() == 0)\r
608                         return;\r
609                 listener.beginInput();\r
610                 for (InputEvent e : events) {\r
611                         if (e instanceof MouseButtonEvent)\r
612                                 listener.onMouseButtonEvent((MouseButtonEvent)e);\r
613                         else\r
614                                 listener.onMouseMotionEvent((MouseMotionEvent)e);\r
615                 }\r
616                 events.clear();\r
617                 listener.endInput();\r
618         }\r
619         \r
620         private List<InputEvent> events = new ArrayList<InputEvent>();\r
621         \r
622         @Override\r
623         public void mouseDoubleClick(MouseEvent e) {\r
624                 //events.add(new MouseButtonEvent(e.button,true, e.x, e.y));\r
625                 \r
626         }\r
627         \r
628         @Override\r
629         public void mouseDown(MouseEvent e) {\r
630                 events.add(new MouseButtonEvent(e.button,true, e.x, e.y));\r
631                 \r
632         }\r
633         \r
634         @Override\r
635         public void mouseUp(MouseEvent e) {\r
636                 events.add(new MouseButtonEvent(e.button,false, e.x, e.y));\r
637                 \r
638         }\r
639         \r
640         int px = 0;\r
641         int py = 0;\r
642         \r
643         @Override\r
644         public void mouseMove(MouseEvent e) {\r
645                 events.add(new MouseMotionEvent(e.x, e.y, e.x - px, e.y - py, 0, 0));\r
646                 px = e.x;\r
647                 py = e.y;\r
648                 \r
649         }\r
650         \r
651         @Override\r
652         public void mouseScrolled(MouseEvent e) {\r
653                 events.add(new MouseMotionEvent(e.x, e.y, 0, 0, e.button, e.count));\r
654         }\r
655         \r
656         @Override\r
657         public void mouseEnter(MouseEvent e) {\r
658                 px = e.x;\r
659                 py = e.y;\r
660         }\r
661         \r
662         @Override\r
663         public void mouseExit(MouseEvent e) {\r
664                 \r
665         }\r
666         \r
667         @Override\r
668         public void mouseHover(MouseEvent e) {\r
669                 \r
670         }\r
671     }\r
672     \r
673     public class SWTKeyInput implements KeyInput, KeyListener {\r
674         SWTCanvas canvas;\r
675         boolean init = false;\r
676         RawInputListener listener;\r
677         \r
678         public SWTKeyInput(SWTCanvas canvas) {\r
679                 this.canvas = canvas;\r
680         }\r
681         \r
682         @Override\r
683         public void destroy() {\r
684                 this.canvas.canvas.removeKeyListener(this);\r
685         }\r
686         \r
687         @Override\r
688         public void initialize() {\r
689                 this.canvas.canvas.addKeyListener(this);\r
690                 init = true;\r
691         }\r
692         \r
693         @Override\r
694         public boolean isInitialized() {\r
695                 return init;\r
696         }\r
697         \r
698         @Override\r
699         public void setInputListener(RawInputListener listener) {\r
700                 this.listener = listener;\r
701         }\r
702         \r
703         public long getInputTimeNanos() {\r
704             return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS;\r
705         }\r
706         \r
707         private List<KeyInputEvent> events = new ArrayList<KeyInputEvent>();\r
708         \r
709         KeyInputEvent prevEvent = new KeyInputEvent(0, (char)0, false, false);\r
710         \r
711         @Override\r
712         public void update() {\r
713                 if (listener == null || events.size() == 0)\r
714                         return;\r
715                 listener.beginInput();\r
716                 \r
717                 for (KeyInputEvent e : events) {\r
718                         //System.out.println("Key " + e.getKeyCode() + " " + e.getKeyChar() + " " + e.isPressed() + " " + e.isRepeating());\r
719                         \r
720                         // SWT reports wrong key code in released event for a key, if multiple keys are down at the same time\r
721                         // example:\r
722                         // press 'a'   -> event press a\r
723                         // press 'b'   -> event press b\r
724                         // release 'a' -> event release b\r
725                         // keep 'b' pressed -> event press b (with slight pause before events starts coming by)\r
726                         // release 'b' -> event release b\r
727                         \r
728                         // press 'a'   -> event press a\r
729                         // press 'b'   -> event press b\r
730                         // release 'b' -> event release b\r
731                         // keep 'a' pressed -> nothing happens.\r
732                         // release 'a' -> nothing happens\r
733                         \r
734                         if (e.isPressed()) {\r
735                                 if (e.getKeyCode() != prevEvent.getKeyCode() && prevEvent.isPressed()) {\r
736                                         listener.onKeyEvent(new KeyInputEvent(prevEvent.getKeyCode(), prevEvent.getKeyChar(), false, false));\r
737                                 }\r
738                         }\r
739                         \r
740                         listener.onKeyEvent(e);\r
741                         prevEvent = e;\r
742                 }\r
743                 events.clear();\r
744                 listener.endInput();\r
745                 \r
746         }\r
747         \r
748         @Override\r
749         public void keyPressed(KeyEvent e) {\r
750                 events.add(new KeyInputEvent(getLWJGLKeyCode(e.keyCode), e.character, true, false));\r
751                 \r
752         }\r
753         \r
754         @Override\r
755         public void keyReleased(KeyEvent e) {\r
756                 \r
757                 events.add(new KeyInputEvent(getLWJGLKeyCode(e.keyCode), e.character, false, false));\r
758         }\r
759         \r
760         private int getLWJGLKeyCode(int swtKeyCode) {\r
761                 // TODO : LWJGL uses mapping/layout of US keyboard, these have to be checked   \r
762                 if(swtKeyCode > 1024) {\r
763                     int keyCode = 0;\r
764                     switch (swtKeyCode) {\r
765                     case SWT.CTRL:\r
766                         keyCode = Keyboard.KEY_LCONTROL;\r
767                         break;\r
768                     case SWT.ALT:\r
769                         keyCode = Keyboard.KEY_LMETA;\r
770                         break;\r
771                     \r
772                     case SWT.SHIFT:\r
773                         keyCode = Keyboard.KEY_LSHIFT;\r
774                         break;\r
775                     case SWT.ARROW_LEFT:\r
776                         keyCode = Keyboard.KEY_LEFT;\r
777                         break;\r
778                     case SWT.ARROW_RIGHT:\r
779                         keyCode = Keyboard.KEY_RIGHT;\r
780                         break;\r
781                     case SWT.ARROW_UP:\r
782                         keyCode = Keyboard.KEY_UP;\r
783                         break;\r
784                     case SWT.ARROW_DOWN:\r
785                         keyCode = Keyboard.KEY_DOWN;\r
786                         break;\r
787                     case SWT.KEYPAD_0:\r
788                         keyCode = Keyboard.KEY_NUMPAD0;\r
789                         break;\r
790                     case SWT.KEYPAD_1:\r
791                         keyCode = Keyboard.KEY_NUMPAD1;\r
792                         break;\r
793                     case SWT.KEYPAD_2:\r
794                         keyCode = Keyboard.KEY_NUMPAD2;\r
795                         break;\r
796                     case SWT.KEYPAD_3:\r
797                         keyCode = Keyboard.KEY_NUMPAD3;\r
798                         break;\r
799                     case SWT.KEYPAD_4:\r
800                         keyCode = Keyboard.KEY_NUMPAD4;\r
801                         break;\r
802                     case SWT.KEYPAD_5:\r
803                         keyCode = Keyboard.KEY_NUMPAD5;\r
804                         break;\r
805                     case SWT.KEYPAD_6:\r
806                         keyCode = Keyboard.KEY_NUMPAD6;\r
807                         break;\r
808                     case SWT.KEYPAD_7:\r
809                         keyCode = Keyboard.KEY_NUMPAD7;\r
810                         break;\r
811                     case SWT.KEYPAD_8:\r
812                         keyCode = Keyboard.KEY_NUMPAD8;\r
813                         break;\r
814                     case SWT.KEYPAD_9:\r
815                         keyCode = Keyboard.KEY_NUMPAD9;\r
816                         break;\r
817                     case SWT.KEYPAD_CR:\r
818                         keyCode = Keyboard.KEY_NUMPADENTER;\r
819                         break;\r
820                     case SWT.NUM_LOCK:\r
821                         keyCode = Keyboard.KEY_NUMLOCK;\r
822                         break;\r
823                     case SWT.SCROLL_LOCK:\r
824                         keyCode = Keyboard.KEY_SCROLL;\r
825                         break;\r
826                     case SWT.CAPS_LOCK:\r
827                         keyCode = Keyboard.KEY_CAPITAL;\r
828                         break;\r
829                     case SWT.INSERT:\r
830                         keyCode = Keyboard.KEY_INSERT;\r
831                         break;\r
832                     case SWT.HOME:\r
833                         keyCode = Keyboard.KEY_HOME;\r
834                         break;\r
835                     case SWT.END:\r
836                         keyCode = Keyboard.KEY_END;\r
837                         break;\r
838                     case SWT.PAGE_UP:\r
839                         keyCode = Keyboard.KEY_NEXT;\r
840                         break;\r
841                     case SWT.PAGE_DOWN:\r
842                         keyCode = Keyboard.KEY_PRIOR;\r
843                         break;\r
844                     case SWT.PAUSE:\r
845                         keyCode = Keyboard.KEY_PAUSE;   \r
846                         break;\r
847                     case SWT.BREAK:\r
848                         keyCode = Keyboard.KEY_PAUSE;   \r
849                         break;\r
850                     case SWT.PRINT_SCREEN:\r
851                         keyCode = Keyboard.KEY_SYSRQ;   \r
852                         break;   \r
853                     case SWT.HELP:\r
854                         keyCode = 0;\r
855                         break;\r
856                     case SWT.KEYPAD_MULTIPLY:\r
857                         keyCode = Keyboard.KEY_MULTIPLY;\r
858                         break;\r
859                     case SWT.KEYPAD_DIVIDE:\r
860                         keyCode = Keyboard.KEY_DIVIDE;\r
861                         break;\r
862                     case SWT.KEYPAD_DECIMAL:\r
863                         keyCode = Keyboard.KEY_DECIMAL;\r
864                         break;\r
865                     case SWT.F1:\r
866                         keyCode = Keyboard.KEY_F1;\r
867                         break;\r
868                     case SWT.F2:\r
869                         keyCode = Keyboard.KEY_F2;\r
870                         break;\r
871                     case SWT.F3:\r
872                         keyCode = Keyboard.KEY_F3;\r
873                         break;\r
874                     case SWT.F4:\r
875                         keyCode = Keyboard.KEY_F4;\r
876                         break;\r
877                     case SWT.F5:\r
878                         keyCode = Keyboard.KEY_F5;\r
879                         break;\r
880                     case SWT.F6:\r
881                         keyCode = Keyboard.KEY_F6;\r
882                         break;\r
883                     case SWT.F7:\r
884                         keyCode = Keyboard.KEY_F7;\r
885                         break;\r
886                     case SWT.F8:\r
887                         keyCode = Keyboard.KEY_F8;\r
888                         break;\r
889                     case SWT.F9:\r
890                         keyCode = Keyboard.KEY_F9;\r
891                         break;\r
892                     case SWT.F10:\r
893                         keyCode = Keyboard.KEY_F10;\r
894                         break;\r
895                     case SWT.F11:\r
896                         keyCode = Keyboard.KEY_F11;\r
897                         break;\r
898                     case SWT.F12:\r
899                         keyCode = Keyboard.KEY_F12;\r
900                         break;\r
901                     default :\r
902                         keyCode = Keyboard.KEY_NONE;\r
903                         break;\r
904                     }\r
905                     \r
906                     return keyCode;\r
907                 } else if (swtKeyCode == 8) {\r
908                         return Keyboard.KEY_BACK;\r
909                 } else if (swtKeyCode == SWT.ESC) {\r
910                         return Keyboard.KEY_ESCAPE;\r
911                 } else if (swtKeyCode == SWT.SPACE) {\r
912                         return Keyboard.KEY_SPACE;\r
913                 } else if (swtKeyCode >= 49 && swtKeyCode < 58) { // 1 - 9\r
914                         return swtKeyCode - 47; \r
915                 } else if (swtKeyCode == 48) {\r
916                         return Keyboard.KEY_0;\r
917                 } else if (swtKeyCode == SWT.TAB) {\r
918                         return Keyboard.KEY_TAB;\r
919                 } else if (swtKeyCode == 46) {\r
920                         return Keyboard.KEY_PERIOD;\r
921                 } else if (swtKeyCode == 44) {\r
922                         return Keyboard.KEY_COMMA;\r
923                 } else if (swtKeyCode == 39) { // '/* on SWE/FI keyboard\r
924                         return Keyboard.KEY_SLASH;\r
925                 } else if (swtKeyCode == 45) {\r
926                         return Keyboard.KEY_MINUS;\r
927                 } else if (swtKeyCode == 43) {\r
928                         return Keyboard.KEY_EQUALS; // +/? on SWE/FI keyboard\r
929                 } else if (swtKeyCode == SWT.DEL) {\r
930                         return Keyboard.KEY_DELETE;\r
931                 } else if (swtKeyCode == SWT.CR) {\r
932                         return Keyboard.KEY_RETURN;\r
933                 } else if (swtKeyCode == 167) { // Â§ on SWE/FI keyboard\r
934                         return Keyboard.KEY_BACKSLASH;\r
935                 }\r
936                 else if (swtKeyCode >= 97 )\r
937                         swtKeyCode -= 32;\r
938                 if (swtKeyCode >= 65 && swtKeyCode <= 90) {\r
939                         switch (swtKeyCode) {\r
940                                 case 65:\r
941                                         return Keyboard.KEY_A;\r
942                                 case 66:\r
943                                         return Keyboard.KEY_B;\r
944                                 case 67:\r
945                                         return Keyboard.KEY_C;\r
946                                 case 68:\r
947                                         return Keyboard.KEY_D;\r
948                                 case 69:\r
949                                         return Keyboard.KEY_E;\r
950                                 case 70:\r
951                                         return Keyboard.KEY_F;\r
952                                 case 71:\r
953                                         return Keyboard.KEY_G;\r
954                                 case 72:\r
955                                         return Keyboard.KEY_H;\r
956                                 case 73:\r
957                                         return Keyboard.KEY_I;\r
958                                 case 74:\r
959                                         return Keyboard.KEY_J;\r
960                                 case 75:\r
961                                         return Keyboard.KEY_K;\r
962                                 case 76:\r
963                                         return Keyboard.KEY_L;\r
964                                 case 77:\r
965                                         return Keyboard.KEY_M;\r
966                                 case 78:\r
967                                         return Keyboard.KEY_N;\r
968                                 case 79:\r
969                                         return Keyboard.KEY_O;\r
970                                 case 80:\r
971                                         return Keyboard.KEY_P;\r
972                                 case 81:\r
973                                         return Keyboard.KEY_Q;\r
974                                 case 82:\r
975                                         return Keyboard.KEY_R;\r
976                                 case 83:\r
977                                         return Keyboard.KEY_S;\r
978                                 case 84:\r
979                                         return Keyboard.KEY_T;\r
980                                 case 85:\r
981                                         return Keyboard.KEY_U;\r
982                                 case 86:\r
983                                         return Keyboard.KEY_V;\r
984                                 case 87:\r
985                                         return Keyboard.KEY_W;\r
986                                 case 88:\r
987                                         return Keyboard.KEY_X;\r
988                                 case 89:\r
989                                         return Keyboard.KEY_Y;\r
990                                 case 90:\r
991                                         return Keyboard.KEY_Z;\r
992                                         \r
993                         }\r
994                 }\r
995                 return Keyboard.KEY_UNLABELED;\r
996             }\r
997 \r
998         \r
999          private int getAWTKeyCode(int swtKeyCode) {\r
1000                 if(swtKeyCode > 1024) {\r
1001                     int keyCode = 0;\r
1002                     switch (swtKeyCode) {\r
1003                     case SWT.CTRL:\r
1004                         keyCode = java.awt.event.KeyEvent.VK_CONTROL;\r
1005                         break;\r
1006                     case SWT.ALT:\r
1007                         keyCode = java.awt.event.KeyEvent.VK_ALT;\r
1008                         break;\r
1009                     \r
1010                     case SWT.SHIFT:\r
1011                         keyCode = java.awt.event.KeyEvent.VK_SHIFT;\r
1012                         break;\r
1013                     case SWT.ARROW_LEFT:\r
1014                         keyCode = java.awt.event.KeyEvent.VK_LEFT;\r
1015                         break;\r
1016                     case SWT.ARROW_RIGHT:\r
1017                         keyCode = java.awt.event.KeyEvent.VK_RIGHT;\r
1018                         break;\r
1019                     case SWT.ARROW_UP:\r
1020                         keyCode = java.awt.event.KeyEvent.VK_UP;\r
1021                         break;\r
1022                     case SWT.ARROW_DOWN:\r
1023                         keyCode = java.awt.event.KeyEvent.VK_DOWN;\r
1024                         break;\r
1025                     case SWT.KEYPAD_0:\r
1026                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD0;\r
1027                         break;\r
1028                     case SWT.KEYPAD_1:\r
1029                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD1;\r
1030                         break;\r
1031                     case SWT.KEYPAD_2:\r
1032                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD2;\r
1033                         break;\r
1034                     case SWT.KEYPAD_3:\r
1035                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD3;\r
1036                         break;\r
1037                     case SWT.KEYPAD_4:\r
1038                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD4;\r
1039                         break;\r
1040                     case SWT.KEYPAD_5:\r
1041                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD5;\r
1042                         break;\r
1043                     case SWT.KEYPAD_6:\r
1044                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD6;\r
1045                         break;\r
1046                     case SWT.KEYPAD_7:\r
1047                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD7;\r
1048                         break;\r
1049                     case SWT.KEYPAD_8:\r
1050                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD8;\r
1051                         break;\r
1052                     case SWT.KEYPAD_9:\r
1053                         keyCode = java.awt.event.KeyEvent.VK_NUMPAD9;\r
1054                         break;\r
1055                     case SWT.KEYPAD_CR:\r
1056                         keyCode = java.awt.event.KeyEvent.VK_ENTER;\r
1057                         break;\r
1058                     case SWT.NUM_LOCK:\r
1059                         keyCode = java.awt.event.KeyEvent.VK_NUM_LOCK;\r
1060                         break;\r
1061                     case SWT.SCROLL_LOCK:\r
1062                         keyCode = java.awt.event.KeyEvent.VK_SCROLL_LOCK;\r
1063                         break;\r
1064                     case SWT.CAPS_LOCK:\r
1065                         keyCode = java.awt.event.KeyEvent.VK_CAPS_LOCK;\r
1066                         break;\r
1067                     case SWT.INSERT:\r
1068                         keyCode = java.awt.event.KeyEvent.VK_INSERT;\r
1069                         break;\r
1070                     case SWT.HOME:\r
1071                         keyCode = java.awt.event.KeyEvent.VK_HOME;\r
1072                         break;\r
1073                     case SWT.END:\r
1074                         keyCode = java.awt.event.KeyEvent.VK_END;\r
1075                         break;\r
1076                     case SWT.PAGE_UP:\r
1077                         keyCode = java.awt.event.KeyEvent.VK_PAGE_UP;\r
1078                         break;\r
1079                     case SWT.PAGE_DOWN:\r
1080                         keyCode = java.awt.event.KeyEvent.VK_PAGE_DOWN;\r
1081                         break;\r
1082                     case SWT.PAUSE:\r
1083                         keyCode = java.awt.event.KeyEvent.VK_PAUSE;   \r
1084                         break;\r
1085                     case SWT.BREAK:\r
1086                         keyCode = java.awt.event.KeyEvent.VK_PAUSE;   \r
1087                         break;\r
1088                     case SWT.PRINT_SCREEN:\r
1089                         keyCode = java.awt.event.KeyEvent.VK_PRINTSCREEN;   \r
1090                         break;   \r
1091                     case SWT.HELP:\r
1092                         keyCode = java.awt.event.KeyEvent.VK_HELP;\r
1093                         break;\r
1094                     default :\r
1095                         keyCode = 0;\r
1096                         break;\r
1097                     }\r
1098                     \r
1099                     return keyCode;\r
1100                 } else if (swtKeyCode == 8) {\r
1101                         return java.awt.event.KeyEvent.VK_BACK_SPACE;\r
1102                 }\r
1103                 else if (swtKeyCode >= 97 )\r
1104                         return swtKeyCode - 32;\r
1105                 else\r
1106                         return swtKeyCode;\r
1107             }\r
1108     }\r
1109 \r
1110 }\r