changeset 327:8716176ff7f0 am-2

added support for arrow keys
author am@osimis.io
date Tue, 16 Oct 2018 15:25:21 +0200
parents 612238b3f3e8
children c80b5bddf86b
files Applications/Qt/QCairoWidget.cpp Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp Applications/Samples/SimpleViewer/MainWidgetInteractor.h Applications/Samples/SimpleViewer/ThumbnailInteractor.h Applications/Samples/SimpleViewerApplicationSingleFile.h Applications/Samples/SingleFrameApplication.h Applications/Samples/SingleFrameEditorApplication.h Applications/Sdl/SdlEngine.cpp Framework/StoneEnumerations.h Framework/Viewport/IViewport.h Framework/Viewport/WidgetViewport.cpp Framework/Viewport/WidgetViewport.h Framework/Widgets/EmptyWidget.h Framework/Widgets/IWidget.h Framework/Widgets/IWorldSceneInteractor.h Framework/Widgets/LayoutWidget.cpp Framework/Widgets/LayoutWidget.h Framework/Widgets/TestCairoWidget.cpp Framework/Widgets/TestCairoWidget.h Framework/Widgets/TestWorldSceneWidget.cpp Framework/Widgets/WorldSceneWidget.cpp Framework/Widgets/WorldSceneWidget.h Framework/dev.h Platforms/Wasm/Defaults.cpp Platforms/Wasm/wasm-viewport.ts Resources/CMake/OrthancStoneConfiguration.cmake
diffstat 26 files changed, 211 insertions(+), 138 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Qt/QCairoWidget.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Qt/QCairoWidget.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -138,9 +138,27 @@
 
 void QCairoWidget::keyPressEvent(QKeyEvent *event)
 {
+  using namespace OrthancStone;
+
   OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
 
-  context_->GetCentralViewport().KeyPressed(event->text()[0].toLatin1(), stoneModifiers);
+  OrthancStone::KeyboardKeys keyType = OrthancStone::KeyboardKeys_Generic;
+  char keyChar = event->text()[0].toLatin1();
+
+#define CASE_QT_KEY_TO_ORTHANC(qt, o) case qt: keyType = o; break;
+  if (keyChar == 0)
+  {
+    switch (event->key())
+    {
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Up, KeyboardKeys_Up);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Down, KeyboardKeys_Down);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Left, KeyboardKeys_Left);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Right, KeyboardKeys_Right);
+    default:
+      break;
+    }
+  }
+  context_->GetCentralViewport().KeyPressed(keyType, keyChar, stoneModifiers);
 }
 
 
--- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -89,11 +89,12 @@
   }
 
   void MainWidgetInteractor::KeyPressed(WorldSceneWidget& widget,
-                                        char key,
+                                        KeyboardKeys key,
+                                        char keyChar,
                                         KeyboardModifiers modifiers,
                                         IStatusBar* statusBar)
   {
-    switch (key)
+    switch (keyChar)
     {
     case 's':
       widget.SetDefaultView();
--- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.h	Tue Oct 16 15:25:21 2018 +0200
@@ -61,7 +61,8 @@
                             IStatusBar* statusBar);
 
     virtual void KeyPressed(WorldSceneWidget& widget,
-                            char key,
+                            KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers,
                             IStatusBar* statusBar);
   };
--- a/Applications/Samples/SimpleViewer/ThumbnailInteractor.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Samples/SimpleViewer/ThumbnailInteractor.h	Tue Oct 16 15:25:21 2018 +0200
@@ -62,7 +62,8 @@
     {}
 
     virtual void KeyPressed(WorldSceneWidget& widget,
-                            char key,
+                            KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers,
                             IStatusBar* statusBar)
     {}
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Tue Oct 16 15:25:21 2018 +0200
@@ -88,7 +88,8 @@
         {}
 
         virtual void KeyPressed(WorldSceneWidget& widget,
-                                char key,
+                                KeyboardKeys key,
+                                char keyChar,
                                 KeyboardModifiers modifiers,
                                 IStatusBar* statusBar)
         {}
