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