Revision: 4874
          http://sourceforge.net/p/vexi/code/4874
Author:   mkpg2
Date:     2016-07-16 00:05:55 +0000 (Sat, 16 Jul 2016)
Log Message:
-----------
Support international keyboards.
- Need to use key typed events and not key pressed.
- New core event KeyTyped.
- Make KeyTyped event primary source of characters in text widgets
- Still use KeyPressed for control characters (arrow keys, delete ... etc.)

Modified Paths:
--------------
    branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Constants.java
    branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Surface.java
    branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Swing.java
    
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusmanager.t
    branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/surface.t
    branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t
    branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/field.t
    
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/shadowtext.t
    branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textarea.t
    
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textfield.t
    branches/vexi3/org.vexi-vexi.widgets/src_poke/poke/widgets/textfield.t
    trunk/org.vexi-build.shared/meta/module.revisions

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Constants.java
===================================================================
--- 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Constants.java    
    2016-07-15 01:16:46 UTC (rev 4873)
+++ 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Constants.java    
    2016-07-16 00:05:55 UTC (rev 4874)
@@ -93,6 +93,7 @@
     static final JS SC_DoubleClick3 = JSU.S("DoubleClick3",true);
     static final JS SC_KeyPressed = JSU.S("KeyPressed",true);
     static final JS SC_KeyReleased = JSU.S("KeyReleased",true);
+    static final JS SC_KeyTyped = JSU.S("KeyTyped",true);
     static final JS SC__Enter = JSU.S("_Enter",true);
     static final JS SC__Leave = JSU.S("_Leave",true);
     static final JS SC__Move = JSU.S("_Move",true);
@@ -112,4 +113,5 @@
     static final JS SC__DoubleClick3 = JSU.S("_DoubleClick3",true);
     static final JS SC__KeyPressed = JSU.S("_KeyPressed",true);
     static final JS SC__KeyReleased = JSU.S("_KeyReleased",true);
+    static final JS SC__KeyTyped = JSU.S("_KeyTyped",true);    
 }
\ No newline at end of file

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Surface.java
===================================================================
--- branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Surface.java  
2016-07-15 01:16:46 UTC (rev 4873)
+++ branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Surface.java  
2016-07-16 00:05:55 UTC (rev 4874)
@@ -204,6 +204,11 @@
     // Event Handling Helper methods for subclasses 
///////////////////////////////////////////
     
     private boolean keypress_scheduled = false;
+    
+    protected final void KeyTyped(String key) {
+        message(SC_KeyTyped, SC__KeyTyped, JSU.S(key), true);
+    }
+    
     protected final void KeyPressed(String key) {
         // check that we've not already got a keypress active
         // otherwise the application may 'queue up' keypresses
@@ -448,9 +453,14 @@
                 return o;
             }
             
-            if (event==SC_KeyPressed) {
+            if (event==SC_KeyTyped) {
                 // set up appropriate combination key values
                 String value = JSU.toString(this.value);
+                this.value = JSU.S(value);
+                
+            }else if (event==SC_KeyPressed) {
+                // set up appropriate combination key values
+                String value = JSU.toString(this.value);
                 if (shift && !value.equals("shift")) {
                     value = value.toUpperCase();
                 }

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Swing.java
===================================================================
--- branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Swing.java    
2016-07-15 01:16:46 UTC (rev 4873)
+++ branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Swing.java    
2016-07-16 00:05:55 UTC (rev 4874)
@@ -654,26 +654,25 @@
         public void componentResized(int newwidth, int newheight) { 
SizeChange(newwidth, newheight); }
         
         private void checkEvent(InputEvent e) {
+               // HACK this isn't right. These should be passed with the value
+               // (because they are set here, but then the event is scheduled 
+               // and these values can change before it is run)
             alt = e.isAltDown();
             control = e.isControlDown();
             shift = e.isShiftDown();
         }
 
         public void keyTyped(KeyEvent k) {
-            checkEvent(k);
-            // REMARK - we are a so called 'passive Input Method' client.
-            // We receive composed text (e.g. Asian characters) as key events
-            // where we want to convert them into a KeyPressed/KeyReleased
-            // Vexi event. Unfortunately we need a way to distinguish between 
-            // events due to inputMethods (which we want) and those from the
-            // keyboard which are already handled via keyPressed/keyReleased.
-            // HACK - simplest is to just except non-ascii chars.
-            int unicode = (int)k.getKeyChar();
-            if (255 >= unicode) {
-                return;
+               // These return odd characters we don't want to pass to the 
traps.
+               // Are we losing anything doing it this way?
+               switch (k.getKeyChar()) {
+               case KeyEvent.VK_TAB: return;
+            case KeyEvent.VK_ENTER: return;
+            case KeyEvent.VK_BACK_SPACE: return;
+            case KeyEvent.VK_DELETE: return;
             }
-            KeyPressed(""+k.getKeyChar());
-            KeyReleased(""+k.getKeyChar());
+               
+            KeyTyped(""+k.getKeyChar());
         }
 
 
@@ -744,18 +743,18 @@
             // VK_ entries not defined for Java 1.4
             case 524: return "windows_key";
             case 525: return "context_menu";
-            // usually only single / known characters
+               // usually only single / known characters
             default:
-                char c = k.getKeyChar();
-                if (c >= 1 && c <= 26) {
-                    c = (char)('a' + c - 1);
-                }
-                // WORKAROUND shift+ctrl+6 (i.e. C-^) returning empty character
-                if (k.getKeyCode() == 54 && k.isControlDown() && 
k.isShiftDown()) {
-                    c = '^';
-                }
-                //System.out.println(c+": "+k.getKeyCode());
-                return String.valueOf(c);
+                   char c = k.getKeyChar();
+                   if (c >= 1 && c <= 26) {
+                       c = (char)('a' + c - 1);
+                   }
+                   // WORKAROUND shift+ctrl+6 (i.e. C-^) returning empty 
character
+                   if (k.getKeyCode() == 54 && k.isControlDown() && 
k.isShiftDown()) {
+                       c = '^';
+                   }
+                   //System.out.println(c+": "+k.getKeyCode());
+                   return String.valueOf(c);
             }
         }
     }

Modified: 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusmanager.t
===================================================================
--- 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusmanager.t  
    2016-07-15 01:16:46 UTC (rev 4873)
+++ 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/focusmanager.t  
    2016-07-16 00:05:55 UTC (rev 4874)
@@ -191,24 +191,36 @@
         }
         
         //////// Key Event Handling ///////////////////////////////////
+
+        /** pass key-type events to focused child */
+        const surfaceKeyTyped = function(v) {
+            model.focusModelKeyTyped(v);
+            return;
+        };
         
+        surface.event._KeyTyped ++= surfaceKeyTyped;
+        
         /** pass key-press events to focused child */
-        var surfaceKeyPress = function(v) {
+        const surfaceKeyPress = function(v) {
             model.focusModelKeyPressed(v);
             return;
-        }
+        };
         
         surface.event._KeyPressed ++= surfaceKeyPress;
         
         /** pass key-release events to focused child */
-        var surfaceKeyRelease = function(v) {
+        const surfaceKeyRelease = function(v) {
             model.focusModelKeyReleased(v);
             return;
-        }
+        };
         
         surface.event._KeyReleased ++= surfaceKeyRelease;
         
         /** focus model keypress event */
+        model.focusModelKeyTyped = function(v) {       
+               focus.KeyTyped = v;
+        };    
+        
         model.focusModelKeyPressed = function(v) {
             if (focus and focus.grabKeyList and focus.grabKeyList[v]) {
                 // the focused widget wishes to intercept special keys
@@ -236,7 +248,7 @@
                 // pass keypress onto focused widget
                 focus.KeyPressed = v;
             }
-        }
+        };
 
         /** focus model keyrelease event */
         model.focusModelKeyReleased = function(v) {
@@ -244,7 +256,7 @@
                     or v!="tab" or v!="TAB" or v.charCodeAt(0)!=65535)) {
                 focus.KeyReleased = v;
             }
-        }
+        };
 
     </ui:box>
 </vexi>