@@ -154,11 +155,12 @@
         }
 
         virtual void KeyPressed(WorldSceneWidget& widget,
-                                char key,
+                                KeyboardKeys key,
+                                char keyChar,
                                 KeyboardModifiers modifiers,
                                 IStatusBar* statusBar)
         {
-          switch (key)
+          switch (keyChar)
           {
           case 's':
             widget.SetDefaultView();
--- a/Applications/Samples/SingleFrameApplication.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Samples/SingleFrameApplication.h	Tue Oct 16 15:25:21 2018 +0200
@@ -100,11 +100,12 @@
         }
 
         virtual void KeyPressed(WorldSceneWidget& widget,
-                                char key,
+                                KeyboardKeys key,
+                                char keyChar,
                                 KeyboardModifiers modifiers,
                                 IStatusBar* statusBar)
         {
-          switch (key)
+          switch (keyChar)
           {
             case 's':
               widget.SetDefaultView();
--- a/Applications/Samples/SingleFrameEditorApplication.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Tue Oct 16 15:25:21 2018 +0200
@@ -109,11 +109,12 @@
         }
 
         virtual void KeyPressed(WorldSceneWidget& widget,
-                                char key,
+                                KeyboardKeys key,
+                                char keyChar,
                                 KeyboardModifiers modifiers,
                                 IStatusBar* statusBar)
         {
-          switch (key)
+          switch (keyChar)
           {
           case 's':
             widget.SetDefaultView();
--- a/Applications/Sdl/SdlEngine.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Applications/Sdl/SdlEngine.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -13,7 +13,7 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Affero General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
@@ -35,7 +35,7 @@
     context_.GetCentralViewport().SetSize(width, height);
     surface_.SetSize(width, height);
   }
-    
+
 
   void SdlEngine::RenderFrame()
   {
@@ -135,7 +135,7 @@
       {
         NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
 
-        if (event.type == SDL_QUIT) 
+        if (event.type == SDL_QUIT)
         {
           stop = true;
           break;
@@ -146,20 +146,20 @@
 
           switch (event.button.button)
           {
-            case SDL_BUTTON_LEFT:
-              context_.GetCentralViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers);
-              break;
+          case SDL_BUTTON_LEFT:
+            context_.GetCentralViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers);
+            break;
             
-            case SDL_BUTTON_RIGHT:
-              context_.GetCentralViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers);
-              break;
+          case SDL_BUTTON_RIGHT:
+            context_.GetCentralViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers);
+            break;
             
-            case SDL_BUTTON_MIDDLE:
-              context_.GetCentralViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers);
-              break;
+          case SDL_BUTTON_MIDDLE:
+            context_.GetCentralViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers);
+            break;
 
-            default:
-              break;
+          default:
+            break;
           }
         }
         else if (event.type == SDL_MOUSEMOTION)
@@ -174,20 +174,20 @@
         {
           switch (event.window.event)
           {
-            case SDL_WINDOWEVENT_LEAVE:
-              context_.GetCentralViewport().MouseLeave();
-              break;
+          case SDL_WINDOWEVENT_LEAVE:
+            context_.GetCentralViewport().MouseLeave();
+            break;
 
-            case SDL_WINDOWEVENT_ENTER:
-              context_.GetCentralViewport().MouseEnter();
-              break;
+          case SDL_WINDOWEVENT_ENTER:
+            context_.GetCentralViewport().MouseEnter();
+            break;
 
-            case SDL_WINDOWEVENT_SIZE_CHANGED:
-              SetSize(event.window.data1, event.window.data2);
-              break;
+          case SDL_WINDOWEVENT_SIZE_CHANGED:
+            SetSize(event.window.data1, event.window.data2);
+            break;
 
-            default:
-              break;
+          default:
+            break;
           }
         }
         else if (event.type == SDL_MOUSEWHEEL)
