KeyboardEvent对象(键盘事件),更改键值

最近搞一个项目中,有个这样的需求,遥控器按键的键值,在页面上没有响应。追其原因是遥控器发送的键值和页面中应做反应的键值不对应。这就导致页面无响应的状态。
坑的点就是页面上的代码是第三方的,不受我们控制,我们能做到的就只能在安卓中更改键值,在把键值映射到页面上去。还好在这一层,可提供一个js文件,可对其映射进行操作。

这里我将主要记录以达目标的代码过程,其中会介绍一些知识点。

先说一下负责安卓的同事的一段代码:

wv.loadUrl(“javascript:$(document).trigger({type:’keydown’,keyCode:27});”);
这里面的 js 代码明显看出是 jQuery 的写法。而现在第三方的页面中根本就没有加载jquery的文件。所以这种写法就不会生效。
改成原生js的写法:
wv.loadUrl(“javascript:document.onkeydown({type:’keydown’,keyCode:27})”);
这样就会对键值的keyCode值进行改变了。
然后。。。发现第三方页面中有对按键的 event 对象进行操作,如果这样映射键值的话,那么 event 对象就消失了。
该怎样才能既更改键值又不使 event 消失呢。

此时 KeyboardEvent 华丽的登场了!
KeyboardEvent 对象描述了键盘的交互方式。事件类型:keydown, keypress, keyup。

接着就想在那个js文件中再把这个键值转一下吧,而且还要保留 event 对象。
在我的 js 文件中声明一个 my_onkeydown 的函数。
此处先记录一下安卓同事更改后的代码为:wv.loadUrl(“javascript:document.my_onkeydown({type:’keydown’,keyCode:27})”);
然后记录 js 文件中的代码历程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
document.my_onkeydown = function(e){
console.log(e.keyCode);
/**
* 最终触发事件的对象
* IE用fireEvent触发,
* 非IE尝试使用createEvent创建事件对象后,分配给目标进行模拟
* **/
if(document.fireEvent && typeof document.fireEvent == 'function')
{
target.fireEvent('onkeydown');
}
else if(document.createEvent && typeof document.createEvent == 'function')
{
//创建 KeyboardEvent 对象
var eventObject = document.createEvent('KeyboardEvent');
//初始化一个 KeyboardEvent 对象
//这里注意一下,我自己测试的时候 27 的位置是 e.keyCode;此处这么写实为了方便解释
eventObject.initKeyboardEvent(e.type,true, true,document.defaultView,false,false,false,false,27,0);
//给 document 节点分配一个合成事件
document.dispatchEvent(eventObject);
}
}
document.onkeydown = function(event)
{
console.log(event)
console.log(event.type)
console.log(event.preventDefault)
console.log(event.keyCode)
}

上面代码中,解释一下 eventObject.initKeyboardEvent(e.type,true, true,document.defaultView,false,false,false,false,27,0); 这句话。

event.initKeyEvent(type,bubbles,cancelable,viewArg,ctrlKeyArg,altKeyArg,shiftKeyArg,metaKeyArg,keyCodeArg,charCodeArg);

参数:
type : (string) 要触发的事件类型,如“keydown”;
bubbles : (boolean) 事件是否冒泡;
cancelable : (boolean) 事件是否可以被取消;
viewArg : (abstractView) 被授予事件的视图,通常为 document.defaultView,也可为 null;
ctrlKeyArg : (boolean) ctrl 键是否被按下,默认:false;
altKeyArg : (boolean) alt 键是否被按下,默认:false;
shiftKeyArg : (boolean) shift 键是否被按下,默认:false;
metaKeyArg : (boolean) meta 键是否被按下,默认:false;
keyCodeArg : (integer) 键按下或释放时所对应的键码,默认 0;
charCodeArg : (integer) 按下的键的字符所对应的 ASCII code,默认 0;

知识点过后,说现象,真是呵呵哒了,打印的 event.keyCode 值是 0 而非传入的 27。
失败的原因是 keyCode 的属性是不可配置/更改的。
那自然就会想到从原型下手,下面是我的两个解决方案的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//方案一:
document.my_onkeydown = function(e){
console.log(e.keyCode);
/**
* 最终触发事件的对象
* IE用fireEvent触发,
* 非IE尝试使用createEvent创建事件对象后,分配给目标进行模拟
* **/
if(document.fireEvent && typeof document.fireEvent == 'function')
{
target.fireEvent('onkeydown');
}
else if(document.createEvent && typeof document.createEvent == 'function')
{
//创建 KeyboardEvent 对象
var eventObject = document.createEvent('KeyboardEvent');
//初始化一个 KeyboardEvent 对象
eventObject.initKeyboardEvent(e.type,true, true,document.defaultView,false,false,false,false,e.keyCode,0);
//先删掉原来的 keyCode 的属性
delete eventObject.keyCode;
//重新定义 keyCode 的属性,且属性值为传过来的值
Object.defineProperty(eventObject,"keyCode",{"value":e.keyCode});
//给 document 节点分配一个合成事件
document.dispatchEvent(eventObject);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//方案二:(跟方案一思路相同,只是实现代码不同)
document.my_onkeydown = function(e){
console.log(e.keyCode);
/**
* 最终触发事件的对象
* IE用fireEvent触发,
* 非IE尝试使用createEvent创建事件对象后,分配给目标进行模拟
* **/
if(document.fireEvent && typeof document.fireEvent == 'function')
{
target.fireEvent('onkeydown');
}
else if(document.createEvent && typeof document.createEvent == 'function')
{
//实例化一个 KeyboardEvent 对象
var eventObject = new KeyboardEvent("keydown", {bubbles:true,view:document.defaultView});
//重新定义 keyCode 的属性,且属性值为传过来的值
Object.defineProperty(eventObject, 'charCode', {get:function(){return e.keyCode;}});
Object.defineProperty(eventObject, 'keyCode', {get:function(){return e.keyCode;}});
//给 document 节点分配一个合成事件
document.dispatchEvent(eventObject);
}
}

呀呀呀!再次测试,成功了呢!欢迎吐槽。。。

好吧,为了方便测试,附上我测试时代替安卓同事的代码:

1
2
3
4
5
//也是在js文件中
document.getElementById("key").onclick = function()
{
document.my_onkeydown({type:'keydown',keyCode:27});
}

也别忘了 html 中的代码

1
<button id="key">点击测试键值</button>

好了,可以测试看看了。@_@