<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>army8735 &#187; 大写锁定键提示</title>
	<atom:link href="http://army8735.org/tag/%e5%a4%a7%e5%86%99%e9%94%81%e5%ae%9a%e9%94%ae%e6%8f%90%e7%a4%ba/feed" rel="self" type="application/rss+xml" />
	<link>http://army8735.org</link>
	<description>我可以A，我也可以-A，我可以同时A和-A。</description>
	<lastBuildDate>Fri, 25 Nov 2011 04:07:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>密码输入框之大写锁定键提示</title>
		<link>http://army8735.org/2009/09/15/82.html</link>
		<comments>http://army8735.org/2009/09/15/82.html#comments</comments>
		<pubDate>Tue, 15 Sep 2009 06:38:33 +0000</pubDate>
		<dc:creator>army8735</dc:creator>
				<category><![CDATA[as、flex]]></category>
		<category><![CDATA[前端开发]]></category>
		<category><![CDATA[用户体验设计]]></category>
		<category><![CDATA[大写锁定键提示]]></category>

		<guid isPermaLink="false">http://army.512j.com/blog/?p=82</guid>
		<description><![CDATA[紧接上篇，正太米想要八抬大轿明媒正娶回大家闺秀——Canon IXUS 95  IS，得先准备好聘礼。凑巧今日同住的一只loli（同学的GF，非闪光弹）要过生日，早先曾说过把淘宝上某个商店的泰迪熊送给她，可是却没有银行卡给支付宝付款。今日试了下拉卡拉，很是便捷，只是要付手续费……
 充值之后，正太米兴奋地要登录淘宝，输入密码时突然发现页面提示大写锁定键打开了！幸好咱及时更正，要不然又要白输一遍了。记得以前英俊（EyesOnline）曾说过我们能不能也弄一个这样的提示功能，来提升用户体验？俺回答说淘宝人家是装了本地插件才能检测CapsLock，一般页面可没有办法。
时过境迁，如今正太米功力大增，思路扩展也今非昔比，于是乎一款网页版大写锁定键提示功能的想法跃然纸上……
为什么一般页面很难做到？
想要拥有大写锁定键提示功能，很显然，假如安装了本地插件那么键盘相应的状态自然很容易就侦测到了，做出提示功能水到渠成。而想基于网页的话，js还没有足够强大的能力来应付，只能做到一点点：在密码框按键或输入时侦测按键代码。凭此想要弄出相同功能的大写锁定键提示的话，明显是不可能的，只有另辟蹊径了。

跳出局限思维
既然js不能胜任，那么flash呢？目前网页上可用的技术有很多，但普遍的无非这两种：js和as。as是有能力检测大写锁定键的（flash.ui.Keyboard类），那么我们便可借助它来完成。
不过这里有个难题，那就是flash  player想要检测按键，必须在激活的状态下才行。也就是说密码输入框需要做成flash，这可是我们不愿意看到的，那么有其它的办法吗？
解决之道
问题的回答是：当然有！结合js和as来做的话，这一问题便迎刃而解！可是有人又要问了：假如用户没有安装flash  player 9及以上的怎么办，或者版本太低怎么办（即使fp9的普及率已经相当高）？不要急，综合考虑的结果是为安装flash player  9及以上版本的人提供全面的大写锁定键检测功能，没有安装的提供部分检测功能，如此便完善了很多。>
详细思路
首先用户分为2种：安装flash player 9及以上版本的和没有安装的。
 假如安装了的用户在密码输入框输入密码时，onfocus和每个按键都会被侦测，一旦按键的keyCode是20（CapsLock的键值），那么便会通过ExternalInterface调用as3的接口，判断Keyboard.capsLock的值true或false，再回调js函数来显示或隐藏提示框。当然做这一切之前需要将焦点移至flash上，做完之后焦点移回密码框。
假如没有安装的用户只能部分体验到它的功能。依旧我们会侦听按键的onkeydown和onkeypress，两者区别是前一个包括功能键，后一个只侦测输入。并且我们设置了一个mode变量以区分大写锁定键为打开、关闭以及未知的情况。这样在已知mode的情况下，按下CapsLock键就能知晓其是否被打开了；而未知mode的情况下就需判断输入的字母的大小写并且是否同时按下了shift键来判断是否给予大写锁定键提示。
/wp-content/web/2009/09/capslock/index.html

具体代码
var bFlash = (function(){
	var...]]></description>
			<content:encoded><![CDATA[<p><span style="font-family: 楷体_GB2312;">紧接上篇，正太米想要八抬大轿明媒正娶回大家闺秀——Canon IXUS 95  IS，得先准备好聘礼。凑巧今日同住的一只loli（同学的GF，非闪光弹）要过生日，早先曾说过把淘宝上某个商店的泰迪熊送给她，可是却没有银行卡给支付宝付款。今日试了下拉卡拉，很是便捷，只是要付手续费……</span></p>
<p> <span style="font-family: 楷体_GB2312;">充值之后，正太米兴奋地要登录淘宝，输入密码时突然发现页面提示大写锁定键打开了！幸好咱及时更正，要不然又要白输一遍了。记得以前英俊（EyesOnline）曾说过我们能不能也弄一个这样的提示功能，来提升用户体验？俺回答说淘宝人家是装了本地插件才能检测CapsLock，一般页面可没有办法。</span></p>
<p><span style="font-family: 楷体_GB2312;">时过境迁，如今正太米功力大增，思路扩展也今非昔比，于是乎一款网页版大写锁定键提示功能的想法跃然纸上……</span></p>
<p><strong>为什么一般页面很难做到？</strong></p>
<p>想要拥有大写锁定键提示功能，很显然，假如安装了本地插件那么键盘相应的状态自然很容易就侦测到了，做出提示功能水到渠成。而想基于网页的话，js还没有足够强大的能力来应付，只能做到一点点：在密码框按键或输入时侦测按键代码。凭此想要弄出相同功能的大写锁定键提示的话，明显是不可能的，只有另辟蹊径了。</p>
<p><img class="aligncenter size-full wp-image-83" title="capslock1" src="http://army.512j.com/blog/wp-content/uploads/2009/09/capslock1.gif" alt="capslock1" width="404" height="272" /></p>
<p><strong>跳出局限思维</strong></p>
<p>既然js不能胜任，那么flash呢？目前网页上可用的技术有很多，但普遍的无非这两种：js和as。as是有能力检测大写锁定键的（flash.ui.Keyboard类），那么我们便可借助它来完成。</p>
<p>不过这里有个难题，那就是flash  player想要检测按键，必须在激活的状态下才行。也就是说密码输入框需要做成flash，这可是我们不愿意看到的，那么有其它的办法吗？</p>
<p><strong>解决之道</strong></p>
<p>问题的回答是：当然有！结合js和as来做的话，这一问题便迎刃而解！可是有人又要问了：假如用户没有安装flash  player 9及以上的怎么办，或者版本太低怎么办（即使fp9的普及率已经相当高）？不要急，综合考虑的结果是为安装flash player  9及以上版本的人提供全面的大写锁定键检测功能，没有安装的提供部分检测功能，如此便完善了很多。></p>
<p><strong>详细思路</strong><br />
首先用户分为2种：安装flash player 9及以上版本的和没有安装的。</p>
<p> 假如安装了的用户在密码输入框输入密码时，onfocus和每个按键都会被侦测，一旦按键的keyCode是20（CapsLock的键值），那么便会通过ExternalInterface调用as3的接口，判断Keyboard.capsLock的值true或false，再回调js函数来显示或隐藏提示框。当然做这一切之前需要将焦点移至flash上，做完之后焦点移回密码框。</p>
<p>假如没有安装的用户只能部分体验到它的功能。依旧我们会侦听按键的onkeydown和onkeypress，两者区别是前一个包括功能键，后一个只侦测输入。并且我们设置了一个mode变量以区分大写锁定键为打开、关闭以及未知的情况。这样在已知mode的情况下，按下CapsLock键就能知晓其是否被打开了；而未知mode的情况下就需判断输入的字母的大小写并且是否同时按下了shift键来判断是否给予大写锁定键提示。</p>
<p><a href="/wp-content/web/2009/09/capslock/index.html">/wp-content/web/2009/09/capslock/index.html</a></p>
<p><img class="aligncenter size-full wp-image-84" title="capslock2" src="http://army.512j.com/blog/wp-content/uploads/2009/09/capslock2.gif" alt="capslock2" width="482" height="58" /></p>
<p><strong>具体代码</strong></p>
<pre class="brush:js">var bFlash = (function(){
	var version = ($try(function(){
		return navigator.plugins['Shockwave Flash'].description;
	}, function(){
		return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
	}) || '0 r0').match(/\d+/g);
	return (parseInt(version[0] || 0 + '.' + version[1], 10) || 0) >= 9;
})();

var oPass = document.getElementById("pass");
var oTips = document.getElementById("tips");
var oSwf = null;
var sLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var iMode = 0; //0未知，1小写，2大写

function $try(){
	for (var i = 0, l = arguments.length; i < l; i++){
		try {
			return arguments[i]();
		} catch(e){}
	}
	return null;
}
function getSwf() {
	if (navigator.appName.indexOf("Microsoft") != -1)
		oSwf = window["capslock"];
	else
		oSwf = document["capslock"];
	oPass.disabled = false;
}
function warning() {
	oTips.innerHTML = "请注意，您的大写锁定键已打开！";
	oTips.style.display = "block";
}
function hide() {
	oTips.innerHTML = "";
	oTips.style.display = "none";
}

var bFocus = false;
oPass.onfocus = function() {
	if(bFocus) {
		return;
	}
	if(oSwf) {
		oSwf.focus();
		oSwf.capslock();
		setTimeout(function(){
			bFocus = true;
			oPass.focus();
		},0);
	}
}
oPass.onblur = function() {
	bFocus = false;
}
oPass.onkeydown = function(event) {
	event = event || window.event;
	var keyCode = event.keyCode;
	if(keyCode == 20) {
		if(bFlash) {
			oSwf.focus();
			oSwf.capslock();
			oPass.focus();
		}
		else if(iMode == 1) {
			warning();
		}
		else if(iMode == 2) {
			hide();
		}
	}
}
oPass.onkeypress = function(event) {
	if(!oSwf) {
		event = event || window.event;
		var origin = oPass.value;
		var c;
		setTimeout(function() {
			var now = oPass.value;
			for(var i = 0, length = Math.min(origin.length, now.length); i < origin; i++) {
				if(origin.charAt(i) !== now.charAt(i)) {
					c = now.charAt(i);
					break;
				}
			}
			if(!c) {
				c = now.charAt(now.length - 1);
			}
			if(sLetters.indexOf(c) > -1) {
				if(event.shiftKey) {
					iMode = 1;
					hide();
				}
				else {
					iMode = 2;
					warning();
				}
			}
			else if(sLetters.toLowerCase().indexOf(c) > -1) {
				if(event.shiftKey) {
					iMode = 2;
					warning();
				}
				else {
					iMode = 1;
					hide();
				}
			}
		}, 0);
	}
}

if(!bFlash) {
	oPass.disabled = false;
}</pre>
<pre class="brush:as">package {
	import flash.display.Sprite;
	import flash.ui.Keyboard;
	import flash.external.ExternalInterface;

	public class Main extends Sprite {
		public function Main():void {
			if (ExternalInterface.available) {
				ExternalInterface.addCallback("capslock", onCapsLockHandler);
				ExternalInterface.call("getSwf");
			}
		}
		public function onCapsLockHandler():void {
			if (Keyboard.capsLock) {
				if (ExternalInterface.available) {
					ExternalInterface.call("warning");
				}
			}
			else {
				if (ExternalInterface.available) {
					ExternalInterface.call("hide");
				}
			}
		}
	}
}</pre>
<p><strong>后话</strong></p>
<p>当然，其中不完善之处甚多，比如用以获取用户输入的字母是用了延迟侦听，而非获取索引范围之类的办法（因为这方面偶的标准化还不熟），希望你能提出更好的建议。而且fp9以后本地浏览会出现跨域安全性限制，这让测试非常麻烦，所以正太米一直使用maxthon浏览器，它能够在本地环境下跳过这个限制，我也不清楚这是为什么……</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2009/09/15/82.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

