The source code

    /**
     * @ignore
     *  inspired by yui3
     * Synthetic event that fires when the <code>value</code> property of an input
     * field or textarea changes as a result of a keystroke, mouse operation, or
     * input method editor (IME) input event.
     *
     * Unlike the <code>onchange</code> event, this event fires when the value
     * actually changes and not when the element loses focus. This event also
     * reports IME and multi-stroke input more reliably than <code>oninput</code> or
     * the various key events across browsers.
     *
     * @author yiminghe@gmail.com
     */
    KISSY.add('event/dom/base/valuechange', function (S, Event, DOM, special) {
        var VALUE_CHANGE = 'valuechange',
            getNodeName = DOM.nodeName,
            KEY = 'event/valuechange',
            HISTORY_KEY = KEY + '/history',
            POLL_KEY = KEY + '/poll',
            interval = 50;

        function clearPollTimer(target) {
            if (DOM.hasData(target, POLL_KEY)) {
                var poll = DOM.data(target, POLL_KEY);
                clearTimeout(poll);
                DOM.removeData(target, POLL_KEY);
            }
        }

        function stopPoll(target) {
            DOM.removeData(target, HISTORY_KEY);
            clearPollTimer(target);
        }

        function stopPollHandler(ev) {
            clearPollTimer(ev.target);
        }

        function checkChange(target) {
            var v = target.value,
                h = DOM.data(target, HISTORY_KEY);
            if (v !== h) {
                // allow delegate
                Event.fireHandler(target, VALUE_CHANGE, {
                    prevVal: h,
                    newVal: v
                });
                DOM.data(target, HISTORY_KEY, v);
            }
        }

        function startPoll(target) {
            if (DOM.hasData(target, POLL_KEY)) {
                return;
            }
            DOM.data(target, POLL_KEY, setTimeout(function () {
                checkChange(target);
                DOM.data(target, POLL_KEY, setTimeout(arguments.callee, interval));
            }, interval));
        }

        function startPollHandler(ev) {
            var target = ev.target;
            // when focus ,record its current value immediately
            if (ev.type == 'focus') {
                DOM.data(target, HISTORY_KEY, target.value);
            }
            startPoll(target);
        }

        function webkitSpeechChangeHandler(e) {
            checkChange(e.target);
        }

        function monitor(target) {
            unmonitored(target);
            Event.on(target, 'blur', stopPollHandler);
            // fix #94
            // see note 2012-02-08
            Event.on(target, 'webkitspeechchange', webkitSpeechChangeHandler);
            Event.on(target, 'mousedown keyup keydown focus', startPollHandler);
        }

        function unmonitored(target) {
            stopPoll(target);
            Event.remove(target, 'blur', stopPollHandler);
            Event.remove(target, 'webkitspeechchange', webkitSpeechChangeHandler);
            Event.remove(target, 'mousedown keyup keydown focus', startPollHandler);
        }

        special[VALUE_CHANGE] = {
            setup: function () {
                var target = this, nodeName = getNodeName(target);
                if (nodeName == 'input' || nodeName == 'textarea') {
                    monitor(target);
                }
            },
            tearDown: function () {
                var target = this;
                unmonitored(target);
            }
        };
        return Event;
    }, {
        requires: ['./api', 'dom', './special']
    });

    /*
     2012-02-08 yiminghe@gmail.com note about webkitspeechchange :
     当 input 没焦点立即点击语音
     -> mousedown -> blur -> focus -> blur -> webkitspeechchange -> focus
     第二次：
     -> mousedown -> blur -> webkitspeechchange -> focus
     */