Results 1 to 8 of 8

Thread: KeyPress event differs between FF and IE

  1. #1
    Sencha User
    Join Date
    May 2011
    Location
    Illinois
    Posts
    32

    Default KeyPress event differs between FF and IE

    I am using some code borrowed from "Fother" found here -> http://www.sencha.com/forum/showthre...ut-mask-plugin

    I have modified this file to work for my needs, but I have came across an issue that I can't seem to solve. The issue is on the onKeyDown and onKeyPress methods. These methods are used to detect which keys were entered and only act on a few certain keys (Escape, Delete, Backspace and numbers). In IE if I press the '5' key on the number pad the onKeyDown picks this up as 101 (ASCII - e ... using fe.getKeyCode()) and in the onKeyPress method it gets picked up as 53 (ASCII - 5)

    Firefox handles this differently, currently I'm using FF-5 which is used by 17% of my clients. The onKeyDown method still retrieves 101, which is fine, but the onKeyPress method retrieves 0 from the same method call. This method retrieves 0 for ALL key presses.

    Here is the code that I am using.

    Code:
    package midins.shared.ui.widget.form;
    
    import java.util.HashMap;
    import java.util.Map;
    
    
    import com.extjs.gxt.ui.client.event.ComponentEvent;
    import com.extjs.gxt.ui.client.event.FieldEvent;
    import com.extjs.gxt.ui.client.widget.form.TextField;
    import com.google.gwt.event.dom.client.KeyCodes;
    import com.google.gwt.user.client.Element;
    
    
    /*
     * Stolen from 'Fother' - http://www.sencha.com/forum/showthread.php?64797-input-mask-plugin
     * 
     * Modified by @jsmith
     * Modification Date - 8-22-2011
     */
    public class TextFieldMask extends TextField<String> {
    
    
        public class Settings {
    
    
            private String placeHolder;
    
    
            public Settings() {
    
    
            }
    
    
            public Settings(String placeHolder) {
                this.placeHolder = placeHolder;
            }
    
    
            public String getPlaceHolder() {
                return placeHolder;
            }
    
    
            public void setPlaceHolder(String placeHolder) {
                this.placeHolder = placeHolder;
            }
    
    
        }
    
    
        private Settings settings;
        private final String mask;
        private int len;
        private int partialPosition;
        private int cursorBegin = -1;
        private int cursorEnd = -1;
        private Integer firstNonMaskPos;
        private boolean ignore;
        private String[] buffer;
        private String[] tests;
        private String focusText;
    
    
        private static final Map<String, String> defs;
    
    
        static {
            defs = new HashMap<String, String>();
            defs.put("9", "[0-9]");
            defs.put("a", "[A-Za-z]");
            defs.put("*", "[A-Za-z0-9]");
        }
    
    
        private static boolean cotainDef(String key) {
    
    
            if (defs.get(key) != null) {
                return true;
            } else {
                return false;
            }
        }
    
    
        private static String getDef(String key) {
            return defs.get(key);
        }
    
    
        public TextFieldMask(String mask) {
            super();
            this.mask = mask;
        }
    
    
        private void buffer() {
    
    
            String[] aux = split(mask);
    
    
            buffer = new String[aux.length];
    
    
            for (int i = 0; i < aux.length; i++) {
                if (cotainDef(aux[i])) {
                    buffer[i] = settings.getPlaceHolder();
                } else {
                    buffer[i] = aux[i];
                }
            }
        }
    
    
        private int checkVal(boolean allow) {
    
    
            String test = "";
    
    
            if (getValue() != null) {
                test = getValue();
            }
    
    
            int lastMatch = -1;
    
    
            int a = 0;
    
    
            for (int i = 0, pos = 0; i < len; i++) {
                if (tests[i] != null) {
                    buffer[i] = settings.getPlaceHolder();
    
    
                    while (pos++ < test.length()) {
                        String c = String.valueOf(test.charAt(pos - 1));
    
    
                        if (c.matches(tests[i])) {
    
    
                            buffer[i] = String.valueOf(c);
                            lastMatch = i;
                            a = i;
                            break;
                        }
                    }
                    if (pos > test.length()) {
                        a = i;
                        break;
                    }
                } else if (i != partialPosition) {
                    try {
                        char d = test.charAt(pos);
    
    
                        if (buffer[i].equals(String.valueOf(d))) {
                            pos++;
                            lastMatch = i;
                        }
                    } catch (Exception e) {
                        continue;
                    }
                }
            }
    
    
            if (allow || lastMatch + 1 >= partialPosition) {
                writeBuffer();
    
    
                if (!allow) {
    
    
                    if (getValue() != null) {
                        setValue(getValue().substring(0, lastMatch + 1));
                    }
                }
                a = partialPosition;
            }
            
            return a;
        }
    
    
        private void clearBuffer(int start, int end) {
    
    
            for (int i = start; i < end && i < len; i++) {
                if (tests[i] != null) {
                    buffer[i] = settings.getPlaceHolder();
                }
            }
        }
    
    
        private void each() {
    
    
            for (int i = 0; i < tests.length; i++) {
                String c = tests[i];
    
    
                if (c == "?") {
                    len--;
                    partialPosition = i;
                } else if (cotainDef(c)) {
                    tests[i] = getDef(c);
    
    
                    if (firstNonMaskPos == null) {
                        firstNonMaskPos = tests.length - 1;
                    }
                } else {
                    tests[i] = null;
                }
            }
        }
    
    
        public void maskField() {
    
    
            settings = new Settings("_");
    
    
            tests = new String[] {};
            partialPosition = mask.length();
            firstNonMaskPos = null;
            len = mask.length();
    
    
            tests = split(mask);
    
    
            each();
            buffer();
    
    
            ignore = false;
    
    
            focusText = "";
    
    
            if (getValue() != null) {
                focusText = getValue();
            }
    
    
            if (!isReadOnly()) {
                checkVal(false);
            }
        }
    
    
        @Override
        protected void onBlur(ComponentEvent be) {
    
    
            super.onBlur(be);
            checkVal(false);
        }
    
    
        @Override
        protected void onFocus(ComponentEvent be) {
    
    
            super.onFocus(be);
    
    
            focusText = "";
    
    
            if (getValue() != null) {
                focusText = getValue();
            }
    
    
            int pos = checkVal(false);
            writeBuffer();
    
    
            if (pos == mask.length()) {
                cursorBegin = 0;
                cursorEnd = pos;
                select(0, pos);
            } else {
                cursorBegin = pos;
                cursorEnd = pos;
                setCursorPos(pos);
            }
        }
    
    
        @Override
        protected void onKeyDown(FieldEvent fe) {
            
            super.onKeyDown(fe);
    
    
            int k = fe.getKeyCode();
    
    
            ignore = k < 16 || k > 16 && k < 32 || k > 32 && k < 41;
    
    
            if (cursorBegin - cursorEnd != 0
                    && (!ignore || k == KeyCodes.KEY_BACKSPACE || k == KeyCodes.KEY_DELETE)) {
                clearBuffer(cursorBegin, cursorEnd);
            }
    
    
            if (k == KeyCodes.KEY_BACKSPACE || k == KeyCodes.KEY_DELETE) {
                shiftL(getCursorPos() + (k == KeyCodes.KEY_DELETE ? 0 : -1));
                fe.stopEvent();
            } else if (k == KeyCodes.KEY_ESCAPE) {
                setValue(focusText);
                fe.stopEvent();
            }
            
        }
        
        @Override
        protected void onKeyPress(FieldEvent fe) {
    
    
            super.onKeyPress(fe);
    
    
            int k = fe.getKeyCode();
    
    
            if (ignore) {
                if (k == KeyCodes.KEY_BACKSPACE) {
                    fe.stopEvent();
                }
                return;
            }
    
    
            if (fe.isControlKey() || fe.isAltKey()) {
                fe.stopEvent();
            } else if (k >= 32 && k <= 125 || k > 186) {
                int p = seekNext(getCursorPos() - 1);
    
    
                if (p < len) {
                    String c = String.valueOf((char) k);
                    if (c.matches(tests[p])) {
                        shiftR(p);
                        buffer[p] = c;
                        writeBuffer();
                        int next = seekNext(p);
                        setCursorPos(next);
                        cursorBegin = next;
                        cursorEnd = next;
                    }
                }
            }
            fe.stopEvent();
        }
    
    
        @Override
        protected void onRender(Element target, int index) {
            super.onRender(target, index);
            maskField();
        }
    
    
        private int seekNext(int index) {
    
    
            while (++index <= len) {
                try {
                    if (tests[index] != null) {
                        break;
                    }
                } catch (Exception e) {
                    break;
                }
            }
            return index;
        }
    
    
        private void shiftL(int index) {
            for (int i = index; i >= 0; i--) {
                if (tests[i] != null) {
                    index = i;
                    break;
                }
            }
    
    
            for (int i = index; i < len; i++) {
                if (i >= 0 && tests[i] != null) {
                    buffer[i] = settings.getPlaceHolder();
    
    
                    int j = seekNext(i);
    
    
                    if (j < len && buffer[j].matches(tests[i])) {
                        buffer[i] = buffer[j];
                    } else {
                        break;
                    }
                }
            }
            writeBuffer();
            setCursorPos(index);
        }
    
    
        private void shiftR(int index) {
    
    
            String c = settings.getPlaceHolder();
    
    
            for (int i = index; i < len; i++) {
                if (tests[i] != null) {
                    int j = seekNext(i);
                    String t = buffer[i];
                    buffer[i] = c;
                    if (j < len && t.matches(tests[j])) {
                        c = t;
                    } else {
                        break;
                    }
                }
            }
        }
    
    
        private String[] split(String text) {
            int length = text.length();
            String[] array = new String[length];
    
    
            for (int i = 0; i < length; i++) {
                array[i] = String.valueOf(text.charAt(i));
            }
            return array;
        }
    
    
        private void writeBuffer() {
    
    
            String valueAux = "";
    
    
            for (String element2 : buffer) {
                valueAux += element2;
            }
            setValue(valueAux);
        }
    }

  2. #2
    Sencha Premium Member
    Join Date
    Sep 2007
    Posts
    13,976

    Default

    Please take a look at this page: http://www.quirksmode.org/dom/events/index.html

  3. #3
    Sencha User
    Join Date
    May 2011
    Location
    Illinois
    Posts
    32

    Default

    I believe it's possible that I should have rephrased my question. It's not necessarily the onKeyPress method that is causing my issues but the getKeyCode method from the FieldEvent.

    The code
    int k = fe.getKeyCode();

    always returns 0 in FireFox inside the onKeyPress method. The same code within the onKeyDown method works identically to IE, which is fine.

    My code allows for the differences in the onKeyPress method from the site that you linked, but the information retrieved from the getKeyCode method is different, and I am not understanding why or how to fix it.

  4. #4
    Sencha User
    Join Date
    May 2011
    Location
    Illinois
    Posts
    32

    Default

    Is there any reasoning that the following code differs in output between FF and IE?

    Code:
    @Override
    protected void onKeyDown(FieldEvent fe) {
            
        int k = fe.getKeyCode();
            
        System.out.println("KeyDown: " + k);
    }
    
    @Override
    protected void onKeyPress(FieldEvent fe) {
            
        int k = fe.getKeyCode();
            
        System.out.println("KeyPress: " + k);
    }
    The output in IE looks like this for pressing the '5' key on the number pad:
    KeyDown: 101
    KeyPress: 53

    The output in FF looks like this for pressing the '5' key on the number pad:
    KeyDown: 101
    KeyPress: 0

    The output for the fe.getKeyCode() method inside the onKeyPress method in FF is ALWAYS 0. Is there a reason for this and more importantly, how can I get around it?

  5. #5
    Sencha User
    Join Date
    Feb 2009
    Location
    Minnesota
    Posts
    2,737

    Default

    In addition to the quirksmode page sven listed, I offer http://www.quirksmode.org/js/keys.html. They point out that FF does indeed return 0 for keycode on the keypress event. They then go on to suggest using charCode if available, and keyCode if it isn't.

    Again, following that chart, keyCode is suggested to be consistent cross browser if you use the KeyDown event. This has been my experience, that sticking with KeyDown, and checking the keyCode value is enough to get a feature to work cross browser.

  6. #6
    Sencha User
    Join Date
    May 2011
    Location
    Illinois
    Posts
    32

    Default

    Thank you for the additional link, it helps clarify the issue that I was having. I have implemented a pretty nifty, although nasty, hack for my situation. I cannot use the charCode in the keyPress event, so I grabbed the keyCode from the keyDown event and passed it through a switch statement in the keyPress event to convert it to the correct numbers needed.

    I never said it was pretty.

    Thank you,

    Joshua

  7. #7
    Sencha User
    Join Date
    Feb 2009
    Location
    Minnesota
    Posts
    2,737

    Default

    Is there a reason to not use just the keydown event, and to ignore the keypress entirely? As far as I can tell, keydown is essentially the same as keypress, except that it occurs earlier.

  8. #8
    Sencha User WesleyMoy's Avatar
    Join Date
    Oct 2009
    Location
    Redwood City, California
    Posts
    402

    Default

    First off, why is it that you need both the keyPress keyCode and the keyDown keyCode? If you just want to know which key was pressed, keyDown is sufficient and works correctly across all browsers.

    Nevertheless, what you want to do is possible.

    When you retrieve the key code from an event, the key code comes from the underlying JavaScript event object. As a result, you are exposed to any browser inconsistencies in generating these events. This is why testing in Firefox yields different results. See http://www.quirksmode.org/js/keys.html.

    If you want to know which physical key is pressed, you can use the key code in onKeyDown like you're doing now. If you want to know which character was actually entered into the field, you can use the key code in onKeyPress. In your example, the key on the keyboard is numbered 101, whereas the ASCII code for digit "5" is 53. I'm assuming this is why you need the key code for both onKeyDown and onKeyPress.

    While Firefox doesn't support finding the ASCII code by retrieving the key code, it does support finding this information by looking up its char code. Thus, your best bet is to find either the char code or the key code directly from the native event. Here's a modified version of your last example:

    Code:
    @Override
    protected void onKeyDown(FieldEvent fe) {
       int k = fe.getKeyCode();
       System.out.println("KeyDown: " + k);
    }
    
    @Override
    protected void onKeyPress(FieldEvent fe) {
       int k = getCharCode(fe.getEvent()) // passes the native event
       System.out.println("KeyPress: " + k);
    }
    
    private static native int getCharCode(NativeEvent event) /*-{
       return event.charCode || event.keyCode;
    }-*/;
    In browsers that support event.charCode (Firefox, Safari, Chrome), event.charCode will be populated with the right value, and this value will be returned. In the other browsers (IE, Opera), [font]event.charCode[/font] will be undefined, so event.keyCode will be returned instead.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •