diff --git a/include/base.css b/include/base.css
index 0578619e6c48726a2f152d184b51940540384b03..cc6575f38f9be1dcb5d3618067725cc4a679bcda 100644
--- a/include/base.css
+++ b/include/base.css
@@ -62,6 +62,14 @@ html {
   display: none;
 }
 
+#noVNC_extra_keys {
+  display: inline;
+  list-style-type: none;
+  padding: 0px;
+  margin: 0px;
+  position: relative;
+}
+
 .noVNC-buttons-left {
   float: left;
   z-index: 1;
@@ -404,6 +412,31 @@ html {
   width: 100%;
 }
 
+#noVNC_extra_keys {
+  float: none;
+  top: 0px;
+}
+
+#noVNC_extra_keys li {  
+  display: inline;
+}
+
+#showExtraKeysButton {
+  display: none;
+}
+#toggleCtrlButton {
+  display: inline;
+}
+#toggleAltButton {
+  display: inline;
+}
+#sendTabButton {
+  display: inline;
+}
+#sendEscButton {
+  display: inline;
+}
+
 @media screen and (max-width: 640px){
   .noVNC_status_button {
     font-size: 10px;
@@ -420,6 +453,28 @@ html {
     width: auto;
     float: left;
   }
+  #noVNC_extra_keys {
+    float: right;
+    top: -35px;
+  }
+  #noVNC_extra_keys li {
+    display: block;
+  }
+  #showExtraKeysButton {
+    display: inline;
+  }
+  #toggleCtrlButton {
+    display: none;
+  }
+  #toggleAltButton {
+    display: none;
+  }
+  #sendTabButton {
+    display: none;
+  }
+  #sendEscButton {
+    display: none;
+  }
 }
 
 @media screen and (min-width: 481px) and (max-width: 640px) {
diff --git a/include/ui.js b/include/ui.js
index b933d312e2129c37a776c0c409a12ab74082b73b..057a42fb00a8fcb6ee723056ab4b65fa438f3d2c 100644
--- a/include/ui.js
+++ b/include/ui.js
@@ -24,6 +24,10 @@ connSettingsOpen : false,
 popupStatusOpen : false,
 clipboardOpen: false,
 keyboardVisible: false,
+hideKeyboardTimeout: null,
+extraKeysVisible: false,
+ctrlOn: false,
+altOn: false,
 
 // Setup rfb object, load settings from browser storage, then call
 // UI.init to setup the UI/menus
@@ -158,6 +162,12 @@ addMouseHandlers: function() {
     //$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); };
     $D("keyboardinput").onblur = UI.keyInputBlur;
 
+    $D("showExtraKeysButton").onclick = UI.showExtraKeys;
+    $D("toggleCtrlButton").onclick = UI.toggleCtrl;
+    $D("toggleAltButton").onclick = UI.toggleAlt;
+    $D("sendTabButton").onclick = UI.sendTab;
+    $D("sendEscButton").onclick = UI.sendEsc;
+
     $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel;
     $D("noVNC_status").onclick = UI.togglePopupStatusPanel;
     $D("noVNC_popup_status_panel").onclick = UI.togglePopupStatusPanel;
@@ -532,13 +542,16 @@ updateVisualState: function() {
         UI.setMouseButton(1);
         $D('clipboardButton').style.display = "inline";
         $D('showKeyboard').style.display = "inline";
+        $D('noVNC_extra_keys').style.display = "";
         $D('sendCtrlAltDelButton').style.display = "inline";
     } else {
         UI.setMouseButton();
         $D('clipboardButton').style.display = "none";
         $D('showKeyboard').style.display = "none";
+        $D('noVNC_extra_keys').style.display = "none";
         $D('sendCtrlAltDelButton').style.display = "none";
     }
+    
     // State change disables viewport dragging.
     // It is enabled (toggled) by direct click on the button
     UI.setViewDrag(false);
@@ -712,12 +725,78 @@ showKeyboard: function() {
     }
 },
 
+keepKeyboard: function() {
+    clearTimeout(UI.hideKeyboardTimeout);
+    if(UI.keyboardVisible === true) {
+        $D('keyboardinput').focus();
+        $D('showKeyboard').className = "noVNC_status_button_selected";
+    } else if(UI.keyboardVisible === false) {
+        $D('keyboardinput').blur();
+        $D('showKeyboard').className = "noVNC_status_button";
+    }
+},
+
 keyInputBlur: function() {
     $D('showKeyboard').className = "noVNC_status_button";
     //Weird bug in iOS if you change keyboardVisible
     //here it does not actually occur so next time
     //you click keyboard icon it doesnt work.
-    setTimeout(function() { UI.setKeyboard(); },100);
+    UI.hideKeyboardTimeout = setTimeout(function() { UI.setKeyboard(); },100);
+},
+
+showExtraKeys: function() {
+    UI.keepKeyboard();
+    if(UI.extraKeysVisible === false) {
+        $D('toggleCtrlButton').style.display = "inline";
+        $D('toggleAltButton').style.display = "inline";
+        $D('sendTabButton').style.display = "inline";
+        $D('sendEscButton').style.display = "inline";
+        $D('showExtraKeysButton').className = "noVNC_status_button_selected";
+        UI.extraKeysVisible = true;
+    } else if(UI.extraKeysVisible === true) {
+        $D('toggleCtrlButton').style.display = "";
+        $D('toggleAltButton').style.display = "";
+        $D('sendTabButton').style.display = "";
+        $D('sendEscButton').style.display = "";
+        $D('showExtraKeysButton').className = "noVNC_status_button";
+        UI.extraKeysVisible = false;
+    }
+},
+
+toggleCtrl: function() {
+    UI.keepKeyboard();
+    if(UI.ctrlOn === false) {
+        UI.rfb.sendKey(0xFFE3, true);
+        $D('toggleCtrlButton').className = "noVNC_status_button_selected";
+        UI.ctrlOn = true;
+    } else if(UI.ctrlOn === true) {
+        UI.rfb.sendKey(0xFFE3, false);
+        $D('toggleCtrlButton').className = "noVNC_status_button";
+        UI.ctrlOn = false;
+    }
+},
+
+toggleAlt: function() {
+    UI.keepKeyboard();
+    if(UI.altOn === false) {
+        UI.rfb.sendKey(0xFFE9, true);
+        $D('toggleAltButton').className = "noVNC_status_button_selected";
+        UI.altOn = true;
+    } else if(UI.altOn === true) {
+        UI.rfb.sendKey(0xFFE9, false);
+        $D('toggleAltButton').className = "noVNC_status_button";
+        UI.altOn = false;
+    }
+},
+
+sendTab: function() {
+    UI.keepKeyboard();
+    UI.rfb.sendKey(0xFF09);
+},
+
+sendEsc: function() {
+    UI.keepKeyboard();
+    UI.rfb.sendKey(0xFF1B);
 },
 
 setKeyboard: function() {
diff --git a/vnc.html b/vnc.html
index 66b702593885f783848f68d0a970293a4f97ce97..306ab85986a441288a61791a1be105b2b770c3e2 100644
--- a/vnc.html
+++ b/vnc.html
@@ -68,6 +68,23 @@
                     value="Keyboard" title="Show Keyboard"/>
                 <input type="email" autocapitalize="off" autocorrect="off"
                     id="keyboardinput" class=""/>
+                <ul id="noVNC_extra_keys">
+                    <li><input type="image" src="images/showextrakeys.png"
+                            id="showExtraKeysButton"
+                            class="noVNC_status_button"></li>
+                    <li><input type="image" src="images/ctrl.png"
+                            id="toggleCtrlButton"
+                            class="noVNC_status_button"></li>
+                    <li><input type="image" src="images/alt.png"
+                            id="toggleAltButton"
+                            class="noVNC_status_button"></li>
+                    <li><input type="image" src="images/tab.png"
+                            id="sendTabButton"
+                            class="noVNC_status_button"></li>
+                    <li><input type="image" src="images/esc.png"
+                            id="sendEscButton"
+                            class="noVNC_status_button"></li>
+                </ul>
             </div>
         </div>