@@ -213,53 +213,61 @@
 
           switch (event.key.keysym.sym)
           {
-            case SDLK_a:    context_.GetCentralViewport().KeyPressed('a', modifiers);  break;
-            case SDLK_b:    context_.GetCentralViewport().KeyPressed('b', modifiers);  break;
-            case SDLK_c:    context_.GetCentralViewport().KeyPressed('c', modifiers);  break;
-            case SDLK_d:    context_.GetCentralViewport().KeyPressed('d', modifiers);  break;
-            case SDLK_e:    context_.GetCentralViewport().KeyPressed('e', modifiers);  break;
-            case SDLK_f:    window_.ToggleMaximize();                         break;
-            case SDLK_g:    context_.GetCentralViewport().KeyPressed('g', modifiers);  break;
-            case SDLK_h:    context_.GetCentralViewport().KeyPressed('h', modifiers);  break;
-            case SDLK_i:    context_.GetCentralViewport().KeyPressed('i', modifiers);  break;
-            case SDLK_j:    context_.GetCentralViewport().KeyPressed('j', modifiers);  break;
-            case SDLK_k:    context_.GetCentralViewport().KeyPressed('k', modifiers);  break;
-            case SDLK_l:    context_.GetCentralViewport().KeyPressed('l', modifiers);  break;
-            case SDLK_m:    context_.GetCentralViewport().KeyPressed('m', modifiers);  break;
-            case SDLK_n:    context_.GetCentralViewport().KeyPressed('n', modifiers);  break;
-            case SDLK_o:    context_.GetCentralViewport().KeyPressed('o', modifiers);  break;
-            case SDLK_p:    context_.GetCentralViewport().KeyPressed('p', modifiers);  break;
-            case SDLK_q:    stop = true;                                      break;
-            case SDLK_r:    context_.GetCentralViewport().KeyPressed('r', modifiers);  break;
-            case SDLK_s:    context_.GetCentralViewport().KeyPressed('s', modifiers);  break;
-            case SDLK_t:    context_.GetCentralViewport().KeyPressed('t', modifiers);  break;
-            case SDLK_u:    context_.GetCentralViewport().KeyPressed('u', modifiers);  break;
-            case SDLK_v:    context_.GetCentralViewport().KeyPressed('v', modifiers);  break;
-            case SDLK_w:    context_.GetCentralViewport().KeyPressed('w', modifiers);  break;
-            case SDLK_x:    context_.GetCentralViewport().KeyPressed('x', modifiers);  break;
-            case SDLK_y:    context_.GetCentralViewport().KeyPressed('y', modifiers);  break;
-            case SDLK_z:    context_.GetCentralViewport().KeyPressed('z', modifiers);  break;
-            case SDLK_KP_0: context_.GetCentralViewport().KeyPressed('0', modifiers);  break;
-            case SDLK_KP_1: context_.GetCentralViewport().KeyPressed('1', modifiers);  break;
-            case SDLK_KP_2: context_.GetCentralViewport().KeyPressed('2', modifiers);  break;
-            case SDLK_KP_3: context_.GetCentralViewport().KeyPressed('3', modifiers);  break;
-            case SDLK_KP_4: context_.GetCentralViewport().KeyPressed('4', modifiers);  break;
-            case SDLK_KP_5: context_.GetCentralViewport().KeyPressed('5', modifiers);  break;
-            case SDLK_KP_6: context_.GetCentralViewport().KeyPressed('6', modifiers);  break;
-            case SDLK_KP_7: context_.GetCentralViewport().KeyPressed('7', modifiers);  break;
-            case SDLK_KP_8: context_.GetCentralViewport().KeyPressed('8', modifiers);  break;
-            case SDLK_KP_9: context_.GetCentralViewport().KeyPressed('9', modifiers);  break;
+          case SDLK_a:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'a', modifiers);  break;
+          case SDLK_b:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'b', modifiers);  break;
+          case SDLK_c:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'c', modifiers);  break;
+          case SDLK_d:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'd', modifiers);  break;
+          case SDLK_e:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'e', modifiers);  break;
+          case SDLK_f:    window_.ToggleMaximize();                         break;
+          case SDLK_g:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'g', modifiers);  break;
+          case SDLK_h:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'h', modifiers);  break;
+          case SDLK_i:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'i', modifiers);  break;
+          case SDLK_j:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'j', modifiers);  break;
+          case SDLK_k:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'k', modifiers);  break;
+          case SDLK_l:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'l', modifiers);  break;
+          case SDLK_m:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'm', modifiers);  break;
+          case SDLK_n:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'n', modifiers);  break;
+          case SDLK_o:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'o', modifiers);  break;
+          case SDLK_p:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'p', modifiers);  break;
+          case SDLK_q:    stop = true;                                      break;
+          case SDLK_r:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'r', modifiers);  break;
+          case SDLK_s:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 's', modifiers);  break;
+          case SDLK_t:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 't', modifiers);  break;
+          case SDLK_u:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'u', modifiers);  break;
+          case SDLK_v:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'v', modifiers);  break;
+          case SDLK_w:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'w', modifiers);  break;
+          case SDLK_x:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'x', modifiers);  break;
+          case SDLK_y:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'y', modifiers);  break;
+          case SDLK_z:    context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'z', modifiers);  break;
+          case SDLK_KP_0: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '0', modifiers);  break;
+          case SDLK_KP_1: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '1', modifiers);  break;
+          case SDLK_KP_2: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '2', modifiers);  break;
+          case SDLK_KP_3: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '3', modifiers);  break;
+          case SDLK_KP_4: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '4', modifiers);  break;
+          case SDLK_KP_5: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '5', modifiers);  break;
+          case SDLK_KP_6: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '6', modifiers);  break;
+          case SDLK_KP_7: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '7', modifiers);  break;
+          case SDLK_KP_8: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '8', modifiers);  break;
+          case SDLK_KP_9: context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '9', modifiers);  break;
 
