SVGHMI: Keypad working for HMI_STRING, still Shift/CapsLock not finished. svghmi
authorEdouard Tisserant
Fri, 03 Apr 2020 14:37:41 +0200
branchsvghmi
changeset 2917 c8d923dd707f
parent 2916 4f3b130fd197
child 2918 5cb6ab87b185
SVGHMI: Keypad working for HMI_STRING, still Shift/CapsLock not finished.
svghmi/gen_index_xhtml.xslt
svghmi/svghmi.js
svghmi/widget_input.ysl2
svghmi/widget_keypad.ysl2
tests/svghmi/svghmi_0@svghmi/svghmi.svg
--- a/svghmi/gen_index_xhtml.xslt	Fri Apr 03 09:52:57 2020 +0200
+++ b/svghmi/gen_index_xhtml.xslt	Fri Apr 03 14:37:41 2020 +0200
@@ -951,13 +951,13 @@
     <xsl:value-of select="path/@value"/>
     <xsl:text>", "</xsl:text>
     <xsl:value-of select="path/@type"/>
-    <xsl:text>", this.edit_callback, this.last_val);
+    <xsl:text>", this, this.last_val);
 </xsl:text>
     <xsl:text>    },
 </xsl:text>
     <xsl:text>    edit_callback: function(new_val) {
 </xsl:text>
-    <xsl:text>        apply_hmi_value(this.indexes[0], opstr);
+    <xsl:text>        apply_hmi_value(this.indexes[0], new_val);
 </xsl:text>
     <xsl:if test="$have_value">
       <xsl:text>        this.value_elt.textContent = String(new_val);
@@ -1187,8 +1187,171 @@
     </xsl:if>
   </xsl:template>
   <xsl:template mode="widget_defs" match="widget[@type='Keypad']">
+    <xsl:param name="hmi_element"/>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>Esc Enter BackSpace Keys Info Value</xsl:text>
+      </xsl:with-param>
+    </xsl:call-template>
+    <xsl:call-template name="defs_by_labels">
+      <xsl:with-param name="hmi_element" select="$hmi_element"/>
+      <xsl:with-param name="labels">
+        <xsl:text>Sign CapsLock Shift Space</xsl:text>
+      </xsl:with-param>
+      <xsl:with-param name="mandatory" select="'no'"/>
+    </xsl:call-template>
     <xsl:text>    init: function() {
 </xsl:text>
+    <xsl:for-each select="$hmi_element/*[@inkscape:label = 'Keys']/*">
+      <xsl:text>        id("</xsl:text>
+      <xsl:value-of select="@id"/>
+      <xsl:text>").setAttribute("onclick", "hmi_widgets['</xsl:text>
+      <xsl:value-of select="$hmi_element/@id"/>
+      <xsl:text>'].on_key_click('</xsl:text>
+      <xsl:value-of select="func:escape_quotes(@inkscape:label)"/>
+      <xsl:text>')");
+</xsl:text>
+    </xsl:for-each>
+    <xsl:for-each select="str:split('Esc Enter BackSpace Sign Space CapsLock Shift')">
+      <xsl:text>        if(this.</xsl:text>
+      <xsl:value-of select="."/>
+      <xsl:text>_elt)
+</xsl:text>
+      <xsl:text>            this.</xsl:text>
+      <xsl:value-of select="."/>
+      <xsl:text>_elt.setAttribute("onclick", "hmi_widgets['</xsl:text>
+      <xsl:value-of select="$hmi_element/@id"/>
+      <xsl:text>'].on_</xsl:text>
+      <xsl:value-of select="."/>
+      <xsl:text>_click()");
+</xsl:text>
+    </xsl:for-each>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    on_key_click: function(symbols) {
+</xsl:text>
+    <xsl:text>        var syms = symbols.split(" ");
+</xsl:text>
+    <xsl:text>        this.shift = this.caps;
+</xsl:text>
+    <xsl:text>        this.editstr += syms[this.shift?syms.length:0];
+</xsl:text>
+    <xsl:text>        this.shift = false;
+</xsl:text>
+    <xsl:text>        this.update();
+</xsl:text>
+    <xsl:text>        console.log(symbols);
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    on_Esc_click: function() {
+</xsl:text>
+    <xsl:text>        end_modal.call(this);
+</xsl:text>
+    <xsl:text>        console.log("Esc");
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    on_Enter_click: function() {
+</xsl:text>
+    <xsl:text>        end_modal.call(this);
+</xsl:text>
+    <xsl:text>        callback_obj = this.result_callback_obj;
+</xsl:text>
+    <xsl:text>        callback_obj.edit_callback(this.editstr);
+</xsl:text>
+    <xsl:text>        console.log("Enter");
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    on_BackSpace_click: function() {
+</xsl:text>
+    <xsl:text>        this.editstr = this.editstr.slice(0,this.editstr.length-1);
+</xsl:text>
+    <xsl:text>        this.update();
+</xsl:text>
+    <xsl:text>        console.log("BackSpace");
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    on_Sign_click: function() {
+</xsl:text>
+    <xsl:text>        if(this.editstr[0] == "-")
+</xsl:text>
+    <xsl:text>            this.editstr = this.editstr.slice(1,this.editstr.length);
+</xsl:text>
+    <xsl:text>        else
+</xsl:text>
+    <xsl:text>            this.editstr = "-" + this.editstr;
+</xsl:text>
+    <xsl:text>        console.log("Sign");
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    on_Space_click: function() {
+</xsl:text>
+    <xsl:text>        this.editstr += " ";
+</xsl:text>
+    <xsl:text>        console.log("Space");
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    caps: false,
+</xsl:text>
+    <xsl:text>    on_CapsLock_click: function() {
+</xsl:text>
+    <xsl:text>        this.caps = !this.caps;
+</xsl:text>
+    <xsl:text>        console.log("CapsLock");
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    shift: false,
+</xsl:text>
+    <xsl:text>    on_Shift_click: function() {
+</xsl:text>
+    <xsl:text>        this.shift = true;
+</xsl:text>
+    <xsl:text>        console.log("Shift");
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:variable name="g" select="$geometry[@Id = $hmi_element/@id]"/>
+    <xsl:text>    coordinates: [</xsl:text>
+    <xsl:value-of select="$g/@x"/>
+    <xsl:text>, </xsl:text>
+    <xsl:value-of select="$g/@y"/>
+    <xsl:text>],
+</xsl:text>
+    <xsl:text>    editstr: "",
+</xsl:text>
+    <xsl:text>    result_callback_obj: undefined,
+</xsl:text>
+    <xsl:text>    start_edit: function(info, valuetype, callback_obj, initial) {
+</xsl:text>
+    <xsl:text>        show_modal.call(this);
+</xsl:text>
+    <xsl:text>        this.editstr = initial;
+</xsl:text>
+    <xsl:text>        this.result_callback_obj = callback_obj;
+</xsl:text>
+    <xsl:text>        this.Info_elt.textContent = info;
+</xsl:text>
+    <xsl:text>        this.shift = false;
+</xsl:text>
+    <xsl:text>        this.caps = false;
+</xsl:text>
+    <xsl:text>        this.update();
+</xsl:text>
+    <xsl:text>    },
+</xsl:text>
+    <xsl:text>    update: function() {
+</xsl:text>
+    <xsl:text>        /* TODO Swith shift and capslock active/inactive elements */
+</xsl:text>
+    <xsl:text>        this.Value_elt.textContent = this.editstr;
+</xsl:text>
     <xsl:text>    },
 </xsl:text>
   </xsl:template>
@@ -2367,6 +2530,8 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>var xmlns = "http://www.w3.org/2000/svg";
+</xsl:text>
     <xsl:text>var edit_callback;
 </xsl:text>
     <xsl:text>function edit_value(path, valuetype, callback, initial) {
@@ -2379,16 +2544,32 @@
 </xsl:text>
     <xsl:text>    edit_callback = callback;
 </xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    let [element, parent] = detachable_elements[keypadid];
-</xsl:text>
-    <xsl:text>    tmpgrp = document.createElement("g");
+    <xsl:text>    let widget = hmi_widgets[keypadid];
+</xsl:text>
+    <xsl:text>    widget.start_edit(path, valuetype, callback, initial);
+</xsl:text>
+    <xsl:text>};
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>var current_modal; /* TODO stack ?*/
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>function show_modal() {
+</xsl:text>
+    <xsl:text>    let [element, parent] = detachable_elements[this.element.id];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    tmpgrp = document.createElementNS(xmlns,"g");
 </xsl:text>
     <xsl:text>    tmpgrpattr = document.createAttribute("transform");
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>    let [xcoord,ycoord] = this.coordinates;
+</xsl:text>
     <xsl:text>    let [xdest,ydest] = page_desc[current_visible_page].bbox;
 </xsl:text>
     <xsl:text>    tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")";
@@ -2403,9 +2584,27 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>    current_modal = [this.element.id, tmpgrp];
+</xsl:text>
     <xsl:text>};
 </xsl:text>
     <xsl:text>
 </xsl:text>
+    <xsl:text>function end_modal() {
+</xsl:text>
+    <xsl:text>    let [eltid, tmpgrp] = current_modal;
+</xsl:text>
+    <xsl:text>    let [element, parent] = detachable_elements[this.element.id];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    parent.removeChild(tmpgrp);
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    current_modal = undefined;
+</xsl:text>
+    <xsl:text>};
+</xsl:text>
   </xsl:template>
 </xsl:stylesheet>
--- a/svghmi/svghmi.js	Fri Apr 03 09:52:57 2020 +0200
+++ b/svghmi/svghmi.js	Fri Apr 03 14:37:41 2020 +0200
@@ -474,11 +474,19 @@
     let [keypadid, xcoord, ycoord] = keypads[valuetype];
     console.log('XXX TODO : Edit value', path, valuetype, callback, initial, keypadid);
     edit_callback = callback;
-
-    let [element, parent] = detachable_elements[keypadid];
+    let widget = hmi_widgets[keypadid];
+    widget.start_edit(path, valuetype, callback, initial);
+};
+
+var current_modal; /* TODO stack ?*/
+
+function show_modal() {
+    let [element, parent] = detachable_elements[this.element.id];
+
     tmpgrp = document.createElementNS(xmlns,"g");
     tmpgrpattr = document.createAttribute("transform");
 
+    let [xcoord,ycoord] = this.coordinates;
     let [xdest,ydest] = page_desc[current_visible_page].bbox;
     tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")";
     tmpgrp.setAttributeNode(tmpgrpattr);
@@ -486,5 +494,14 @@
     tmpgrp.appendChild(element);
     parent.appendChild(tmpgrp);
 
-};
-
+    current_modal = [this.element.id, tmpgrp];
+};
+
+function end_modal() {
+    let [eltid, tmpgrp] = current_modal;
+    let [element, parent] = detachable_elements[this.element.id];
+
+    parent.removeChild(tmpgrp);
+
+    current_modal = undefined;
+};
--- a/svghmi/widget_input.ysl2	Fri Apr 03 09:52:57 2020 +0200
+++ b/svghmi/widget_input.ysl2	Fri Apr 03 14:37:41 2020 +0200
@@ -33,11 +33,11 @@
         }
     |     },
     |     on_edit_click: function(opstr) {
-    |         edit_value("«path/@value»", "«path/@type»", this.edit_callback, this.last_val);
+    |         edit_value("«path/@value»", "«path/@type»", this, this.last_val);
     |     },
 
     |     edit_callback: function(new_val) {
-    |         apply_hmi_value(this.indexes[0], opstr);
+    |         apply_hmi_value(this.indexes[0], new_val);
         if "$have_value"{
     |         this.value_elt.textContent = String(new_val);
               /* TODO gray out value until refreshed */
--- a/svghmi/widget_keypad.ysl2	Fri Apr 03 09:52:57 2020 +0200
+++ b/svghmi/widget_keypad.ysl2	Fri Apr 03 14:37:41 2020 +0200
@@ -1,6 +1,77 @@
 // widget_keypad.ysl2
 
 template "widget[@type='Keypad']", mode="widget_defs" {
+    param "hmi_element";
+    labels("Esc Enter BackSpace Keys Info Value");
+    optional_labels("Sign CapsLock Shift Space");
     |     init: function() {
+    foreach "$hmi_element/*[@inkscape:label = 'Keys']/*" {
+    |         id("«@id»").setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_key_click('«func:escape_quotes(@inkscape:label)»')");
+    }
+    foreach "str:split('Esc Enter BackSpace Sign Space CapsLock Shift')" {
+    |         if(this.«.»_elt)
+    |             this.«.»_elt.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_«.»_click()");
+    }
+    |     },
+    |     on_key_click: function(symbols) {
+    |         var syms = symbols.split(" ");
+    |         this.shift = this.caps;
+    |         this.editstr += syms[this.shift?syms.length:0];
+    |         this.shift = false;
+    |         this.update();
+    |         console.log(symbols);
+    |     },
+    |     on_Esc_click: function() {
+    |         end_modal.call(this);
+    |         console.log("Esc");
+    |     },
+    |     on_Enter_click: function() {
+    |         end_modal.call(this);
+    |         callback_obj = this.result_callback_obj;
+    |         callback_obj.edit_callback(this.editstr);
+    |         console.log("Enter");
+    |     },
+    |     on_BackSpace_click: function() {
+    |         this.editstr = this.editstr.slice(0,this.editstr.length-1);
+    |         this.update();
+    |         console.log("BackSpace");
+    |     },
+    |     on_Sign_click: function() {
+    |         if(this.editstr[0] == "-")
+    |             this.editstr = this.editstr.slice(1,this.editstr.length);
+    |         else
+    |             this.editstr = "-" + this.editstr;
+    |         console.log("Sign");
+    |     },
+    |     on_Space_click: function() {
+    |         this.editstr += " ";
+    |         console.log("Space");
+    |     },
+    |     caps: false,
+    |     on_CapsLock_click: function() {
+    |         this.caps = !this.caps;
+    |         console.log("CapsLock");
+    |     },
+    |     shift: false,
+    |     on_Shift_click: function() {
+    |         this.shift = true;
+    |         console.log("Shift");
+    |     },
+    const "g", "$geometry[@Id = $hmi_element/@id]"; 
+    |     coordinates: [«$g/@x», «$g/@y»],
+    |     editstr: "",
+    |     result_callback_obj: undefined,
+    |     start_edit: function(info, valuetype, callback_obj, initial) {
+    |         show_modal.call(this);
+    |         this.editstr = initial;
+    |         this.result_callback_obj = callback_obj;
+    |         this.Info_elt.textContent = info;
+    |         this.shift = false;
+    |         this.caps = false;
+    |         this.update();
+    |     },
+    |     update: function() {
+    |         /* TODO Swith shift and capslock active/inactive elements */
+    |         this.Value_elt.textContent = this.editstr;
     |     },
 }
--- a/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Fri Apr 03 09:52:57 2020 +0200
+++ b/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Fri Apr 03 14:37:41 2020 +0200
@@ -124,17 +124,17 @@
      inkscape:pageopacity="0"
      inkscape:pageshadow="2"
      inkscape:document-units="px"
-     inkscape:current-layer="hmi0"
+     inkscape:current-layer="g2432"
      showgrid="false"
      units="px"
      inkscape:zoom="0.35355339"
-     inkscape:cx="-314.31196"
-     inkscape:cy="282.25622"
-     inkscape:window-width="1600"
-     inkscape:window-height="886"
+     inkscape:cx="-418.67433"
+     inkscape:cy="-1206.7258"
+     inkscape:window-width="1800"
+     inkscape:window-height="836"
      inkscape:window-x="0"
      inkscape:window-y="27"
-     inkscape:window-maximized="0"
+     inkscape:window-maximized="1"
      showguides="true"
      inkscape:guide-bbox="true" />
   <rect
@@ -1323,7 +1323,7 @@
        inkscape:label="Background"
        inkscape:connector-curvature="0"
        id="path2136"
-       d="M 54.211084,1.2654702 H 435.7388 V 230.18209 H 54.211084 Z"
+       d="M 54.211099,1.2654702 H 435.73881 V 230.18209 H 54.211099 Z"
        style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.16776976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
     <rect
        ry="3.8152773"
@@ -1595,6 +1595,19 @@
          style="font-weight:normal;font-size:9.28803921px;font-family:Arial;fill:#2b2828;stroke-width:0.10514989"
          transform="scale(1.0007154,0.99928514)">+/-</text>
     </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.31375408px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.30784383px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="252.9579"
+       y="12.333653"
+       id="text509"
+       transform="scale(0.96824589,1.0327955)"
+       inkscape:label="Info"><tspan
+         sodipodi:role="line"
+         id="tspan507"
+         x="252.9579"
+         y="12.333653"
+         style="stroke-width:0.30784383px">information</tspan></text>
   </g>
   <g
      transform="matrix(3.3549332,0,0,3.14525,-181.87457,1556.0198)"
@@ -2275,46 +2288,6 @@
       </g>
     </g>
     <g
-       id="g908"
-       inkscape:label="Shift">
-      <g
-         id="g914"
-         inkscape:label="inactive"
-         style="display:inline;stroke-width:0.47631353"
-         transform="translate(0,-9.5381931)">
-        <path
-           inkscape:connector-curvature="0"
-           d="m 379.96247,195 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 42.96244 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
-           id="path910"
-           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-           sodipodi:nodetypes="sssssssss" />
-        <text
-           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
-           id="text912"
-           y="187.4456"
-           x="392.55679"
-           transform="scale(1.0007154,0.99928514)">Shift</text>
-      </g>
-      <g
-         transform="translate(0,-9.5381931)"
-         style="stroke-width:0.47631353"
-         inkscape:label="active"
-         id="g3592">
-        <path
-           sodipodi:nodetypes="sssssssss"
-           style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
-           id="path551"
-           d="m 379.96247,195 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 42.96244 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
-           inkscape:connector-curvature="0" />
-        <text
-           transform="scale(1.0007154,0.99928514)"
-           x="392.55679"
-           y="187.4456"
-           id="text629"
-           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#ffffff;stroke-width:0.36866826">Shift</text>
-      </g>
-    </g>
-    <g
        transform="translate(335.89988,-58.934803)"
        id="g3544"
        inkscape:label="Esc"
@@ -2333,7 +2306,7 @@
          x="59.288635">Esc</text>
     </g>
     <g
-       inkscape:label="Return"
+       inkscape:label="Enter"
        id="g4291"
        style="stroke-width:0.47631353"
        transform="translate(0,-19.076386)">
@@ -2443,44 +2416,77 @@
          y="38.296417"
          style="text-align:start;text-anchor:start;stroke-width:0.47690967px">text</tspan></text>
     <g
-       id="g868"
+       id="g437"
        inkscape:label="Shift">
       <g
-         inkscape:label="inactive"
-         id="g862"
-         style="display:inline;fill-rule:evenodd;stroke-width:0.47631353"
-         transform="translate(0,-9.5381931)">
+         id="g421"
+         inkscape:label="inactive">
+        <path
+           inkscape:connector-curvature="0"
+           d="m 379.96247,185.46181 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 42.96244 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
+           id="path910"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           sodipodi:nodetypes="sssssssss" />
+        <text
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
+           id="text912"
+           y="177.90059"
+           x="392.55679"
+           transform="scale(1.0007154,0.99928513)">Shift</text>
         <path
            sodipodi:nodetypes="sssssssss"
-           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           style="opacity:1;vector-effect:none;fill:#d3d2d2;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.16824308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
            id="path856"
-           d="m 67.025031,195 c -1,0 -3,-1 -3,-3 v -17 c 0,-1 2,-3 3,-3 H 104 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 z"
+           d="m 67.025031,185.46181 c -1,0 -3,-1 -3,-3 v -17 c 0,-1 2,-3 3,-3 H 104 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 z"
            inkscape:connector-curvature="0" />
         <text
            x="75.85218"
-           y="187.4456"
+           y="177.90059"
            id="text858"
-           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#2b2828;stroke-width:0.36866826"
-           transform="scale(1.0007154,0.99928514)">Shift</text>
-      </g>
-      <g
-         transform="translate(0,-9.5381931)"
-         style="display:inline;fill-rule:evenodd;stroke-width:0.47631353"
-         id="g883"
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#2b2828;fill-rule:evenodd;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928513)">Shift</text>
+      </g>
+      <g
+         id="g413"
          inkscape:label="active">
         <path
-           inkscape:connector-curvature="0"
-           d="m 67.025031,195 c -1,0 -3,-1 -3,-3 v -17 c 0,-1 2,-3 3,-3 H 104 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 z"
+           sodipodi:nodetypes="sssssssss"
+           style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           id="path551"
+           d="m 379.96247,185.46181 c -1,0 -2,-1 -2,-3 v -17 c 0,-1 1,-3 2,-3 h 42.96244 c 2,0 3,2 3,3 v 17 c 0,2 -1,3 -3,3 z"
+           inkscape:connector-curvature="0" />
+        <text
+           transform="scale(1.0007154,0.99928513)"
+           x="392.55679"
+           y="177.90059"
+           id="text629"
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#ffffff;stroke-width:0.36866826">Shift</text>
+        <path
+           inkscape:connector-curvature="0"
+           d="m 67.025031,185.46181 c -1,0 -3,-1 -3,-3 v -17 c 0,-1 2,-3 3,-3 H 104 c 1,0 2,2 2,3 v 17 c 0,2 -1,3 -2,3 z"
            id="path879"
-           style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+           style="opacity:1;vector-effect:none;fill:#4f4c4d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.16824313;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
            sodipodi:nodetypes="sssssssss" />
         <text
-           transform="scale(1.0007154,0.99928514)"
-           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#ffffff;stroke-width:0.36866826"
+           transform="scale(1.0007154,0.99928513)"
+           style="font-weight:normal;font-size:8.92098808px;font-family:Arial;fill:#ffffff;fill-rule:evenodd;stroke-width:0.36866826"
            id="text881"
-           y="187.4456"
+           y="177.90059"
            x="75.85218">Shift</text>
       </g>
     </g>
+    <text
+       transform="scale(0.96824588,1.0327955)"
+       id="text471"
+       y="12.333657"
+       x="252.9579"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.31375408px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.30784383px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       inkscape:label="Info"><tspan
+         style="stroke-width:0.30784383px"
+         y="12.333657"
+         x="252.9579"
+         id="tspan469"
+         sodipodi:role="line">information</tspan></text>
   </g>
 </svg>