最近开发的一个项目要用到单键快捷键, 遂写了个快捷键管理类.
目前能满足需求, 使用方便, 开放出来, 欢迎大家拍砖 :D
主要功能:
- 各快捷键可对应多个方法
- 各快捷键可分别绑定 KeyUp 或 KeyDown 事件
- 已"快捷键+事件+方法"确定某绑定, 均可单独注册/反注册
下面是代码 (Shortcut.as) :
package com.douban.utils
{
import flash.display.Stage;
import flash.events.KeyboardEvent;
/**
* 快捷键管理器
* @author Seven Yu
*/
public class Shortcut
{
// 注册/注销快捷键动作
private static const ACTION_ADD:int = 1;
private static const ACTION_DEL:int = -1;
// 保存按键与方法映射
private static var _keyMaps:Object = {};
// 绑定键盘监听的 stage
private static var _stage:Stage;
// 是否开始监听标记 (可以暂停全部监听, 改造成非静态类可以按需暂停/监听)
private static var _started:Boolean = false;
// 事件类型对应方法计数器
private static var _upFuncsCount:int = 0;
private static var _downFuncsCount:int = 0;
/**
* 初始化
* @param stage 绑定键盘事件的 stage
* @param autoStart 自动开始监听 (默认: false)
*/
public static function init(stage:Stage, autoStart:Boolean = false):void
{
_stage = stage;
autoStart && start();
}
/**
* 开始监听键盘事件
*/
public static function start():void
{
if (_stage)
{
_started = true;
}
}
/**
* 停止监听
*/
public static function stop():void
{
_started = false;
}
/**
* 处理快捷键响应
* @param evt
*/
private static function keyHandler(evt:KeyboardEvent):void
{
trace('event type:', evt.type, 'key code:', evt.keyCode);
if (!_started)
{
return;
}
var keyName:String = getKeyName(evt.type, evt.keyCode);
if (keyName in _keyMaps)
{
var funcs:Array = _keyMaps[keyName].concat();
for (var i:int = 0, len:int = funcs.length; i < len; i++)
{
funcs[i]();
}
}
}
/**
* 注册快捷键
* @param keyCode
* @param func
* @param type
*/
public static function register(keyCode:int, func:Function, type:String = KeyboardEvent.KEY_UP):void
{
trace('shortcat.register', keyCode);
var keyName:String = getKeyName(type, keyCode);
if (keyName in _keyMaps)
{
trace(_keyMaps[keyName].indexOf(func));
if (_keyMaps[keyName].indexOf(func) == -1)
{
_keyMaps[keyName].push(func);
checkFuncs(type, ACTION_ADD);
}
}
else
{
_keyMaps[keyName] = [func];
checkFuncs(type, ACTION_ADD);
}
}
/**
* 注销快捷键
* @param keyCode
* @param func
* @param type
*/
public static function unregister(keyCode:int, func:Function, type:String = KeyboardEvent.KEY_UP):void
{
trace('shortcat.unregister', keyCode);
var keyName:String = getKeyName(type, keyCode);
if (keyName in _keyMaps)
{
var funcIndex:int = _keyMaps[keyName].indexOf(func);
if (funcIndex >= 0)
{
_keyMaps[keyName].splice(funcIndex, 1);
checkFuncs(type, ACTION_DEL);
}
}
}
/**
* 检测函数注册数, 以确定绑定或移除事件监听
* @param type 事件类型
* @param action 动作(添加或移除)
*/
private static function checkFuncs(type:String, action:int):void
{
trace('check funcs', type, action);
if (!_stage)
{
throw new Error('Please call Shortcut.init method first.');
}
switch (type)
{
case KeyboardEvent.KEY_UP:
{
_upFuncsCount += action;
if (1 == _upFuncsCount)
{
_stage.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
}
if (0 == _upFuncsCount)
{
_stage.removeEventListener(KeyboardEvent.KEY_UP, keyHandler);
}
break;
}
case KeyboardEvent.KEY_DOWN:
{
_downFuncsCount += action;
if (1 == _downFuncsCount)
{
_stage.addEventListener(KeyboardEvent.KEY_DOWN, keyHandler);
}
if (0 == _downFuncsCount)
{
_stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyHandler);
}
break;
}
default:
{
throw new Error('KeyboardEvent.KEY_UP & KeyboardEvent.KEY_DOWN only.');
break;
}
}
}
/**
* 获取映射名
* @param type 事件类型
* @param keyCode 按键键值
* @return 形如 type_keyCode 的字符串
*/
private static function getKeyName(type:String, keyCode:int):String
{
return [type, keyCode].join('_');
}
/**
* 是否已开始监听
*/
static public function get started():Boolean
{
return _started;
}
}
}
例: (伪代码)
// 初始化快捷键管理器
Shortcut.init(stage, true);
// 注册 空格 + KeyUp + testFunc1 (默认 KeyUp 事件)
Shortcut.register(Keys.SPACEBAR, testFunc1);
// 注册 空格 + KeyDown + testFunc1
Shortcut.register(Keys.SPACEBAR, testFunc1, KeyboardEvent.KEY_DOWN);
// 注册 S + KeyUp + testFunc2
Shortcut.register(Keys.S, testFunc2, KeyboardEvent.KEY_UP);
// 反注册 空格 + KeyUp + testFunc1 (KeyUp 为默认值, 可省略)
Shortcut.unregister(Keys.SPACEBAR, testFunc1, KeyboardEvent.KEY_UP);
// 反注册 E + KeyUp + testFunc2 (不会有任何反映, 该组合没被注册过)
Shortcut.unregister(Keys.E, testFunc2);
// 测试函数1
private function testFunc1():void
{
trace('test function 1');
}
// 测试函数2
private function testFunc2():void
{
trace('test function 2');
}
另外代码中还用到一个 Keys 类, 是对一些键位相应 KeyCode 常量的定义, 直接改成对应的数字即可, 例如: 空格->32, S->83, E->69
可能还有不成熟的地方, 欢迎拍砖, 共同探讨 :D