-            case SDLK_PLUS:
-            case SDLK_KP_PLUS:
-              context_.GetCentralViewport().KeyPressed('+', modifiers);  break;
+          case SDLK_PLUS:
+          case SDLK_KP_PLUS:
+            context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '+', modifiers);  break;
+
+          case SDLK_MINUS:
+          case SDLK_KP_MINUS:
+            context_.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '-', modifiers);  break;
 
-            case SDLK_MINUS:
-            case SDLK_KP_MINUS:
-              context_.GetCentralViewport().KeyPressed('-', modifiers);  break;
-
-            default:
-              break;
+          case SDLK_RIGHT:
+            context_.GetCentralViewport().KeyPressed(KeyboardKeys_Right, 0, modifiers);  break;
+          case SDLK_LEFT:
+            context_.GetCentralViewport().KeyPressed(KeyboardKeys_Left, 0, modifiers);  break;
+          case SDLK_UP:
+            context_.GetCentralViewport().KeyPressed(KeyboardKeys_Up, 0, modifiers);  break;
+          case SDLK_DOWN:
+            context_.GetCentralViewport().KeyPressed(KeyboardKeys_Down, 0, modifiers);  break;
+          default:
+            break;
           }
         }
       }
--- a/Framework/StoneEnumerations.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/StoneEnumerations.h	Tue Oct 16 15:25:21 2018 +0200
@@ -75,6 +75,17 @@
     KeyboardModifiers_Alt = (1 << 2)
   };
 
+  enum KeyboardKeys
+  {
+    KeyboardKeys_Generic = 0,
+
+    // let's use the same ids as in javascript to avoid some conversion in WASM: https://css-tricks.com/snippets/javascript/javascript-keycodes/
+    KeyboardKeys_Left = 37,
+    KeyboardKeys_Up = 38,
+    KeyboardKeys_Right = 39,
+    KeyboardKeys_Down = 40
+  };
+
   enum SliceImageQuality
   {
     SliceImageQuality_FullPng,  // smaller to transmit but longer to generate on Orthanc side (better choice when on low bandwidth)
--- a/Framework/Viewport/IViewport.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Viewport/IViewport.h	Tue Oct 16 15:25:21 2018 +0200
@@ -78,7 +78,8 @@
                             int y,
                             KeyboardModifiers modifiers) = 0;
 
