チェンジセット 2642
- コミット日時:
- 2009/05/15 01:19:55 (3 年前)
- ファイル:
-
- air/TLife/trunk/air/TLife.air (更新) (変更前)
- air/TLife/trunk/air/version.xml (更新) (1 diff)
- air/TLife/trunk/application.xml (更新) (1 diff)
- air/TLife/trunk/bin/TLife.swf (更新) (変更前)
- air/TLife/trunk/bin/initial/config.xml (更新) (3 diffs)
- air/TLife/trunk/src/Main.mxml (更新) (1 diff)
- air/TLife/trunk/src/uwi/thread/InitialMovementThread.as (更新) (3 diffs)
- air/TLife/trunk/src/uwi/thread/MainThread.as (更新) (2 diffs)
- air/TLife/trunk/src/uwi/thread/ReloadThread.as (更新) (1 diff)
- air/TLife/trunk/src/uwi/thread/StreamManageThread.as (追加)
- air/TLife/trunk/src/uwi/thread/event/IncrementalSearchThread.as (更新) (2 diffs)
- air/TLife/trunk/src/uwi/thread/event/PostEventThread.as (更新) (4 diffs)
- air/TLife/trunk/src/uwi/twitter/TwitterPostThread.as (更新) (1 diff)
- air/TLife/trunk/src/uwi/twitter/TwitterShadowGetThread.as (削除)
- air/TLife/trunk/src/uwi/twitter/TwitterSocialGraphGetThread.as (追加)
- air/TLife/trunk/src/uwi/twitter/TwitterStreamFollowGetThread.as (追加)
- air/TLife/trunk/src/uwi/ui/globalconfig/GlobalConfigEventThread.as (更新) (2 diffs)
- air/TLife/trunk/src/uwi/ui/mainmenu/MainMenu.mxml (更新) (4 diffs)
- air/TLife/trunk/src/uwi/ui/mainmenu/MainMenuEventThread.as (更新) (3 diffs)
- air/TLife/trunk/src/uwi/util/CommonData.as (更新) (3 diffs)
- air/TLife/trunk/src/uwi/util/KeyBind.as (更新) (2 diffs)
凡例:
- 変更無し
- 追加
- 削除
- 更新
- コピー
- 移動
air/TLife/trunk/air/version.xml
r2624 r2642 1 1 <version> 2 <version>alpha1 6/version>2 <version>alpha18/version> 3 3 <url>http://www.libspark.org/svn/air/TLife/trunk/air/TLife.air</url> 4 4 </version> air/TLife/trunk/application.xml
r2634 r2642 3 3 4 4 <id>uwi.TLife</id> 5 <version>alpha1 7</version>5 <version>alpha18</version> 6 6 <filename>TLife</filename> 7 7 <name>TLife</name> air/TLife/trunk/bin/initial/config.xml
r2626 r2642 3 3 <userid></userid> 4 4 <password></password> 5 <oauth_token /> 6 <oauth_token_secret /> 5 7 </login> 6 8 <method>scrape</method> 9 <stream>false</stream> 7 10 <numpageget> 8 11 <recent>1</recent> … … 21 24 <tablock>true</tablock> 22 25 <datagrid> 26 <interval>1</interval> 23 27 <headerlock>true</headerlock> 24 28 <sortlock>true</sortlock> 25 <interval>1</interval>26 29 <rowheight>16</rowheight> 27 30 <dateformat>YY/MM/DD J:NN:SS</dateformat> … … 68 71 <ifiltercontent>Ctrl+F</ifiltercontent> 69 72 <ifilterscreenname>Ctrl+G</ifilterscreenname> 73 <jumptotimeline>Ctrl+J</jumptotimeline> 74 <downatpostarea>Ctrl+Down</downatpostarea> 75 <upatpostarea>Ctrl+Up</upatpostarea> 76 <leftatpostarea>Ctrl+Left</leftatpostarea> 77 <rightatpostarea>Ctrl+Right</rightatpostarea> 70 78 </keybind> 71 79 <search> air/TLife/trunk/src/Main.mxml
r2634 r2642 277 277 Logger.errorLevel = Class(Logger).hasOwnProperty(level) ? Logger[level] : Logger.INFO; 278 278 279 CommonData.judgers_incrementalsearch = [ 280 null, 281 KeyBind.makeJudger(CommonData.configxml.keybind.isearchcontent), 282 KeyBind.makeJudger(CommonData.configxml.keybind.isearchscreenname), 283 KeyBind.makeJudger(CommonData.configxml.keybind.ifiltercontent), 284 KeyBind.makeJudger(CommonData.configxml.keybind.ifilterscreenname) 285 ]; 279 // キーバインド 280 var keybindkeywords : Array = [ 281 "isearchcontent", "isearchscreenname", "ifiltercontent", "ifilterscreenname", 282 "jumptotimeline", "jumptopostarea", "replyatpostarea", "replyattimeline", 283 "downatpostarea", "upatpostarea", "leftatpostarea", "rightatpostarea" 284 ]; 285 CommonData.keybindjudgers = { }; 286 for each(var keyword : String in keybindkeywords) { 287 CommonData.keybindjudgers[keyword] = KeyBind.makeJudger(CommonData.configxml.keybind.child(keyword)); 288 } 286 289 } 287 290 air/TLife/trunk/src/uwi/thread/InitialMovementThread.as
r2634 r2642 5 5 import mx.core.Application; 6 6 import org.libspark.thread.Thread; 7 import org.libspark.thread.utils.ParallelExecutor; 7 8 import org.libspark.thread.utils.SerialExecutor; 8 9 import uwi.twitter.TwitterBitStatusGetThread; … … 11 12 import uwi.twitter.TwitterMobileLoginThread; 12 13 import uwi.twitter.TwitterMobileLogoutThread; 13 import uwi.twitter.TwitterS hadowGetThread;14 import uwi.twitter.TwitterStreamFollowGetThread; 14 15 import uwi.util.CommonData; 15 16 import uwi.util.TimerThread; … … 81 82 // ログイン成功時 82 83 // new Friends().open(true); 83 new TwitterShadowGetThread(null).start();84 /*85 84 86 85 CommonData.state_basicauth = 1; 86 87 // stream 88 if (CommonData.configxml.stream == "true") { 89 if (CommonData.smt != null) CommonData.smt.interrupt(); 90 CommonData.smt = new StreamManageThread(); 91 CommonData.smt.start(); 92 } 93 87 94 var rt : ReloadThread = new ReloadThread(true); 88 95 rt.start(); 89 96 rt.join(); 90 */91 97 }else { 92 98 // ログイン失敗時 air/TLife/trunk/src/uwi/thread/MainThread.as
r2634 r2642 132 132 Security.loadPolicyFile("https://static.twitter.com/crossdomain.xml"); 133 133 134 /*135 134 new TabBarEventThread().start(); 136 135 new ContextMenuItemEventThread().start(); … … 141 140 new DataGridRoutineThread().start(); 142 141 new ReloadTimerThread(CommonData.configxml.interval).start(); 143 */144 142 145 143 if (CommonData.configxml.login.userid == "" || CommonData.configxml.login.password == "") { air/TLife/trunk/src/uwi/thread/ReloadThread.as
r2634 r2642 47 47 pep.addThread(CommonData.factory_statusgetter.newInstance()); 48 48 } 49 if(CommonData.configxml.numpageget.hasOwnProperty("recent")){ 50 CommonData.factory_statusgetter.properties = { posterid : null, pageend : CommonData.configxml.numpageget.recent }; 51 pep.addThread(CommonData.factory_statusgetter.newInstance()); 49 if(CommonData.configxml.stream != "true") { 50 if(CommonData.configxml.numpageget.hasOwnProperty("recent")){ 51 CommonData.factory_statusgetter.properties = { posterid : null, pageend : CommonData.configxml.numpageget.recent }; 52 pep.addThread(CommonData.factory_statusgetter.newInstance()); 53 } 52 54 } 53 55 } air/TLife/trunk/src/uwi/thread/event/IncrementalSearchThread.as
r2634 r2642 70 70 71 71 private static const STR_SEARCH : Array = ["", "本文で検索:", "userid検索:", "本文でフィルタ:", "useridでフィルタ:"]; 72 private static const KEYWORDS : Array = [null, "isearchcontent", "isearchscreenname", "ifiltercontent", "ifilterscreenname"]; 72 73 73 74 private function onKeyDown(e : KeyboardEvent) : void … … 80 81 case 0: 81 82 for (var i : int = 1; i <= 4; i++) { 82 if (CommonData. judgers_incrementalsearch[i].apply(null, [e])) {83 if (CommonData.keybindjudgers[KEYWORDS[i]].apply(null, [e])) { 83 84 mode = i; 84 85 CommonData.mainstatusbar.write(STR_SEARCH[mode], DEPTH_IST); air/TLife/trunk/src/uwi/thread/event/PostEventThread.as
r2634 r2642 8 8 import ken39arg.logging.Logger; 9 9 import mx.controls.Button; 10 import mx.controls.Label;11 10 import mx.controls.TextArea; 12 11 import mx.core.Application; … … 20 19 import uwi.twitter.TwitterScrapeThread; 21 20 import uwi.ui.complete.UserIDCompleteThread; 21 import uwi.ui.DataGridEx; 22 22 import uwi.ui.TextAreaEx; 23 23 import uwi.util.CommonData; … … 33 33 private var postbtn : Button = Application.application.postbtn; 34 34 private var postarea : TextAreaEx = Application.application.postarea; 35 private var charleft : Label = Application.application.charleft;35 private var datagrid : DataGridEx = Application.application.datagrid; 36 36 37 37 private var sub : EventThread; … … 78 78 } 79 79 80 // 投稿 80 81 if (e.keyCode == Keyboard.ENTER && e.controlKey == false) { 81 82 e.preventDefault(); 82 83 onSubmit(null); 83 84 return; 85 } 86 87 if (CommonData.keybindjudgers.jumptotimeline.apply(null, [e])) { 88 Application.application.datagrid.setFocus(); 89 } 90 91 if (CommonData.keybindjudgers.downatpostarea.apply(null, [e])) { 92 if (datagrid.selectedIndex == -1) datagrid.selectedIndex = datagrid.verticalScrollPosition; 93 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, 0, Keyboard.DOWN)); 94 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_UP, true, false, 0, Keyboard.DOWN)); 95 } 96 97 if (CommonData.keybindjudgers.upatpostarea.apply(null, [e])) { 98 if (datagrid.selectedIndex == -1) datagrid.selectedIndex = datagrid.verticalScrollPosition; 99 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, 0, Keyboard.UP)); 100 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_UP, true, false, 0, Keyboard.UP)); 101 } 102 103 if (CommonData.keybindjudgers.leftatpostarea.apply(null, [e])) { 104 if (datagrid.selectedIndex == -1) datagrid.selectedIndex = datagrid.verticalScrollPosition; 105 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, 0, Keyboard.LEFT)); 106 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_UP, true, false, 0, Keyboard.LEFT)); 107 } 108 109 if (CommonData.keybindjudgers.rightatpostarea.apply(null, [e])) { 110 if (datagrid.selectedIndex == -1) datagrid.selectedIndex = datagrid.verticalScrollPosition; 111 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, 0, Keyboard.RIGHT)); 112 datagrid.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_UP, true, false, 0, Keyboard.RIGHT)); 84 113 } 85 114 air/TLife/trunk/src/uwi/twitter/TwitterPostThread.as
r2634 r2642 70 70 CommonData.mainstatusbar.write(eventname + "失敗!(" + event.status + ")"); 71 71 } 72 Logger.info("TwitterPostThread failed " + eventname + " (response " + event.status );72 Logger.info("TwitterPostThread failed " + eventname + " (response " + event.status + ")"); 73 73 } 74 74 } air/TLife/trunk/src/uwi/ui/globalconfig/GlobalConfigEventThread.as
r2634 r2642 39 39 } 40 40 event(gc.tn1, FlexEvent.SHOW, onTN1Show); 41 event(gc.oauthbtn, MouseEvent.CLICK, onOAuth);42 41 43 42 event(gc.ok, MouseEvent.CLICK, onOK); … … 102 101 next(run); 103 102 } 104 105 private function onOAuth(e : MouseEvent) : void106 {107 new TwitterOAuthRequestThread().start();108 next(run);109 }110 103 } 111 104 air/TLife/trunk/src/uwi/ui/mainmenu/MainMenu.mxml
r2634 r2642 6 6 verticalAlign="middle" 7 7 creationComplete="onLoad()" 8 show="onShow()" 8 9 close="PopUpManager.removePopUp(this)" 9 10 remove="onRemove()" 10 11 > 11 <mx:Button id="dbsearch" label="DB検索" width="100%" click="createDBSearch()" /> 12 <mx:Button id="relog" label="再ログイン" width="100%" click="relogin()" /> 13 <mx:Button id="config" label="設定" width="100%" click="createGlobalConfig()" /> 14 <mx:Button id="check" label="更新チェック" width="100%" click="checkUpdate()" /> 12 <mx:Button id="dbsearch" label="DB検索" width="100%" /> 13 <mx:Button id="relogin" label="再ログイン" width="100%" /> 14 <mx:Button id="oauth" label="OAuth認証" width="100%" /> 15 <mx:Button id="config" label="設定" width="100%" /> 16 <mx:Button id="checkupdate" label="更新チェック" width="100%" /> 15 17 <mx:Button id="about" label="About" width="100%" click="PopUpManager.removePopUp(this)" /> 16 18 <mx:Label id="version" textAlign="right" width="100%" /> … … 18 20 <mx:Script> 19 21 <![CDATA[ 22 import flash.desktop.NativeApplication; 20 23 import mx.managers.PopUpManager; 21 import net.jirox.AirAutoUpdater;22 import uwi.thread.InitialMovementThread;23 import uwi.util.CommonData;24 import uwi.ui.dbsearch.DBSearchWindow;25 import uwi.ui.globalconfig.GlobalConfig;26 24 27 25 private var mmet : MainMenuEventThread; … … 29 27 private function onLoad() : void 30 28 { 29 trace("onLoad"); 31 30 var appDescriptor:XML = NativeApplication.nativeApplication.applicationDescriptor; 32 31 var ns:Namespace = appDescriptor.namespace(); … … 38 37 } 39 38 39 private function onShow() : void 40 { 41 mmet = new MainMenuEventThread(this); 42 mmet.start(); 43 } 44 40 45 private function onRemove() : void 41 46 { 42 47 mmet = null; 43 48 } 44 45 private function createGlobalConfig() : void46 {47 PopUpManager.removePopUp(this);48 if (CommonData.globalconfig == null) {49 CommonData.globalconfig = new GlobalConfig();50 CommonData.globalconfig.open(true);51 }else {52 CommonData.globalconfig.restore();53 CommonData.globalconfig.orderToFront();54 }55 }56 57 private function createDBSearch() : void58 {59 PopUpManager.removePopUp(this);60 if (CommonData.dbsearchwindow == null) {61 CommonData.dbsearchwindow = new DBSearchWindow();62 CommonData.dbsearchwindow.open(true);63 }else {64 CommonData.dbsearchwindow.close();65 }66 }67 68 private function relogin() : void69 {70 PopUpManager.removePopUp(this);71 new InitialMovementThread().start();72 }73 74 private function checkUpdate() : void75 {76 PopUpManager.removePopUp(this);77 var aau : AirAutoUpdater = new AirAutoUpdater();78 aau.url = "http://www.libspark.org/svn/air/TLife/trunk/air/version.xml";79 aau.checkUpdate();80 }81 49 ]]> 82 50 </mx:Script> air/TLife/trunk/src/uwi/ui/mainmenu/MainMenuEventThread.as
r2634 r2642 3 3 import flash.events.MouseEvent; 4 4 import mx.core.Application; 5 import mx.managers.PopUpManager; 6 import net.jirox.AirAutoUpdater; 5 7 import org.libspark.thread.Thread; 8 import uwi.thread.InitialMovementThread; 9 import uwi.twitter.TwitterOAuthRequestThread; 10 import uwi.ui.dbsearch.DBSearchWindow; 6 11 import uwi.ui.globalconfig.GlobalConfig; 7 12 import uwi.util.CommonData; … … 22 27 protected override function run() : void 23 28 { 29 event(mainmenu.dbsearch, MouseEvent.CLICK, onDBSearchClick); 24 30 event(mainmenu.config, MouseEvent.CLICK, onConfigClick); 31 event(mainmenu.relogin, MouseEvent.CLICK, onReLoginClick); 32 event(mainmenu.oauth, MouseEvent.CLICK, onOAuthClick); 33 event(mainmenu.checkupdate, MouseEvent.CLICK, onCheckUpdateClick); 34 } 35 36 private function onDBSearchClick(e : MouseEvent) : void 37 { 38 PopUpManager.removePopUp(mainmenu); 39 if (CommonData.dbsearchwindow == null) { 40 CommonData.dbsearchwindow = new DBSearchWindow(); 41 CommonData.dbsearchwindow.open(true); 42 }else { 43 CommonData.dbsearchwindow.close(); 44 } 25 45 } 26 46 27 47 private function onConfigClick(e : MouseEvent) : void 28 48 { 49 PopUpManager.removePopUp(mainmenu); 29 50 if (CommonData.globalconfig == null) { 30 51 CommonData.globalconfig = new GlobalConfig(); … … 36 57 next(run); 37 58 } 59 60 private function onReLoginClick(e : MouseEvent) : void 61 { 62 PopUpManager.removePopUp(mainmenu); 63 new InitialMovementThread().start(); 64 } 65 66 private function onOAuthClick(e : MouseEvent) : void 67 { 68 PopUpManager.removePopUp(mainmenu); 69 new TwitterOAuthRequestThread().start(); 70 } 71 72 private function onCheckUpdateClick() : void 73 { 74 PopUpManager.removePopUp(mainmenu); 75 var aau : AirAutoUpdater = new AirAutoUpdater(); 76 aau.url = "http://www.libspark.org/svn/air/TLife/trunk/air/version.xml"; 77 aau.checkUpdate(); 78 } 38 79 } 39 80 air/TLife/trunk/src/uwi/util/CommonData.as
r2634 r2642 13 13 import uwi.thread.event.DataGridRoutineThread; 14 14 import uwi.thread.ReplyGetThread; 15 import uwi.thread.StreamManageThread; 15 16 import uwi.tinysegmenter.TinySegmenter; 16 17 import uwi.twitter.TwitterBitScrapeThread; 17 18 import uwi.twitter.TwitterBitStatusGetThread; 18 19 import uwi.twitter.TwitterScrapeThread; 20 import uwi.twitter.TwitterStreamFollowGetThread; 19 21 import uwi.twitter.TwitterTimelineGetThread; 20 22 import uwi.ui.globalconfig.GlobalConfig; … … 74 76 public static var rgt : ReplyGetThread = null; 75 77 public static var mtbdet : MultipleTabBarDragEventThread = null; 78 public static var smt : StreamManageThread = null; 76 79 77 80 public static var configxml : XML = null; … … 91 94 public static var prevpos_replypost : int = -1; 92 95 93 public static var judgers_incrementalsearch : Array;96 public static var keybindjudgers : Object; 94 97 95 98 public static var urlcache : Object = { }; // URL解決用のキャッシュ air/TLife/trunk/src/uwi/util/KeyBind.as
r2634 r2642 10 10 public class KeyBind 11 11 { 12 private static const FUNCTION_FAILED : Function = function(e : KeyboardEvent) : Boolean { return false; }; 13 14 private static const KEYMAP : Object = { 15 down : Keyboard.DOWN, 16 up : Keyboard.UP, 17 left : Keyboard.LEFT, 18 right : Keyboard.RIGHT, 19 enter : Keyboard.ENTER, 20 nenter : Keyboard.NUMPAD_ENTER, 21 space : Keyboard.SPACE, 22 backspace : Keyboard.BACKSPACE, 23 f1 : Keyboard.F1, 24 f2 : Keyboard.F2, 25 f3 : Keyboard.F3, 26 f4 : Keyboard.F4, 27 f5 : Keyboard.F5, 28 f6 : Keyboard.F6, 29 f7 : Keyboard.F7, 30 f8 : Keyboard.F8, 31 f9 : Keyboard.F9, 32 f10 : Keyboard.F10, 33 f11 : Keyboard.F11, 34 f12 : Keyboard.F12, 35 escape : Keyboard.ESCAPE, 36 capslock : Keyboard.CAPS_LOCK, 37 home : Keyboard.HOME, 38 end : Keyboard.END, 39 a : Keyboard.A, 40 b : Keyboard.B, 41 c : Keyboard.C, 42 d : Keyboard.D, 43 e : Keyboard.E, 44 f : Keyboard.F, 45 g : Keyboard.G, 46 h : Keyboard.H, 47 i : Keyboard.I, 48 j : Keyboard.J, 49 k : Keyboard.K, 50 l : Keyboard.L, 51 m : Keyboard.M, 52 n : Keyboard.N, 53 o : Keyboard.O, 54 p : Keyboard.P, 55 q : Keyboard.Q, 56 r : Keyboard.R, 57 s : Keyboard.S, 58 t : Keyboard.T, 59 u : Keyboard.U, 60 v : Keyboard.V, 61 w : Keyboard.W, 62 x : Keyboard.X, 63 y : Keyboard.Y, 64 z : Keyboard.Z 65 }; 66 67 /** 68 * キーバインド判定関数を作成する。失敗した場合常にfalseを返す判定関数を作成する。 69 * @param src 70 * @return 71 */ 12 72 public static function makeJudger(src : String) : Function 13 73 { … … 15 75 16 76 var keys : Array = src.split("+"); 17 var code : Number = keys.pop().charCodeAt(0); 77 if (keys.length == 0) return FUNCTION_FAILED; 78 var last : String = keys.pop(); 18 79 var ctrl : Boolean = keys.indexOf("ctrl") != -1; 19 80 var alt : Boolean = keys.indexOf("alt") != -1; 20 81 var shift : Boolean = keys.indexOf("shift") != -1; 21 82 22 if (code < "a".charCodeAt(0) || code > "z".charCodeAt(0)) return null; 23 var keycode : uint = code - "a".charCodeAt(0) + 65; 83 var keycode : uint; 84 if (KEYMAP[last]) { 85 keycode = KEYMAP[last]; 86 }else{ 87 switch(last) { 88 case "-" : keycode = Keyboard.MINUS; break; 89 case "n+" : keycode = Keyboard.NUMPAD_ADD; break; 90 case "n-" : keycode = Keyboard.NUMPAD_SUBTRACT; break; 91 case "n*" : keycode = Keyboard.NUMPAD_MULTIPLY; break; 92 case "n/" : keycode = Keyboard.NUMPAD_DIVIDE; break; 93 case "n." : keycode = Keyboard.NUMPAD_DECIMAL; break; 94 case "." : keycode = Keyboard.PERIOD; break; 95 case "," : keycode = Keyboard.COMMA; break; 96 case "'" : keycode = Keyboard.QUOTE; break; 97 case "\\" : keycode = Keyboard.BACKSLASH; break; 98 case "/" : keycode = Keyboard.SLASH; break; 99 case "`" : keycode = Keyboard.BACKQUOTE; break; 100 case ";" : keycode = Keyboard.SEMICOLON; break; 101 case "=" : keycode = Keyboard.EQUAL; break; 102 case "[" : keycode = Keyboard.LEFTBRACKET; break; 103 case "]" : keycode = Keyboard.RIGHTBRACKET; break; 104 case "0" : keycode = Keyboard.NUMBER_0; break; 105 case "1" : keycode = Keyboard.NUMBER_1; break; 106 case "2" : keycode = Keyboard.NUMBER_2; break; 107 case "3" : keycode = Keyboard.NUMBER_3; break; 108 case "4" : keycode = Keyboard.NUMBER_4; break; 109 case "5" : keycode = Keyboard.NUMBER_5; break; 110 case "6" : keycode = Keyboard.NUMBER_6; break; 111 case "7" : keycode = Keyboard.NUMBER_7; break; 112 case "8" : keycode = Keyboard.NUMBER_8; break; 113 case "9" : keycode = Keyboard.NUMBER_9; break; 114 default : 115 return FUNCTION_FAILED; 116 break; 117 } 118 } 119 24 120 return function(e : KeyboardEvent) : Boolean { 25 121 return e.controlKey == ctrl && e.altKey == alt && e.shiftKey == shift && e.keyCode == keycode;