Modified: 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/surface.t
===================================================================
--- branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/surface.t   
2016-07-15 01:16:46 UTC (rev 4873)
+++ branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/role/surface.t   
2016-07-16 00:05:55 UTC (rev 4874)
@@ -67,7 +67,7 @@
             "_Release1", "_Release2", "_Release3" );
         
         /** special case key events for focusable integration */
-        .util.redirect..addRedirect(thisbox, event, "_KeyPressed", 
"_KeyReleased" );
+        .util.redirect..addRedirect(thisbox, event, "_KeyPressed", 
"_KeyReleased", "_KeyTyped" );
         
         /** redirect frame properties for access */
         .util.redirect..addRedirect(frame, thisbox,

Modified: branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t
===================================================================
--- branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t      
2016-07-15 01:16:46 UTC (rev 4873)
+++ branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/edit.t      
2016-07-16 00:05:55 UTC (rev 4874)
@@ -929,261 +929,344 @@
         //thisbox.syncCursor = function() { return true; }
         
         /** handles keyboard editing - cursor movement, character insertion 
and deletion */
-        KeyPressed ++= function(v) {
-            cascade = v;
-            
+        KeyTyped ++= function(v) {
+               cascade = v;
+               
             // key input invalidates textstore
             textstore = null;
             
             // the index of cWord in cBlock
             cwInd = cWord ? cBlock.indexof(cWord) : null;
+               
+            // special case select mode
+            if (select) deleteSelectedText();
             
-            // character insertion
-            if (v.length == 1) {
-                // special case select mode
-                if (select) deleteSelectedText();
-                
-                var type = .block..getCharType(v);
-                if (insert) {
-                    if (cWord) {
-                        // this is a box of the same character type
-                        if (type == cWord.chartype) {
-                            if (cPos == 0) {
-                                cWord.text = v + cWord.text;
-                            } else if (cPos == cWord.text.length) {
-                                cWord.text += v;
-                            } else {
-                                var str1 = cWord.text.substring(0, cPos);
-                                var str2 = cWord.text.substring(cPos, 
cWord.text.length);
-                                cWord.text = str1 + v + str2;
-                            }
-                            cPos++;
+            var type = .block..getCharType(v);
+            if (insert) {
+                if (cWord) {
+                    // this is a box of the same character type
+                    if (type == cWord.chartype) {
+                        if (cPos == 0) {
+                            cWord.text = v + cWord.text;
+                        } else if (cPos == cWord.text.length) {
+                            cWord.text += v;
+                        } else {
+                            var str1 = cWord.text.substring(0, cPos);
+                            var str2 = cWord.text.substring(cPos, 
cWord.text.length);
+                            cWord.text = str1 + v + str2;
+                        }
+                        cPos++;
+                    
+                    } else if (cPos == 0 and cwInd != 0 and type == 
cBlock[cwInd-1].chartype) {
+                        // cursor is at the start of a word which follows a 
set of spaces
+                        cBlock[cwInd-1].text += v;
+                    
+                    } else {
+                        // need to insert new word
+                        var w = .word(vexi.box, cBlock.wordargs);
+                        w.text = v;
+                        w.chartype = type;
                         
-                        } else if (cPos == 0 and cwInd != 0 and type == 
cBlock[cwInd-1].chartype) {
-                            // cursor is at the start of a word which follows 
a set of spaces
-                            cBlock[cwInd-1].text += v;
+                        if (cPos == 0) {
+                            // place before current word
+                            cBlock[cwInd] = w;
                         
+                        } else if (cPos == cWord.text.length) {
+                            // place after current word
+                            cBlock[cBlock.numchildren] = w;
+                            cPos = 1;
+                            cWord = w;
+                        
                         } else {
-                            // need to insert new word
-                            var w = .word(vexi.box, cBlock.wordargs);
-                            w.text = v;
-                            w.chartype = type;
-                            
-                            if (cPos == 0) {
-                                // place before current word
-                                cBlock[cwInd] = w;
-                            
-                            } else if (cPos == cWord.text.length) {
-                                // place after current word
-                                cBlock[cBlock.numchildren] = w;
-                                cPos = 1;
-                                cWord = w;
-                            
-                            } else {
-                                // need to split current word
-                                var w2 = .word(vexi.box, cBlock.wordargs);
-                                w2.text = cWord.text.slice(cPos);
-                                cWord.text = cWord.text.slice(0, cPos);
-                                cBlock[cwInd+1] = w;
-                                cBlock[cwInd+2] = w2;
-                                cPos = 0;
-                                cWord = w2;
-                            }
+                            // need to split current word
+                            var w2 = .word(vexi.box, cBlock.wordargs);
+                            w2.text = cWord.text.slice(cPos);
+                            cWord.text = cWord.text.slice(0, cPos);
+                            cBlock[cwInd+1] = w;
+                            cBlock[cwInd+2] = w2;
+                            cPos = 0;
+                            cWord = w2;
                         }
-                    
-                    } else {
-                        // no word in this block - create one
-                        cBlock[0] = .word(vexi.box, cBlock.wordargs);
-                        cBlock[0].text = v;
-                        cBlock[0].chartype = type;
-                        cPos = 1;
-                        cWord = cBlock[0];
                     }
                 
                 } else {
-                    // insert == false
-                    
-                    // delete next character and insert new char
-                    KeyPressed = "delete";
-                    insert = true;
-                    KeyPressed = v;
-                    insert = false;
+                    // no word in this block - create one
+                    cBlock[0] = .word(vexi.box, cBlock.wordargs);
+                    cBlock[0].text = v;
+                    cBlock[0].chartype = type;
+                    cPos = 1;
+                    cWord = cBlock[0];
                 }
             
             } else {
-                // actions
+                // insert == false
                 
-                // the index of cBlock in thisbox
-                cbInd = thisbox.indexof(cBlock);
+                // delete next character and insert new char
+                KeyPressed = "delete";
+                insert = true;
+                KeyTyped = v;
+                insert = false;
+            }
+            cBlock.reflowbox = true;
+            syncCursorAndOffset(false);
+            return true;
+        };
+        
+        
+        KeyPressed ++= function(v) {
+            cascade = v;
+            
+            if (v.length == 1) return;
+            
+            // key input invalidates textstore
+            textstore = null;
+            
+            // the index of cWord in cBlock
+            cwInd = cWord ? cBlock.indexof(cWord) : null;
+            
+            // actions
+            
+            // the index of cBlock in thisbox
+            cbInd = thisbox.indexof(cBlock);
+            
+            switch(v) {
+            // select all
+            case "C-a":
+            case "C-A":
+                selectAll();
+                break;
+            
+            // unselect all
+            case "escape":
+                unselectAll();
+                break;
+            
+            // copy
+            case "C-c":
+            case "C-C":
+                copy();
+                break;
                 
-                switch(v) {
-                // select all
-                case "C-a":
-                case "C-A":
-                    selectAll();
-                    break;
+            // cut
+            case "C-x":
+            case "C-X":
+                cut();
+                break;
                 
-                // unselect all
-                case "escape":
-                    unselectAll();
-                    break;
+            // paste
+            case "C-v":
+            case "C-V":
+                paste();
+                break;
+            
+            // add circumflex (caret) accent
+            case "C-^":
+                checkAndApplyCaret(cbInd, cwInd, cPos);
+                break;
                 
-                // copy
-                case "C-c":
-                case "C-C":
-                    copy();
-                    break;
-                    
-                // cut
-                case "C-x":
-                case "C-X":
-                    cut();
-                    break;
-                    
-                // paste
-                case "C-v":
-                case "C-V":
-                    paste();
-                    break;
+            // move cursor right
+            case "right":
+            case "C-right":
+                if (unselectRight()) return;
+            case "RIGHT":
+            case "C-RIGHT":
+                if (vexi.ui.key.control) {
+                    // control key held down - shift to end of next word
+                    if (cWord and cWord.text.length>cPos) {
+                        // force skipping to end of cWord if cursor is mid-word
+                        cwInd--;
+                    }
+                    OUT:while (thisbox[cbInd]) {
+                        while (thisbox[cbInd][++cwInd]) {
+                            if (1>=thisbox[cbInd][cwInd].chartype) {
+                                continue;
+                            }
+                            break OUT;
+                        }
+                        cbInd++;
+                        cwInd = thisbox.numchildren>cbInd ? -1 : 
thisbox[cbInd-1].numchildren-1;
+                    }
+                    aBlock = thisbox.numchildren>cbInd ? thisbox[cbInd] : 
thisbox[thisbox.numchildren-1];
+                    if (aBlock.numchildren-1 > cwInd) {
+                        aWord = aBlock[cwInd+1];
+                        aPos = 0;
+                    } else {
+                        aWord = aBlock[cwInd];
+                        aPos = aWord.text.length;
+                    }
                 
-                // add circumflex (caret) accent
-                case "C-^":
-                    checkAndApplyCaret(cbInd, cwInd, cPos);
-                    break;
+                } else {
+                    // normal case
+                    aBlock = cBlock;
+                    aWord = cWord;
+                    aPos = cPos;
                     
-                // move cursor right
-                case "right":
-                case "C-right":
-                    if (unselectRight()) return;
-                case "RIGHT":
-                case "C-RIGHT":
-                    if (vexi.ui.key.control) {
-                        // control key held down - shift to end of next word
-                        if (cWord and cWord.text.length>cPos) {
-                            // force skipping to end of cWord if cursor is 
mid-word
-                            cwInd--;
-                        }
-                        OUT:while (thisbox[cbInd]) {
-                            while (thisbox[cbInd][++cwInd]) {
-                                if (1>=thisbox[cbInd][cwInd].chartype) {
-                                    continue;
-                                }
-                                break OUT;
+                    if (aWord and ++aPos >= aWord.text.length) {
+                        // shift cursor forwards and check whether the 
position is legal
+                        if (aWord.text.length >= aPos) {
+                            if (cwInd != aBlock.numchildren-1) {
+                                aPos = 0;
+                                aWord = aBlock[cwInd+1];
                             }
-                            cbInd++;
-                            cwInd = thisbox.numchildren>cbInd ? -1 : 
thisbox[cbInd-1].numchildren-1;
+                        } else if (thisbox.numchildren-1 > cbInd) {
+                            aWord = null;
+                        } else {
+                            aPos--;
                         }
-                        aBlock = thisbox.numchildren>cbInd ? thisbox[cbInd] : 
thisbox[thisbox.numchildren-1];
-                        if (aBlock.numchildren-1 > cwInd) {
-                            aWord = aBlock[cwInd+1];
+                    }
+                    
+                    if (!aWord) {
+                        // find the next available legal position
+                        if (thisbox.indexof(aBlock) != thisbox.numchildren-1) {
+                            aBlock = thisbox[thisbox.indexof(aBlock)+1];
                             aPos = 0;
+                            aWord = aBlock.numchildren ? aBlock[0] : null;
                         } else {
-                            aWord = aBlock[cwInd];
-                            aPos = aWord.text.length;
+                            return;
                         }
+                    }
+                }
+                // invoke selection or set cursor position
+                if (vexi.ui.key.shift) {
+                    selectWords();
+                } else {
+                    cBlock = aBlock;
+                    cWord = aWord;
+                    cPos = aPos;
+                }
+                break;
+                
+            // move cursor left
+            case "left":
+            case "C-left":
+                if (unselectLeft()) {
+                    return;
+                }
+            case "LEFT":
+            case "C-LEFT":
+                if (vexi.ui.key.control) {
+                    // control key held down - shift to start of previous word
+                    if (cWord and cPos>0) {
+                        // force skipping to start of cWord if cursor is 
mid-word
+                        cwInd++;
+                    }
+                    OUT:while (thisbox[cbInd]) {
+                        while (thisbox[cbInd][--cwInd]) {
+                            if (1>=thisbox[cbInd][cwInd].chartype) {
+                                continue;
+                            }
+                            break OUT;
+                        }
+                        cbInd--;
+                        cwInd = (cbInd>=0) ? thisbox[cbInd].numchildren : 0;
+                    }
+                    if (0>cbInd) {
+                        // already at start of text
+                        return;
+                    }
+                    aBlock = thisbox[cbInd];
+                    aWord = aBlock[cwInd];
+                    aPos = 0;
+                } else {
+                    aBlock = cBlock;
+                    aWord = cWord;
+                    aPos = cPos;
                     
-                    } else {
-                        // normal case
-                        aBlock = cBlock;
-                        aWord = cWord;
-                        aPos = cPos;
-                        
-                        if (aWord and ++aPos >= aWord.text.length) {
-                            // shift cursor forwards and check whether the 
position is legal
-                            if (aWord.text.length >= aPos) {
-                                if (cwInd != aBlock.numchildren-1) {
-                                    aPos = 0;
-                                    aWord = aBlock[cwInd+1];
-                                }
-                            } else if (thisbox.numchildren-1 > cbInd) {
-                                aWord = null;
+                    if (0 > --aPos) {
+                        // shift the cursor backwards and check whether the 
position is legal
+                        if (!aWord or cwInd == 0) {
+                            // nowhere to go with current block, try next block
+                            if (cbInd > 0) {
+                                aBlock = thisbox[cbInd-1];
+                                aWord = aBlock.numchildren ? 
aBlock[aBlock.numchildren-1] : null;
+                                aPos = aWord ? aWord.text.length : 0;
                             } else {
-                                aPos--;
+                                return;
                             }
-                        }
                         
-                        if (!aWord) {
-                            // find the next available legal position
-                            if (thisbox.indexof(aBlock) != 
thisbox.numchildren-1) {
-                                aBlock = thisbox[thisbox.indexof(aBlock)+1];
-                                aPos = 0;
-                                aWord = aBlock.numchildren ? aBlock[0] : null;
+                        } else if (aWord) {
+                            // get prior word
+                            if (cwInd>0) {
+                                aWord = aBlock[cwInd-1];
+                                aPos = aWord.text.length-1;
+                            } else if (cbInd>0) {
+                                aBlock = thisbox[cbInd-1];
+                                aWord = aBlock.numchildren ? 
aBlock[aBlock.numchildren-1] : null;
+                                aPos = aWord ? aWord.text.length : 0;
                             } else {
                                 return;
                             }
                         }
                     }
-                    // invoke selection or set cursor position
-                    if (vexi.ui.key.shift) {
-                        selectWords();
-                    } else {
-                        cBlock = aBlock;
-                        cWord = aWord;
-                        cPos = aPos;
-                    }
-                    break;
-                    
-                // move cursor left
-                case "left":
-                case "C-left":
-                    if (unselectLeft()) {
-                        return;
-                    }
-                case "LEFT":
-                case "C-LEFT":
+                }
+                // invoke selection or set cursor position
+                if (vexi.ui.key.shift) {
+                    selectWords();
+                } else {
+                    cBlock = aBlock;
+                    cWord = aWord;
+                    cPos = aPos;
+                }
+                break;
+                
+            // move cursor up
+            case "up":
+            case "C-up":
+                if (unselectLeft()) {
+                    return;
+                }
+            case "UP":
+            case "C-UP":
+                if (multiline) {
                     if (vexi.ui.key.control) {
-                        // control key held down - shift to start of previous 
word
-                        if (cWord and cPos>0) {
-                            // force skipping to start of cWord if cursor is 
mid-word
-                            cwInd++;
-                        }
-                        OUT:while (thisbox[cbInd]) {
-                            while (thisbox[cbInd][--cwInd]) {
-                                if (1>=thisbox[cbInd][cwInd].chartype) {
-                                    continue;
-                                }
-                                break OUT;
-                            }
+                        // control key held down - shift to start of previous 
block
+                        if (!cWord or (cwInd == 0 and cPos == 0)) {
                             cbInd--;
-                            cwInd = (cbInd>=0) ? thisbox[cbInd].numchildren : 
0;
                         }
-                        if (0>cbInd) {
-                            // already at start of text
-                            return;
+                        if (0 > cbInd) {
+                            cbInd = 0;
                         }
                         aBlock = thisbox[cbInd];
-                        aWord = aBlock[cwInd];
+                        aWord = aBlock[0];
                         aPos = 0;
-                    } else {
+                    
+                    } else if (cWord and cBlock.multiline and cWord.y > 0) {
+                        // search for next line within cBlock
+                        var i = cwInd-1;
+                        // pass through words on the same line
+                        while (i>0 and cBlock[i].y == cWord.y) {
+                            i--;
+                        }
+                        var ly = cBlock[i].y;
+                        // pass through words on the previous line until we 
reach the word in question or the start of the line
+                        while (i>0 and cBlock[i].y == ly and cBlock[i].x > 
cOffset) {
+                            i--;
+                        }
+                        if (cBlock[i].y != ly) {
+                            i++;
+                        }
                         aBlock = cBlock;
-                        aWord = cWord;
-                        aPos = cPos;
+                        aWord = cBlock[i];
+                        aPos = (cOffset > aWord.x+aWord.width) ? 
aWord.text.length : static.getIndInWord(aWord, cOffset-aWord.x);
+                    
+                    } else if (cbInd > 0) {
+                        // next line upwards is in previous block
+                        if (thisbox[cbInd-1].numchildren) {
+                            var nblock = thisbox[cbInd-1];
+                            var i = nblock.numchildren-1;
+                            var ly = nblock[i].y;
+                            while (i>0 and nblock[i-1].y == ly and nblock[i].x 
> cOffset) {
+                                i--;
+                            }
+                            aBlock = nblock;
+                            aWord = i>=0 ? nblock[i] : nblock[0];
+                            aPos = cOffset ? static.getIndInWord(aWord, 
cOffset-aWord.x) : 0;
                         
-                        if (0 > --aPos) {
-                            // shift the cursor backwards and check whether 
the position is legal
-                            if (!aWord or cwInd == 0) {
-                                // nowhere to go with current block, try next 
block
-                                if (cbInd > 0) {
-                                    aBlock = thisbox[cbInd-1];
-                                    aWord = aBlock.numchildren ? 
aBlock[aBlock.numchildren-1] : null;
-                                    aPos = aWord ? aWord.text.length : 0;
-                                } else {
-                                    return;
-                                }
-                            
-                            } else if (aWord) {
-                                // get prior word
-                                if (cwInd>0) {
-                                    aWord = aBlock[cwInd-1];
-                                    aPos = aWord.text.length-1;
-                                } else if (cbInd>0) {
-                                    aBlock = thisbox[cbInd-1];
-                                    aWord = aBlock.numchildren ? 
aBlock[aBlock.numchildren-1] : null;
-                                    aPos = aWord ? aWord.text.length : 0;
-                                } else {
-                                    return;
-                                }
-                            }
+                        } else {
+                            // no words in next block
+                            aBlock = thisbox[cbInd-1];
+                            aWord = null;
+                            aPos = 0;
                         }
                     }
                     // invoke selection or set cursor position
@@ -1194,182 +1277,76 @@
                         cWord = aWord;
                         cPos = aPos;
                     }
-                    break;
+                }
+                // invoke syncCursor directly
+                syncCursor();
+                return true;
+                
+            // move cursor down
+            case "down":
+            case "C-down":
+                if (unselectRight()) {
+                    return;
+                }
+            case "DOWN":
+            case "C-DOWN":
+                if (multiline) {
+                    if (vexi.ui.key.control) {
+                        // control key held down - shift to end of next block
+                        if (!cWord or (cBlock.numchildren-1 == cwInd and 
(cWord?cWord.text.length:0) == cPos)) {
+                            cbInd++;
+                        }
+                        if (cbInd >= thisbox.numchildren) {
+                            cbInd = thisbox.numchildren-1;
+                        }
+                        aBlock = thisbox[cbInd];
+                        aWord = aBlock[aBlock.numchildren-1];
+                        aPos = aWord?aWord.text.length:0;
                     
-                // move cursor up
-                case "up":
-                case "C-up":
-                    if (unselectLeft()) {
-                        return;
-                    }
-                case "UP":
-                case "C-UP":
-                    if (multiline) {
-                        if (vexi.ui.key.control) {
-                            // control key held down - shift to start of 
previous block
-                            if (!cWord or (cwInd == 0 and cPos == 0)) {
-                                cbInd--;
-                            }
-                            if (0 > cbInd) {
-                                cbInd = 0;
-                            }
-                            aBlock = thisbox[cbInd];
-                            aWord = aBlock[0];
+                    } else if (cWord and cBlock.multiline and cBlock.height > 
cWord.y+cWord.height) {
+                        // search for next line within cBlock
+                        var i = cwInd;
+                        // pass through words on the same line
+                        while (cBlock[i+1] and cBlock[i].y == cWord.y) {
+                            i++;
+                        }
+                        var ly = cBlock[i].y;
+                        // pass through words on the next line until we reach 
the word in question or the end of the line
+                        while (cBlock[i+1] and cBlock[i].y == ly and cOffset > 
cBlock[i].x+cBlock[i].width) {
+                            i++;
+                        }
+                        aBlock = cBlock;
+                        aWord = cBlock[i];
+                        aPos = (cOffset > aWord.x+aWord.width) ? 
aWord.text.length : static.getIndInWord(aWord, cOffset-aWord.x);
+                        if (cPos == aWord.text.length and 
aBlock.indexof(aWord) != aBlock.numchildren-1) {
+                            // increment cWord/cPos
+                            aWord = aBlock[aBlock.indexof(aWord)+1];
                             aPos = 0;
-                        
-                        } else if (cWord and cBlock.multiline and cWord.y > 0) 
{
-                            // search for next line within cBlock
-                            var i = cwInd-1;
-                            // pass through words on the same line
-                            while (i>0 and cBlock[i].y == cWord.y) {
-                                i--;
-                            }
-                            var ly = cBlock[i].y;
-                            // pass through words on the previous line until 
we reach the word in question or the start of the line
-                            while (i>0 and cBlock[i].y == ly and cBlock[i].x > 
cOffset) {
-                                i--;
-                            }
-                            if (cBlock[i].y != ly) {
-                                i++;
-                            }
-                            aBlock = cBlock;
-                            aWord = cBlock[i];
-                            aPos = (cOffset > aWord.x+aWord.width) ? 
aWord.text.length : static.getIndInWord(aWord, cOffset-aWord.x);
-                        
-                        } else if (cbInd > 0) {
-                            // next line upwards is in previous block
-                            if (thisbox[cbInd-1].numchildren) {
-                                var nblock = thisbox[cbInd-1];
-                                var i = nblock.numchildren-1;
-                                var ly = nblock[i].y;
-                                while (i>0 and nblock[i-1].y == ly and 
nblock[i].x > cOffset) {
-                                    i--;
-                                }
+                        }
+                    
+                    } else if (thisbox.numchildren-1 > cbInd) {
+                        // next line is in next block
+                        if (thisbox[cbInd+1].numchildren) {
+                            var nblock = thisbox[cbInd+1];
+                            var i = 0;
+                            while (nblock[i] and nblock[i].y == 0 and (cOffset 
> nblock[i].x+nblock[i].width)) i++;
+                            if (!nblock[i] or (cOffset > 
nblock[i].x+nblock[i].width)) {
                                 aBlock = nblock;
-                                aWord = i>=0 ? nblock[i] : nblock[0];
-                                aPos = cOffset ? static.getIndInWord(aWord, 
cOffset-aWord.x) : 0;
-                            
+                                aWord = aBlock[aBlock.numchildren-1];
+                                aPos = aWord.text.length;
                             } else {
-                                // no words in next block
-                                aBlock = thisbox[cbInd-1];
-                                aWord = null;
-                                aPos = 0;
+                                aBlock = nblock;
+                                aWord = nblock[i];
+                                aPos = static.getIndInWord(aWord, 
cOffset-aWord.x);
                             }
-                        }
-                        // invoke selection or set cursor position
-                        if (vexi.ui.key.shift) {
-                            selectWords();
-                        } else {
-                            cBlock = aBlock;
-                            cWord = aWord;
-                            cPos = aPos;
-                        }
-                    }
-                    // invoke syncCursor directly
-                    syncCursor();
-                    return true;
-                    
-                // move cursor down
-                case "down":
-                case "C-down":
-                    if (unselectRight()) {
-                        return;
-                    }
-                case "DOWN":
-                case "C-DOWN":
-                    if (multiline) {
-                        if (vexi.ui.key.control) {
-                            // control key held down - shift to end of next 
block
-                            if (!cWord or (cBlock.numchildren-1 == cwInd and 
(cWord?cWord.text.length:0) == cPos)) {
-                                cbInd++;
-                            }
-                            if (cbInd >= thisbox.numchildren) {
-                                cbInd = thisbox.numchildren-1;
-                            }
-                            aBlock = thisbox[cbInd];
-                            aWord = aBlock[aBlock.numchildren-1];
-                            aPos = aWord?aWord.text.length:0;
                         
-                        } else if (cWord and cBlock.multiline and 
cBlock.height > cWord.y+cWord.height) {
-                            // search for next line within cBlock
-                            var i = cwInd;
-                            // pass through words on the same line
-                            while (cBlock[i+1] and cBlock[i].y == cWord.y) {
-                                i++;
-                            }
-                            var ly = cBlock[i].y;
-                            // pass through words on the next line until we 
reach the word in question or the end of the line
-                            while (cBlock[i+1] and cBlock[i].y == ly and 
cOffset > cBlock[i].x+cBlock[i].width) {
-                                i++;
-                            }
-                            aBlock = cBlock;
-                            aWord = cBlock[i];
-                            aPos = (cOffset > aWord.x+aWord.width) ? 
aWord.text.length : static.getIndInWord(aWord, cOffset-aWord.x);
-                            if (cPos == aWord.text.length and 
aBlock.indexof(aWord) != aBlock.numchildren-1) {
-                                // increment cWord/cPos
-                                aWord = aBlock[aBlock.indexof(aWord)+1];
-                                aPos = 0;
-                            }
-                        
-                        } else if (thisbox.numchildren-1 > cbInd) {
-                            // next line is in next block
-                            if (thisbox[cbInd+1].numchildren) {
-                                var nblock = thisbox[cbInd+1];
-                                var i = 0;
-                                while (nblock[i] and nblock[i].y == 0 and 
(cOffset > nblock[i].x+nblock[i].width)) i++;
-                                if (!nblock[i] or (cOffset > 
nblock[i].x+nblock[i].width)) {
-                                    aBlock = nblock;
-                                    aWord = aBlock[aBlock.numchildren-1];
-                                    aPos = aWord.text.length;
-                                } else {
-                                    aBlock = nblock;
-                                    aWord = nblock[i];
-                                    aPos = static.getIndInWord(aWord, 
cOffset-aWord.x);
-                                }
-                            
-                            } else {
-                                // no words in next block
-                                aBlock = thisbox[cbInd+1];
-                                aWord = null;
-                                aPos = 0;
-                            }
-                        }
-                        // invoke selection or set cursor position
-                        if (vexi.ui.key.shift) {
-                            selectWords();
                         } else {
-                            cBlock = aBlock;
-                            cWord = aWord;
-                            cPos = aPos;
+                            // no words in next block
+                            aBlock = thisbox[cbInd+1];
+                            aWord = null;
+                            aPos = 0;
                         }
                     }
-                    // invoke syncCursor directly
-                    syncCursor();
-                    return true;
-                    
-                // move cursor to start of line
-                case "home":
-                case "HOME":
-                    // special case select mode
-                    if (unselectLeft()) {
-                        return;
-                    }
-                    
-                    if (multiline and cWord and cWord.y != 0) {
-                        var i = cwInd-1;
-                        while (i>0 and cBlock[i] and cBlock[i].y == cWord.y) {
-                            i--;
-                        }
-                        aBlock = cBlock;
-                        aWord = aBlock[i+1];
-                        aPos = 0;
-                    
-                    } else {
-                        // single line or empty block
-                        aBlock = cBlock;
-                        aWord = aBlock[0];
-                        aPos = 0;
-                    }
                     // invoke selection or set cursor position
                     if (vexi.ui.key.shift) {
                         selectWords();
@@ -1378,264 +1355,299 @@
                         cWord = aWord;
                         cPos = aPos;
                     }
-                    break;
-                    
-                // move cursor to end of line
-                case "end":
-                case "END":
-                    // special case select mode
-                    if (unselectRight()) {
-                        return;
+                }
+                // invoke syncCursor directly
+                syncCursor();
+                return true;
+                
+            // move cursor to start of line
+            case "home":
+            case "HOME":
+                // special case select mode
+                if (unselectLeft()) {
+                    return;
+                }
+                
+                if (multiline and cWord and cWord.y != 0) {
+                    var i = cwInd-1;
+                    while (i>0 and cBlock[i] and cBlock[i].y == cWord.y) {
+                        i--;
                     }
+                    aBlock = cBlock;
+                    aWord = aBlock[i+1];
+                    aPos = 0;
+                
+                } else {
+                    // single line or empty block
+                    aBlock = cBlock;
+                    aWord = aBlock[0];
+                    aPos = 0;
+                }
+                // invoke selection or set cursor position
+                if (vexi.ui.key.shift) {
+                    selectWords();
+                } else {
+                    cBlock = aBlock;
+                    cWord = aWord;
+                    cPos = aPos;
+                }
+                break;
+                
+            // move cursor to end of line
+            case "end":
+            case "END":
+                // special case select mode
+                if (unselectRight()) {
+                    return;
+                }
+                
+                if (multiline and cWord) {
+                    var i = cwInd+1;
+                    while (cBlock[i] and cBlock[i].y == cWord.y) i++;
+                    aBlock = cBlock;
+                    aWord = aBlock[i-1];
+                    aPos = aWord.text.length;
+                
+                } else {
+                    // single line or empty block
+                    aBlock = cBlock;
+                    aWord = aBlock.numchildren ? aBlock[cBlock.numchildren-1] 
: null;
+                    aPos = aWord ? aWord.text.length : 0;
+                }
+                // invoke selection or set cursor position
+                if (vexi.ui.key.shift) {
+                    selectWords();
+                } else {
+                    cBlock = aBlock;
+                    cWord = aWord;
+                    cPos = aPos;
+                }
+                break;
+                
+            case "enter":
+            case "ENTER":
+                // special case select mode
+                if (select) {
+                    deleteSelectedText();
+                }
+                
+                if (multiline) {
+                    // multiline edits add blocks at cursor point
                     
-                    if (multiline and cWord) {
-                        var i = cwInd+1;
-                        while (cBlock[i] and cBlock[i].y == cWord.y) i++;
-                        aBlock = cBlock;
-                        aWord = aBlock[i-1];
-                        aPos = aWord.text.length;
+                    // create new block
+                    var nblock = .block(vexi.box, blockargs);
+                    if (nblock.font != cBlock.font)
+                        nblock.font = cBlock.font;
+                    if (nblock.fontsize != cBlock.fontsize)
+                        nblock.fontsize = cBlock.fontsize;
+                    if (nblock.textcolor != cBlock.textcolor)
+                        nblock.textcolor = cBlock.textcolor;
                     
-                    } else {
-                        // single line or empty block
-                        aBlock = cBlock;
-                        aWord = aBlock.numchildren ? 
aBlock[cBlock.numchildren-1] : null;
-                        aPos = aWord ? aWord.text.length : 0;
+                    if (cWord) {
+                        // in empty block if cWord is null
+                        
+                        // move trailing words
+                        while (cBlock.numchildren > cwInd+1) {
+                            nblock[0] = cBlock[cBlock.numchildren-1];
+                        }
+                        if (cPos == 0) {
+                            // move cWord
+                            nblock[0] = cWord;
+                        
+                        } else if (cPos != cWord.text.length) {
+                            // split cWord
+                            nblock[0] = .word(vexi.box, nblock.wordargs);
+                            nblock[0].text = cWord.text.substring(cPos);
+                            nblock[0].chartype = cWord.chartype;
+                            cWord.text = cWord.text.substring(0, cPos);
+                        }
                     }
-                    // invoke selection or set cursor position
-                    if (vexi.ui.key.shift) {
-                        selectWords();
-                    } else {
-                        cBlock = aBlock;
-                        cWord = aWord;
-                        cPos = aPos;
-                    }
-                    break;
+                    thisbox[cbInd+1] = nblock;
+                    cBlock.reflowbox = true;
+                    // cBlock.reflow called at the end of KeyPressed
+                    // so no need to reflow nblock(cBlock) manually
+                    cBlock = nblock;
+                    cWord = cBlock.numchildren ? cBlock[0] : null;
+                    cPos = 0;
+                }
+                break;
+                
+            // switch insert mode on/off
+            case "insert":
+            case "INSERT":
+                insert = !insert;
+                break;
+                
+            // delete - deletes forwards
+            case "delete":
+            case "DELETE":
+            case "C-delete":
+            case "C-DELETE":
+                // special case select mode
+                if (select) {
+                    deleteSelectedText();
+                } else if (cWord) {
+                    // normal operation
                     
-                case "enter":
-                case "ENTER":
-                    // special case select mode
-                    if (select) {
-                        deleteSelectedText();
-                    }
-                    
-                    if (multiline) {
-                        // multiline edits add blocks at cursor point
-                        
-                        // create new block
-                        var nblock = .block(vexi.box, blockargs);
-                        if (nblock.font != cBlock.font)
-                            nblock.font = cBlock.font;
-                        if (nblock.fontsize != cBlock.fontsize)
-                            nblock.fontsize = cBlock.fontsize;
-                        if (nblock.textcolor != cBlock.textcolor)
-                            nblock.textcolor = cBlock.textcolor;
-                        
-                        if (cWord) {
-                            // in empty block if cWord is null
+                    if (cPos == cWord.text.length) {
+                        // at the end of a block
+                        if (thisbox.numchildren-1 > cbInd) {
+                            // increment cbInd as we're interested in the next 
block
+                            cbInd++;
                             
-                            // move trailing words
-                            while (cBlock.numchildren > cwInd+1) {
-                                nblock[0] = cBlock[cBlock.numchildren-1];
-                            }
-                            if (cPos == 0) {
-                                // move cWord
-                                nblock[0] = cWord;
+                            // combine blocks by taking words from 
thisbox[cbInd]
+                            if (cBlock.numchildren > 
thisbox[cbInd].numchildren) {
+                                while (thisbox[cbInd].numchildren) {
+                                    cBlock.add(thisbox[cbInd][0]);
+                                }
+                                thisbox[cbInd].thisbox = null;
                             
-                            } else if (cPos != cWord.text.length) {
-                                // split cWord
-                                nblock[0] = .word(vexi.box, nblock.wordargs);
-                                nblock[0].text = cWord.text.substring(cPos);
-                                nblock[0].chartype = cWord.chartype;
-                                cWord.text = cWord.text.substring(0, cPos);
+                            } else {
+                                // combine blocks by taking words from cBlock
+                                while (cBlock.numchildren) {
+                                    thisbox[cbInd][0] = 
cBlock[cBlock.numchildren-1];
+                                }
+                                cBlock.thisbox = null;
+                                cBlock = thisbox[cbInd-1];    // -1 as cBlock 
was just deleted
+                                cwInd = cBlock.indexof(cWord);
                             }
+                            if (cBlock[cwInd+1] and cWord.chartype == 
cBlock[cwInd+1].chartype) {
+                                // combine same-type words if together
+                                cWord.text += cBlock[cwInd+1].text;
+                                cBlock[cwInd+1] = null;
+                            }
                         }
-                        thisbox[cbInd+1] = nblock;
-                        cBlock.reflowbox = true;
-                        // cBlock.reflow called at the end of KeyPressed
-                        // so no need to reflow nblock(cBlock) manually
-                        cBlock = nblock;
-                        cWord = cBlock.numchildren ? cBlock[0] : null;
-                        cPos = 0;
+                    
+                    } else if (cWord.text.length == 1) {
+                        // one letter left in word
+                        cBlock[cwInd] = null;
+                        if (cBlock.numchildren) {
+                            if (cBlock.numchildren == cwInd) {
+                                cWord = cBlock[cwInd-1];
+                                cPos = cWord.text.length;
+                            } else {
+                                cWord = cBlock[cwInd];
+                                cPos = 0;
+                            }
+                        } else {
+                            cWord = null;
+                            cPos = 0;
+                        }
+                    
+                    } else {
+                        // word is larger than one letter
+                        cWord.text = cWord.text.slice(0, cPos) + 
cWord.text.slice(cPos+1);
+                        if (cPos == cWord.text.length and cBlock.numchildren-1 
> cwInd) {
+                            cPos = 0;
+                            cWord = cBlock[cwInd+1];
+                        }
                     }
-                    break;
+                
+                } else if (thisbox.numchildren-1 > cbInd) {
+                    // no word in this block, try and remove it
+                    cBlock.thisbox = null;
+                    cBlock = thisbox[cbInd];
+                    cPos = 0;
+                    cWord = cBlock.numchildren ? cBlock[0] : null;
+                }
+                break;
+                
+            // backspace - deletes backwards
+            case "back_space":
+            case "BACK_SPACE":
+            case "C-back_space":
+            case "C-BACK_SPACE":
+                // special case select mode
+                if (select) {
+                    deleteSelectedText();
+                }
+                else if (cWord) {
+                    // normal operation
                     
-                // switch insert mode on/off
-                case "insert":
-                case "INSERT":
-                    insert = !insert;
-                    break;
-                    
-                // delete - deletes forwards
-                case "delete":
-                case "DELETE":
-                case "C-delete":
-                case "C-DELETE":
-                    // special case select mode
-                    if (select) {
-                        deleteSelectedText();
-                    } else if (cWord) {
-                        // normal operation
-                        
-                        if (cPos == cWord.text.length) {
-                            // at the end of a block
-                            if (thisbox.numchildren-1 > cbInd) {
-                                // increment cbInd as we're interested in the 
next block
-                                cbInd++;
+                    if (cPos == 0) {
+                        // at the start of a word
+                        if (cwInd == 0) {
+                            // at the start of a block
+                            if (cbInd != 0) {
+                                // decrement cbInd as we're interested in the 
prior block
+                                --cbInd;
                                 
-                                // combine blocks by taking words from 
thisbox[cbInd]
                                 if (cBlock.numchildren > 
thisbox[cbInd].numchildren) {
+                                    // combine blocks by taking words from 
thisbox[cbInd]
                                     while (thisbox[cbInd].numchildren) {
-                                        cBlock.add(thisbox[cbInd][0]);
+                                        cBlock[0] = 
thisbox[cbInd][thisbox[cbInd].numchildren-1];
                                     }
                                     thisbox[cbInd].thisbox = null;
                                 
                                 } else {
                                     // combine blocks by taking words from 
cBlock
                                     while (cBlock.numchildren) {
-                                        thisbox[cbInd][0] = 
cBlock[cBlock.numchildren-1];
+                                        
thisbox[cbInd][thisbox[cbInd].numchildren] = cBlock[0];
                                     }
                                     cBlock.thisbox = null;
-                                    cBlock = thisbox[cbInd-1];    // -1 as 
cBlock was just deleted
-                                    cwInd = cBlock.indexof(cWord);
+                                    cBlock = thisbox[cbInd];
                                 }
-                                if (cBlock[cwInd+1] and cWord.chartype == 
cBlock[cwInd+1].chartype) {
-                                    // combine same-type words if together
-                                    cWord.text += cBlock[cwInd+1].text;
-                                    cBlock[cwInd+1] = null;
+                                
+                                // combine same-type words if together
+                                cwInd = cBlock.indexof(cWord);
+                                if (cwInd != 0 and cWord.chartype == 
cBlock[cwInd-1].chartype) {
+                                    cPos = cBlock[cwInd-1].text.length;
+                                    cWord.text = cBlock[cwInd-1].text + 
cWord.text;
+                                    cBlock[cwInd-1].thisbox = null;
                                 }
                             }
                         
-                        } else if (cWord.text.length == 1) {
-                            // one letter left in word
-                            cBlock[cwInd] = null;
-                            if (cBlock.numchildren) {
-                                if (cBlock.numchildren == cwInd) {
-                                    cWord = cBlock[cwInd-1];
-                                    cPos = cWord.text.length;
-                                } else {
-                                    cWord = cBlock[cwInd];
-                                    cPos = 0;
+                        } else {
+                            // delete from previous word
+                            var w = cBlock[cwInd-1];
+                            if (w.text.length == 1) {
+                                cBlock[cwInd-1] = null;
+                            } else {
+                                w.text = w.text.substring(0, w.text.length-1);
+                                if (w.chartype == cWord.chartype) {
+                                    cPos = w.text.length;
+                                    w.text += cWord.text;
+                                    cBlock[cwInd] = null;
+                                    cWord = w;
                                 }
-                            } else {
-                                cWord = null;
-                                cPos = 0;
                             }
-                        
-                        } else {
-                            // word is larger than one letter
-                            cWord.text = cWord.text.slice(0, cPos) + 
cWord.text.slice(cPos+1);
-                            if (cPos == cWord.text.length and 
cBlock.numchildren-1 > cwInd) {
-                                cPos = 0;
-                                cWord = cBlock[cwInd+1];
-                            }
                         }
                     
-                    } else if (thisbox.numchildren-1 > cbInd) {
-                        // no word in this block, try and remove it
-                        cBlock.thisbox = null;
-                        cBlock = thisbox[cbInd];
-                        cPos = 0;
-                        cWord = cBlock.numchildren ? cBlock[0] : null;
-                    }
-                    break;
-                    
-                // backspace - deletes backwards
-                case "back_space":
-                case "BACK_SPACE":
-                case "C-back_space":
-                case "C-BACK_SPACE":
-                    // special case select mode
-                    if (select) {
-                        deleteSelectedText();
-                    }
-                    else if (cWord) {
-                        // normal operation
+                    } else if (cWord.text.length == 1) {
+                        // delete the word altogether
+                        cWord.thisbox = null;
                         
-                        if (cPos == 0) {
-                            // at the start of a word
-                            if (cwInd == 0) {
-                                // at the start of a block
-                                if (cbInd != 0) {
-                                    // decrement cbInd as we're interested in 
the prior block
-                                    --cbInd;
-                                    
-                                    if (cBlock.numchildren > 
thisbox[cbInd].numchildren) {
-                                        // combine blocks by taking words from 
thisbox[cbInd]
-                                        while (thisbox[cbInd].numchildren) {
-                                            cBlock[0] = 
thisbox[cbInd][thisbox[cbInd].numchildren-1];
-                                        }
-                                        thisbox[cbInd].thisbox = null;
-                                    
-                                    } else {
-                                        // combine blocks by taking words from 
cBlock
-                                        while (cBlock.numchildren) {
-                                            
thisbox[cbInd][thisbox[cbInd].numchildren] = cBlock[0];
-                                        }
-                                        cBlock.thisbox = null;
-                                        cBlock = thisbox[cbInd];
-                                    }
-                                    
-                                    // combine same-type words if together
-                                    cwInd = cBlock.indexof(cWord);
-                                    if (cwInd != 0 and cWord.chartype == 
cBlock[cwInd-1].chartype) {
-                                        cPos = cBlock[cwInd-1].text.length;
-                                        cWord.text = cBlock[cwInd-1].text + 
cWord.text;
-                                        cBlock[cwInd-1].thisbox = null;
-                                    }
-                                }
-                            
-                            } else {
-                                // delete from previous word
-                                var w = cBlock[cwInd-1];
-                                if (w.text.length == 1) {
-                                    cBlock[cwInd-1] = null;
-                                } else {
-                                    w.text = w.text.substring(0, 
w.text.length-1);
-                                    if (w.chartype == cWord.chartype) {
-                                        cPos = w.text.length;
-                                        w.text += cWord.text;
-                                        cBlock[cwInd] = null;
-                                        cWord = w;
-                                    }
-                                }
-                            }
+                        if (cwInd == 0) {
+                            // at the start of a block
+                            cWord = cBlock.numchildren ? cBlock[0] : null;
+                            cPos = 0;
                         
-                        } else if (cWord.text.length == 1) {
-                            // delete the word altogether
-                            cWord.thisbox = null;
-                            
-                            if (cwInd == 0) {
-                                // at the start of a block
-                                cWord = cBlock.numchildren ? cBlock[0] : null;
-                                cPos = 0;
-                            
-                            } else if (cwInd == cBlock.numchildren) {
-                                // at the end of a block
-                                cWord = cBlock[cwInd-1];
-                                cPos = cWord.text.length;
-                            
-                            } else {
-                                // mid-block
-                                cWord = cBlock[cwInd];
-                                cPos = 0;
-                            }
+                        } else if (cwInd == cBlock.numchildren) {
+                            // at the end of a block
+                            cWord = cBlock[cwInd-1];
+                            cPos = cWord.text.length;
+                        
                         } else {
-                            // delete from within the word
-                            cWord.text = cWord.text.slice(0, cPos-1) + 
cWord.text.slice(cPos);
-                            cPos--;
+                            // mid-block
+                            cWord = cBlock[cwInd];
+                            cPos = 0;
                         }
-                    
                     } else {
-                        // no word in this block, try to delete the block
-                        if (cbInd > 0) {
-                            cBlock.thisbox = null;
-                            cBlock = thisbox[cbInd-1];
-                            cWord = cBlock.numchildren ? 
cBlock[cBlock.numchildren-1] : null;
-                            cPos = cWord ? cWord.text.length : 0;
-                        }
+                        // delete from within the word
+                        cWord.text = cWord.text.slice(0, cPos-1) + 
cWord.text.slice(cPos);
+                        cPos--;
                     }
-                    break;
+                
+                } else {
+                    // no word in this block, try to delete the block
+                    if (cbInd > 0) {
+                        cBlock.thisbox = null;
+                        cBlock = thisbox[cbInd-1];
+                        cWord = cBlock.numchildren ? 
cBlock[cBlock.numchildren-1] : null;
+                        cPos = cWord ? cWord.text.length : 0;
+                    }
                 }
+                break;
             }
             
             cBlock.reflowbox = true;

Modified: 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/field.t
===================================================================
--- branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/field.t     
2016-07-15 01:16:46 UTC (rev 4873)
+++ branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/text/field.t     
2016-07-16 00:05:55 UTC (rev 4874)
@@ -25,10 +25,11 @@
         visible    ++= static.visibleWrite;
         th_view    ++= static.viewWrite;
         KeyPressed ++= static.keypressWrite;
+        KeyTyped   ++= static.keytypedWrite;
         
     </ui:box>
     
-    static.keypressWrite = function(v) {
+    static.keytypedWrite = function(v){
         var edit = trapee.v_edit;
         if (!edit.select and v.length == 1 and trapee.maxlength > 0 and 
edit.text.length >= trapee.maxlength) {
             // limit amount of text
@@ -43,12 +44,9 @@
             }
         }
         
-        if (v == "enter" || v == "ENTER") {
-            // fire action
-            trapee.action = true;
-        } else if (v.length>1) {
+        if (v.length>1) {
             // pass to edit
-            edit.KeyPressed = v;
+            edit.KeyTyped = v;
         } else {
             // alpha numeric -- 48-57 (0-9), 65-90 (A-Z), 97-122 (a-z)
             var c = v.charCodeAt(0);
@@ -56,26 +54,36 @@
             case "alpha":
                 if ((c>=97 and 122>=c) or (c>=65 and 90>=c)) {
                     // pass to edit
-                    edit.KeyPressed = v;
+                    edit.KeyTyped = v;
                 }
                 break;
             case "alphanumeric":
                 if ((c>=97 and 122>=c) or (c>=65 and 90>=c) or (c>=48 and 
57>=c)) {
                     // pass to edit
-                    edit.KeyPressed = v;
+                    edit.KeyTyped = v;
                 }
                 break;
             case "numeric":
                 if (c>=48 and 57>=c) {
                     // pass to edit
-                    edit.KeyPressed = v;
+                    edit.KeyTyped = v;
                 }
                 break;
             default:
                 // pass to edit
-                edit.KeyPressed = v;
+                edit.KeyTyped = v;
             }
         }
+    };
+    
+    static.keypressWrite = function(v) {
+        if (v == "enter" || v == "ENTER") {
+            // fire action
+            trapee.action = true;
+        } else if (v.length>1) {
+            // pass to edit
+            trapee.v_edit.KeyPressed = v;
+        }
     }
     
     /** retrieve a integer offset of where the cursor is within the textfield 
*/

Modified: 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/shadowtext.t
===================================================================
--- 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/shadowtext.t  
    2016-07-15 01:16:46 UTC (rev 4873)
+++ 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/shadowtext.t  
    2016-07-16 00:05:55 UTC (rev 4874)
@@ -14,6 +14,7 @@
         thisbox.th_shadowtext;
         thisbox.th_shadowwrap;
         
+        thisbox.KeyTyped ++= static.keypressWrite;
         thisbox.KeyPressed ++= static.keypressWrite;
         thisbox.shadowtext ++= static.shadowtextWrite;
         thisbox.v_container ++= static.containerWrite;

Modified: 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textarea.t
===================================================================
--- 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textarea.t    
    2016-07-15 01:16:46 UTC (rev 4873)
+++ 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textarea.t    
    2016-07-16 00:05:55 UTC (rev 4874)
@@ -11,7 +11,8 @@
         thisbox.liveValuePut = true;
         thisbox.th_scroll;
         
-        thisbox.KeyPressed ++= static.keypressWrite;
+        thisbox.KeyTyped   ++= static.keyeventWrite;
+        thisbox.KeyPressed ++= static.keyeventWrite;
         thisbox.enabled ++= static.enableWrite;
         thisbox.focused ++= static.focusWrite;
         thisbox.value ++= static.valueRead;
@@ -34,9 +35,9 @@
     static.enableWrite = function(v) { cascade = v; trapee.v_edit.enabled = 
trapee.enabled; }
     
     /** passon keypress to editbox */
-    static.keypressWrite = function(v) {
+    static.keyeventWrite = function(v) {
         cascade = v;
-        trapee.v_edit.KeyPressed = v;
+        trapee.v_edit[trapname] = v;
         if (trapee.liveValuePut) {
             trapee.v_valueput = true;
             trapee.value = trapee.value;

Modified: 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textfield.t
===================================================================
--- 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textfield.t   
    2016-07-15 01:16:46 UTC (rev 4873)
+++ 
branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/textfield.t   
    2016-07-16 00:05:55 UTC (rev 4874)
@@ -16,6 +16,7 @@
         thisbox.value = "";
         thisbox.v_valueput = false;
         
+        KeyTyped   ++= static.keytypedEvent;
         KeyPressed ++= static.keypressEvent;
         password   ++= static.passwordWrite;
         value      ++= static.valueRead;
@@ -36,6 +37,51 @@
         trapee.v_field.value = v;
     }
     
+    static.keytypedEvent = function(v){
+       var edit = trapee.v_edit;        
+        if (trapee.password) {
+            // deal with input for password fields
+            var do_del = true;
+            var cPos = edit.getCPos();
+            var sPos = edit.getSPos();
+            var val = trapee.value;
+            
+            if (edit.select) {
+                // delete text matching selected text
+                if (cPos > sPos) {
+                    val = val.substring(0, sPos) + val.substring(cPos, 
val.length);
+                } else {
+                    val = val==null?"":val.substring(0, cPos) + 
val.substring(sPos, val.length);
+                }
+                do_del = false;
+            }
+            
+            val =
+                val==null or val==""
+                    ? v
+                    : val.substring(0, cPos) + v + val.substring(cPos, 
val.length);
+            v = '*';
+
+            // must be done after as not to inadvertently modify cPos
+            edit.KeyTyped = v;
+            trapee.v_valueput = true;
+            trapee.value = val;
+            
+        } else {
+            if (trapee.forcecase) {
+               if (trapee.forcecase == "upper") {
+                   v = v.toUpperCase();
+               } else if (trapee.forcecase == "lower") {
+                   v = v.toLowerCase();
+               }
+            }
+            // normal textfield input
+            cascade = v;
+            trapee.text = trapee.text;
+        }
+    
+    };
+    
     /** fire action or filter key in case of password fields */
     static.keypressEvent = function(v) {
         var edit = trapee.v_edit;
@@ -69,7 +115,7 @@
                 else return;
             }
             
-            if (edit.select and ((v.length == 1) or
+            if (edit.select and (
                     (v.toLowerCase() == "delete") or (v.toLowerCase() == 
"back_space"))) {
                 // delete text matching selected text
                 if (cPos > sPos) {
@@ -80,14 +126,6 @@
                 do_del = false;
             }
             
-            if (v.length == 1) {
-                // insert single character
-                val =
-                    val==null or val==""
-                        ? v
-                        : val.substring(0, cPos) + v + val.substring(cPos, 
val.length);
-                v = '*';
-            } else
             if (v == "back_space") {
                 // delete character before cPos
                 if (do_del and (cPos > 0)) {
@@ -115,21 +153,6 @@
             trapee.value = val;
             
         } else {
-            if (v.length==1 and trapee.forcecase) {
-               var c = v.charCodeAt(0);
-               if (trapee.forcecase.indexOf("upper")==0) {
-                   // 97-122 (a-z)
-                   if (122>=c and c>=97) {
-                       v = vexi.string.fromCharCode(c-32);
-                   }
-               } else
-               if (trapee.forcecase.indexOf("lower")) {
-                   // 65-90 (A-Z)
-                   if (90>=c and c>=65) {
-                       v = vexi.string.fromCharCode(c+32);
-                   }
-               }
-            }
             // normal textfield input
             cascade = v;
             trapee.text = trapee.text;

Modified: branches/vexi3/org.vexi-vexi.widgets/src_poke/poke/widgets/textfield.t
===================================================================
--- branches/vexi3/org.vexi-vexi.widgets/src_poke/poke/widgets/textfield.t      
2016-07-15 01:16:46 UTC (rev 4873)
+++ branches/vexi3/org.vexi-vexi.widgets/src_poke/poke/widgets/textfield.t      
2016-07-16 00:05:55 UTC (rev 4874)
@@ -1,17 +1,29 @@
 <!-- public domain -->
 
-<vexi xmlns:ui="vexi://ui" xmlns:w="vexi.widget" xmlns:poke="poke">
+<vexi xmlns:ui="vexi://ui" xmlns:w="vexi.widget" xmlns:poke="poke" 
xmlns:lay="vexi.layout">
     <w:surface />
     <ui:box fill="white" orient="vertical">
+        <lay:grid cols="2" maxwidth="350">
+            <ui:Box text="Field" shrink="true"/>
+            <w:textfield id="field" shadowtext="normal text"/>
+            <ui:Box text="Password" shrink="true"/>
+            <ui:Box>
+               <w:textfield id="password" password="true" 
shadowtext="password"/>
+               <ui:Box id="reveal"/> 
+            </ui:Box>
+            <ui:Box text="Area" shrink="true"/>
+            <w:textarea />
+            
+        </lay:grid>
         <ui:box>
-            <ui:Box />
-            <w:textfield id="field" fill="yellow" />
-            <ui:Box />
-        </ui:box>
-        <ui:box>
             <w:link id="enable" text="Enable" />
         </ui:box>
+                     
         
+        $password.value ++= function(v){
+               cascade = v;
+               $reveal.text = v;
+        };
         $enable.action ++= function(v) { $field.enabled = !$field.enabled; }
         
         vexi.ui.frame = thisbox;

Modified: trunk/org.vexi-build.shared/meta/module.revisions
===================================================================
--- trunk/org.vexi-build.shared/meta/module.revisions   2016-07-15 01:16:46 UTC 
(rev 4873)
+++ trunk/org.vexi-build.shared/meta/module.revisions   2016-07-16 00:05:55 UTC 
(rev 4874)
@@ -1 +1 @@
-{"https:\/\/ebuild-project.org\/svn\/ebuild\/plugins":"180","https:\/\/emanate-project.org\/svn\/eapi":"223"}
\ No newline at end of file
+{"https:\/\/ebuild-project.org\/svn\/ebuild\/plugins":"209","https:\/\/emanate-project.org\/svn\/eapi":"223"}
\ No newline at end of file

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are 
consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
J-Flow, sFlow and other flows. Make informed decisions using capacity planning
reports.http://sdm.link/zohodev2dev
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to