-    virtual void KeyPressed(char key,
+    virtual void KeyPressed(KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers) = 0;
 
     virtual bool HasUpdateContent() = 0;
--- a/Framework/Viewport/WidgetViewport.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Viewport/WidgetViewport.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -235,13 +235,14 @@
   }
 
 
-  void WidgetViewport::KeyPressed(char key,
+  void WidgetViewport::KeyPressed(KeyboardKeys key,
+                                  char keyChar,
                                   KeyboardModifiers modifiers)
   {
     if (centralWidget_.get() != NULL &&
         mouseTracker_.get() == NULL)
     {
-      centralWidget_->KeyPressed(key, modifiers);
+      centralWidget_->KeyPressed(key, keyChar, modifiers);
     }
   }
 
--- a/Framework/Viewport/WidgetViewport.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Viewport/WidgetViewport.h	Tue Oct 16 15:25:21 2018 +0200
@@ -82,7 +82,8 @@
                             int y,
                             KeyboardModifiers modifiers);
 
-    virtual void KeyPressed(char key,
+    virtual void KeyPressed(KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers);
 
     virtual bool HasUpdateContent();
--- a/Framework/Widgets/EmptyWidget.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/EmptyWidget.h	Tue Oct 16 15:25:21 2018 +0200
@@ -94,7 +94,8 @@
     {
     }
 
-    virtual void KeyPressed(char key,
+    virtual void KeyPressed(KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers)
     {
     }
--- a/Framework/Widgets/IWidget.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/IWidget.h	Tue Oct 16 15:25:21 2018 +0200
@@ -64,7 +64,8 @@
                             int y,
                             KeyboardModifiers modifiers) = 0;
 
-    virtual void KeyPressed(char key,
+    virtual void KeyPressed(KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers) = 0;
 
     virtual bool HasUpdateContent() const = 0;
--- a/Framework/Widgets/IWorldSceneInteractor.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/IWorldSceneInteractor.h	Tue Oct 16 15:25:21 2018 +0200
@@ -13,7 +13,7 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Affero General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
@@ -29,38 +29,39 @@
 
 namespace OrthancStone
 {
-  class WorldSceneWidget;
+    class WorldSceneWidget;
 
-  class IWorldSceneInteractor : public boost::noncopyable
-  {
-  public:
-    virtual ~IWorldSceneInteractor()
+    class IWorldSceneInteractor : public boost::noncopyable
     {
-    }
-    
-    virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                        const ViewportGeometry& view,
-                                                        MouseButton button,
-                                                        KeyboardModifiers modifiers,
-                                                        double x,
-                                                        double y,
-                                                        IStatusBar* statusBar) = 0;
+    public:
+        virtual ~IWorldSceneInteractor()
+        {
+        }
+
+        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+                                                            const ViewportGeometry& view,
+                                                            MouseButton button,
+                                                            KeyboardModifiers modifiers,
+                                                            double x,
+                                                            double y,
+                                                            IStatusBar* statusBar) = 0;
 
-    virtual void MouseOver(CairoContext& context,
-                           WorldSceneWidget& widget,
-                           const ViewportGeometry& view,
-                           double x,
-                           double y,
-                           IStatusBar* statusBar) = 0;
+        virtual void MouseOver(CairoContext& context,
+                               WorldSceneWidget& widget,
+                               const ViewportGeometry& view,
+                               double x,
+                               double y,
+                               IStatusBar* statusBar) = 0;
 
-    virtual void MouseWheel(WorldSceneWidget& widget,
-                            MouseWheelDirection direction,
-                            KeyboardModifiers modifiers,
-                            IStatusBar* statusBar) = 0;
+        virtual void MouseWheel(WorldSceneWidget& widget,
+                                MouseWheelDirection direction,
+                                KeyboardModifiers modifiers,
+                                IStatusBar* statusBar) = 0;
 
-    virtual void KeyPressed(WorldSceneWidget& widget,
-                            char key,
-                            KeyboardModifiers modifiers,
-                            IStatusBar* statusBar) = 0;
-  };
+        virtual void KeyPressed(WorldSceneWidget& widget,
+                                KeyboardKeys key,
+                                char keyChar,
+                                KeyboardModifiers modifiers,
+                                IStatusBar* statusBar) = 0;
+    };
 }
