使用javascript捕获在android虚拟键盘上键入的键
Posted
技术标签:
【中文标题】使用javascript捕获在android虚拟键盘上键入的键【英文标题】:Capture keys typed on android virtual keyboard using javascript 【发布时间】: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
感谢有关此问题的任何帮助..
【问题讨论】:
此处记录的 android 错误:bugs.chromium.org/p/chromium/issues/detail?id=118639 【参考方案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()
,并且您可能必须收听所有input
、keyup
、change
和beforeinput
,以确保获得所有修改的事件。某些具有预测 IME 的设备不会触发任何 keyup
事件,input
和 change
可能会或可能不会在 IME 输入后立即触发,beforeinput
可能还没有得到足够广泛的支持。根据我的经验,每次更改都会触发其中至少一个事件,因此监听所有这些事件并应用节流可能是最佳选择。以上是关于使用javascript捕获在android虚拟键盘上键入的键的主要内容,如果未能解决你的问题,请参考以下文章