【问题标题】:Capture keys typed on android virtual keyboard using javascript使用javascript捕获在android虚拟键盘上键入的键
【发布时间】:2015-08-24 22:43:27
【问题描述】:

我有一个带有文本区域的网页,我需要捕获用户键入的键(以便我可以用不同的 unicode 字符替换键入的键)。我目前的代码如下:

$("#myTextArea").bind('keypress', function(event) {

    var keyInput = event.which;
   // call other functions

});

以上代码适用于 PC 和 iPhone/Safari。但是,在 android(三星)平板电脑上使用 Chrome 时会失败。出于某种原因,当我在 android 虚拟(软)键盘上键入时,不会触发“keypress”事件。安卓版本是5.0.2。

如果我尝试使用 "keyUp" 或 "keyDown",它总是为所有字符返回 229(返回键、空格、退格等除外)。

即使 keyCode 始终为 229,文本区域仍会显示用户键入的正确字符。这意味着设备知道输入了哪个密钥,但不知何故我无法使用 javascript 处理此事件(和密钥代码)。

以下是我迄今为止尝试过的替代方案及其结果:

$("#mainTextArea").on("keydown keyup", function(event) { 
    // event.which and event.keyCode both return 229

$(document).on('keypress', function(event) { 
    // function is not triggered

$('#myTextArea').bind('input keypress', function(event) { 
   // comes inside function, but keyCode and which are undefined

感谢有关此问题的任何帮助..

【问题讨论】:

标签: javascript android jquery samsung-mobile


【解决方案1】:

不幸的是,您似乎在这里无能为力。 Keypress 事件已被弃用,因此不会被触发。 keyup 和 keydown 上的 229 表示键盘缓冲区正忙。原因——当你按下一个键——输入仍然不能保证是用户按下的,因为自动建议和其他事件可能会立即发生并使事件无效。 虽然在我看来,最好先发送密钥,然后在自动建议上触发另一个事件,以便您可以单独对其采取行动......

我目前知道的唯一一件事是附加到 keydown 和 keyup,将值存储在 keydown 上,获取 keyup 上的值并找到用户按下的增量。不幸的是,这不适用于非输入控件(例如 - 身体或类似的东西)。 也许不是你想听到的答案,但仍然如此。

【讨论】:

  • oninput 确实有效,但它没有相同的功能。至少在我的情况下,用 oninput 代替 keypress 真的很难。
  • 不幸的是。不过,我不确定是否有更好的解决方案。
  • @PavelDonchev 请看我的回答
【解决方案2】:

我遇到了同样的问题。有几种解释,但无论如何,没有提供解决方案似乎很奇怪。 目前我通过捕获oninput 事件解决了这个问题。

"这个事件和onchange事件类似,不同的是oninput事件是在元素的值发生变化后立即发生,而onchange是在元素失去焦点、内容发生变化后发生"

此事件也支持插入文本,来自粘贴文本或更正和建议。

它没有给我完美的解决方案,因为我只能在输入文本后对其进行操作,但目前它是我所拥有的最好的。

如果有人有更好的解决方案,我会很高兴听到的。

【讨论】:

    【解决方案3】:

    我在为我正在从事的项目进行研究时遇到了这个讨论。我必须为移动应用程序创建输入掩码,Pavel Donchev's answer 让我思考如何在 Android 中捕获键。在我的特定项目中,keydown 和 keyup 是不够的,因为 keyup 事件仅在释放密钥后触发,因此这意味着验证较晚,因此我对输入事件进行了更多研究(以及大量试验和错误)并让它工作。

    var input = document.getElementById('credit-card-mask'),
        oldValue,
        newValue,
        difference = function(value1, value2) {
          var output = [];
          for(i = 0; i < value2.length; i++) {
            if(value1[i] !== value2[i]) {
              output.push(value2[i]);
            }
          }
          return output.join("");
        },
        keyDownHandler = function(e) {
          oldValue = input.value;
          document.getElementById("onkeydown-result").innerHTML = input.value;
        },
        inputHandler = function(e) {
          newValue = input.value;
          document.getElementById("oninput-result").innerHTML = input.value;
          document.getElementById("typedvalue-result").innerHTML = difference(oldValue, newValue);
        }
    ;
    
    input.addEventListener('keydown', keyDownHandler);
    input.addEventListener('input', inputHandler);
    <input type="text" id="credit-card-mask" />
    <div id="result">
      <h4>on keydown value</h4>
      <div id="onkeydown-result"></div>
      <h4>on input value</h4>
      <div id="oninput-result"></div>
      <h4>typed value</h4>
      <div id="typedvalue-result"></div>
    </div>

    oninput 事件在 keydown 事件之后立即触发,这是我验证的最佳时机。

    我在一篇文章中整理了整个内容。如果你好奇,可以阅读here

    【讨论】:

    • 在堆栈溢出时不鼓励仅链接答案。请在您的回答中添加简要说明。
    【解决方案4】:

    只需检查您输入的字符 keyCode,如果是 0 或 229,那么这里是函数 getKeyCode(),它使用 JS 的 charCodeAt 返回接受输入的 KeyCode字符串一个参数并返回最后一个字符的键码。

    <script>
            var getKeyCode = function (str) {
                return str.charCodeAt(str.length);
            }
    
    
            $('#myTextfield').on('keyup',function(e){
    
                //for android chrome keycode fix
                if (navigator.userAgent.match(/Android/i)) {
    
                    var inputValue = this.value;
    
                    var charKeyCode = e.keyCode || e.which;
                    if (charKeyCode == 0 || charKeyCode == 229) { 
                        charKeyCode = getKeyCode(inputValue);
                        alert(charKeyCode+' key Pressed');
                    }else{
                       alert(charKeyCode+' key Pressed');
                        }
                }       
            });
        </script>
    

    【讨论】:

    • 如果我们在文本框之间的某处输入文本,这将失败
    • @ImamudinNaseem 是的,在这种情况下,我们将不得不修改与场景匹配的代码。但 AFAIK 这是您可以与虚拟键盘的按键交互以获取键值的唯一方法
    • AkshayTilekar,酷 :)
    • @ImamudinNaseem :)
    • 这甚至不是一个解决方案。如果我没有在输入框的末尾输入怎么办。
    【解决方案5】:

    有一个textInput 事件为您提供输入的字符

    const inputField = document.getElementById('wanted-input-field');
    
    inputField.addEventListener('textInput', function(e) {
        // e.data will be the 1:1 input you done
        const char = e.data; // In our example = "a"
    
        // If you want the keyCode..
        const keyCode = char.charCodeAt(0); // a = 97
    
        // Stop processing if "a" is pressed
        if (keyCode === 97) {
            e.preventDefault();
            return false;
        }
        return true;
    });
    

    【讨论】:

      【解决方案6】:

      我最近在我们的 Astro AI 辅助电子邮件应用程序的最新版本中实现了“提及”功能。基本上,您在我们的撰写网页视图中键入“@”,您会得到一个自动完成建议的列表。像大多数其他人一样,我们在尝试用 Javascript 解决这个问题时遇到了问题。最终奏效的是本机解决方案。如果你@Override WebView 的 onCreateInputConnection() 方法,你可以用自定义类包装 super.onCreateInputConnection() 结果(它只是一个 InputConnection 接口)。然后在你的包装器实现中,你可以通过 commitText() 或 setComposingText() 或者其他一些特定于你正在寻找的方法来捕获输入......比如删除。我不知道您是否会在控制字符(例如向上和向下箭头)上获得任何回调,但也许这可以作为开始解决您的特定问题的地方。

      【讨论】:

        【解决方案7】:

        我想通了!

        这是一个 100% 有效的解决方案,可在任何地方使用所有功能,甚至包括 iOS 上的表情符号建议和任何粘贴的内容。我正在使用子字符串比较来查找从 onInput 更改为 onInput 的实际内容。

        指出删除文本和插入文本的点。

        赞赏并选择作为答案。

        var x = document.getElementById("area"),
            text = x.value,
            event_count = 0
        
        
        
        function find_Entered_And_Removed_Substrings(
            previous_string, current_string, pos
        ) {
            let
                right_pos = pos,
                right_boundary_of_removed =
                    previous_string.length -
                    (
                        current_string.length -
                        pos
                    ),
                left_max_pos = Math.min(
                    pos,
                    right_boundary_of_removed
                ),
                left_pos = left_max_pos
        
            for (
                let x = 0; x < left_max_pos; x++
            ) {
                if (
                    previous_string[x] !==
                    current_string[x]
                ) {
                    left_pos = x
                    break
                }
            }
        
        
            return {
                left: left_pos,
                right: pos,
                removed_left: left_pos,
                removed_right: right_boundary_of_removed
            }
        }
        
        x.oninput =
            (e) => {
                // debugger;
                let
                    cur_text = x.value,
                    positions =
                        find_Entered_And_Removed_Substrings(
                            text, cur_text, Math.max(
                                x.selectionStart, x.selectionEnd
                            )
                        )
                console.log(positions)
                let
                    entered =
                        cur_text.substring(
                            positions.left, positions.right
                        ),
                    removed =
                        text.substring(
                            positions.removed_left, positions.removed_right
                        )
        
        
                if (
                    entered.length >
                    0 ||
                    removed.length >
                    0
                ) {
                    document.getElementById("entered")
                        .innerHTML +=
                        entered
        
                    document.getElementById("removed")
                        .innerHTML +=
                        removed
        
                    document.getElementById("events")
                        .innerHTML =
                        event_count++
                }
        
        
                text = cur_text
            }
        <textarea id="area"></textarea>
        <br/>
        <pre id="entered"></pre>
        <br/>
        <div id="events"></div>
        <pre id="removed"></pre>

        【讨论】:

        • 感谢用户投票反对此答案的评论。
        • 我猜原因是:格式错误(不常用),根本不可读!调试代码(调试器、console.log)
        • 看起来它不能处理用户在字符串中间输入文本的用例。如果有人试图修正错字,此代码将失败
        • 例如,输入'1245',然后尝试在2之后添加3。
        • 我猜问题是oninput 不够好。您应该改用addEventListener(),并且您可能必须收听所有inputkeyupchangebeforeinput,以确保获得所有修改的事件。某些具有预测 IME 的设备不会触发任何 keyup 事件,inputchange 可能会或可能不会在 IME 输入后立即触发,beforeinput 可能还没有得到足够广泛的支持。根据我的经验,每次更改都会触发其中至少一个事件,因此监听所有这些事件并应用节流可能是最佳选择。
        猜你喜欢
        • 1970-01-01
        • 2012-09-30
        • 2010-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多