--- a/Framework/Widgets/LayoutWidget.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/LayoutWidget.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -451,12 +451,13 @@
   }
 
 
-  void LayoutWidget::KeyPressed(char key,
+  void LayoutWidget::KeyPressed(KeyboardKeys key,
+                                char keyChar,
                                 KeyboardModifiers modifiers)
   {
     for (size_t i = 0; i < children_.size(); i++)
     {
-      children_[i]->GetWidget().KeyPressed(key, modifiers);
+      children_[i]->GetWidget().KeyPressed(key, keyChar, modifiers);
     }
   }
 
--- a/Framework/Widgets/LayoutWidget.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/LayoutWidget.h	Tue Oct 16 15:25:21 2018 +0200
@@ -117,7 +117,8 @@
                             int y,
                             KeyboardModifiers modifiers);
 
-    virtual void KeyPressed(char key,
+    virtual void KeyPressed(KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers);
 
     virtual bool HasUpdateContent() const
--- a/Framework/Widgets/TestCairoWidget.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/TestCairoWidget.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -115,10 +115,11 @@
     }
 
     
-    void TestCairoWidget::KeyPressed(char key,
+    void TestCairoWidget::KeyPressed(KeyboardKeys key,
+                                     char keyChar,
                                      KeyboardModifiers modifiers)
     {
-      UpdateStatusBar("Key pressed: \"" + std::string(1, key) + "\"");
+      UpdateStatusBar("Key pressed: \"" + std::string(1, keyChar) + "\"");
     }
   }
 }
--- a/Framework/Widgets/TestCairoWidget.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/TestCairoWidget.h	Tue Oct 16 15:25:21 2018 +0200
@@ -58,7 +58,8 @@
                               int y,
                               KeyboardModifiers modifiers);
     
-      virtual void KeyPressed(char key,
+      virtual void KeyPressed(KeyboardKeys key,
+                              char keyChar,
                               KeyboardModifiers modifiers);
 
       virtual bool HasUpdateContent() const
--- a/Framework/Widgets/TestWorldSceneWidget.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/TestWorldSceneWidget.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -13,7 +13,7 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Affero General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
@@ -81,20 +81,21 @@
       }
 
       virtual void KeyPressed(WorldSceneWidget& widget,
-                              char key,
+                              KeyboardKeys key,
+                              char keyChar,
                               KeyboardModifiers modifiers,
                               IStatusBar* statusBar)
       {
         if (statusBar)
         {
-          statusBar->SetMessage("Key pressed: \"" + std::string(1, key) + "\"");
+          statusBar->SetMessage("Key pressed: \"" + std::string(1, keyChar) + "\"");
         }
       }
     };
 
 
     bool TestWorldSceneWidget::RenderScene(CairoContext& context,
-                                           const ViewportGeometry& view) 
+                                           const ViewportGeometry& view)
     {
       cairo_t* cr = context.GetObject();
 
--- a/Framework/Widgets/WorldSceneWidget.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/WorldSceneWidget.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -330,12 +330,13 @@
   }
 
 
-  void WorldSceneWidget::KeyPressed(char key,
+  void WorldSceneWidget::KeyPressed(KeyboardKeys key,
+                                    char keyChar,
                                     KeyboardModifiers modifiers)
   {
     if (interactor_)
     {
-      interactor_->KeyPressed(*this, key, modifiers, GetStatusBar());
+      interactor_->KeyPressed(*this, key, keyChar, modifiers, GetStatusBar());
     }
   }
 }
--- a/Framework/Widgets/WorldSceneWidget.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/Widgets/WorldSceneWidget.h	Tue Oct 16 15:25:21 2018 +0200
@@ -160,7 +160,8 @@
                             int y,
                             KeyboardModifiers modifiers);
 
-    virtual void KeyPressed(char key,
+    virtual void KeyPressed(KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers);
   };
 }
--- a/Framework/dev.h	Tue Oct 16 12:57:38 2018 +0200
+++ b/Framework/dev.h	Tue Oct 16 15:25:21 2018 +0200
@@ -748,11 +748,12 @@
     }
 
     virtual void KeyPressed(WorldSceneWidget& widget,
-                            char key,
+                            KeyboardKeys key,
+                            char keyChar,
                             KeyboardModifiers modifiers,
                             IStatusBar* statusBar)
     {
-      switch (key)
+      switch (keyChar)
       {
       case 's':
         widget.SetDefaultView();
--- a/Platforms/Wasm/Defaults.cpp	Tue Oct 16 12:57:38 2018 +0200
+++ b/Platforms/Wasm/Defaults.cpp	Tue Oct 16 15:25:21 2018 +0200
@@ -219,7 +219,8 @@
   }
   
   void EMSCRIPTEN_KEEPALIVE ViewportKeyPressed(ViewportHandle viewport,
-                                               const char* key, 
+                                               int key,
+                                               const char* keyChar, 
                                                bool isShiftPressed, 
                                                bool isControlPressed,
                                                bool isAltPressed)
@@ -235,8 +236,12 @@
     if (isAltPressed) {
       modifiers = static_cast<OrthancStone::KeyboardModifiers>(modifiers + OrthancStone::KeyboardModifiers_Alt);
     }
-    printf("key pressed : %c\n", key[0]);
-    viewport->KeyPressed(key[0], modifiers);
+
+    char c = 0;
+    if (keyChar != NULL && key == OrthancStone::KeyboardKeys_Generic) {
+      c = keyChar[0];
+    }
+    viewport->KeyPressed(static_cast<OrthancStone::KeyboardKeys>(key), c, modifiers);
   }
   
 
--- a/Platforms/Wasm/wasm-viewport.ts	Tue Oct 16 12:57:38 2018 +0200
+++ b/Platforms/Wasm/wasm-viewport.ts	Tue Oct 16 15:25:21 2018 +0200
@@ -80,7 +80,7 @@
       this.ViewportMouseEnter = this.module_.cwrap('ViewportMouseEnter', null, [ 'number' ]);
       this.ViewportMouseLeave = this.module_.cwrap('ViewportMouseLeave', null, [ 'number' ]);
       this.ViewportMouseWheel = this.module_.cwrap('ViewportMouseWheel', null, [ 'number', 'number', 'number', 'number', 'number' ]);
-      this.ViewportKeyPressed = this.module_.cwrap('ViewportKeyPressed', null, [ 'number', 'string', 'number', 'number' ]);
+      this.ViewportKeyPressed = this.module_.cwrap('ViewportKeyPressed', null, [ 'number', 'number', 'string', 'number', 'number' ]);
     }
 
     public GetCppViewport() : number {
@@ -204,7 +204,15 @@
       });
     
       window.addEventListener('keydown', function(event) {
-        that.ViewportKeyPressed(that.pimpl_, event.key, event.shiftKey, event.ctrlKey, event.altKey);
+        var keyChar = event.key;
+        var keyCode = event.keyCode
+        if (keyChar.length == 1) {
+          keyCode = 0; // maps to OrthancStone::KeyboardKeys_Generic
+        } else {
+          keyChar = null;
+        }
+//        console.log("key: ", keyCode, keyChar);
+        that.ViewportKeyPressed(that.pimpl_, keyCode, keyChar, event.shiftKey, event.ctrlKey, event.altKey);
       });
     
       this.htmlCanvas_.addEventListener('wheel', function(event) {
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Oct 16 12:57:38 2018 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Oct 16 15:25:21 2018 +0200
@@ -273,7 +273,9 @@
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeReslicer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/CairoWidget.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/EmptyWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWidget.h
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWorldSceneMouseTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWorldSceneInteractor.h
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/LayerWidget.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/LayoutWidget.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Widgets/TestCairoWidget.cpp