From 319bdaf88581e768968518b15cfb7d828dc49f8d Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Mon, 11 Jul 2011 08:29:39 -0400 Subject: [PATCH] Enhance debugging utilities for developers --- js/src/util.js | 42 ++++++++++++---- js/src/wii.js | 91 +++++++++++++++++++++++++++------ js/wii.js | 133 +++++++++++++++++++++++++++++++++++++++---------- js/wii.min.js | 2 +- 4 files changed, 215 insertions(+), 53 deletions(-) diff --git a/js/src/util.js b/js/src/util.js index 3ddb1fb..7e0b1da 100644 --- a/js/src/util.js +++ b/js/src/util.js @@ -9,6 +9,19 @@ */ Wii.util = { + /** + * A placeholder for the original Error function, since we pretty much overwrite it to actually + * be useful to us. See "Wii.installListeners()" for more information on this. + */ + originalErrFunction: null, + + /** + * Upon first call to Wii.util.debug(), this becomes a div that we keep + * a reference to. It's primarily used for logging information to the screen + * on the Wii itself. + */ + msgNode: null, + /** * Wii.util.debug(err); * @@ -18,37 +31,46 @@ Wii.util = { * try { ... } catch(e) { Wii.util.debug(e); } */ debug: function(err) { - if(Wii.debuggerDiv === null) { - Wii.debuggerDiv = document.createElement('div'); + if(Wii.util.msgNode === null) { + Wii.util.msgNode = document.createElement('div'); - Wii.debuggerDiv.style.cssText = [ - 'width: 90%;', - 'height: 90%;', + Wii.util.msgNode.style.cssText = [ + 'min-width: 756px;', 'padding: 10px;', - 'font-size: 26px;', + 'font-size: 28px;', + 'line-height: 32px;', 'font-family: monospace;', - 'overflow: scroll', 'position: absolute;', 'top: 10px;', 'left: 10px;', 'color: #f9f9f9;', - 'background-color: #010101;' + 'background-color: rgba(44, 44, 44, .7);', + 'border: 2px solid #42a2cc;' ].join(''); - document.body.appendChild(Wii.debuggerDiv); + Wii.util.msgNode.addEventListener('click', Wii.util.hideDebugger, false); + document.body.appendChild(Wii.util.msgNode); } if(typeof err === 'string') { Wii.debuggerDiv.innerHTML = err; } else { var msg = ''; - for(var e in err) { msg += e + '=' + err[e] + '
'; } + for(var e in err) { msg += '' + e + '=' + err[e] + '
'; } Wii.debuggerDiv.innerHTML = msg; } Wii.debuggerDiv.style.display = 'block'; }, + /** + * Wii.util.hideDebugger() + * + * Keep this around so we've got an easy reference to use for proper unloading + * of event handlers once someone leaves this page. + */ + hideDebugger: function() { this.style.display = 'none'; }, + /** * Wiimote.util.bind(bindReference, fn) * diff --git a/js/src/wii.js b/js/src/wii.js index 775fc15..a6af879 100644 --- a/js/src/wii.js +++ b/js/src/wii.js @@ -23,31 +23,86 @@ var Wii = { * through on each loop/iteration and poll for a new status on it. */ extraRemotes: [], + + /** + * A "global" reference to the (current) primary Wiimote. This can change if the + * primary Wiimote runs out of battery, and the library shoul transparently account + * for this. + */ currentBrowsingRemote: null, - setKeyListeners: false, - debuggerDiv: null + + /** + * Internal flag for whether or not we've actually set some document event listeners. + * A little messy, sure, but not the biggest guffaw in the world. + */ + setListeners: false, + + /** + * A global debug flag. If this is enabled/set to true, any errors raised will be thrown + * up on the screen for the Wii. Should be set when the initial .listen() request is fired. + * + * e.g, Wii.listen({debug: true}); + */ + debug: false, + + /** + * The primary Wiimote depends on typical DOM-esque events to communicate what actions it's + * doing, and the other three use a whole bitmask-esque scenario. This is a "global" Array of + * the events we're interested in for the primary Wiimote. + * + * We catch multiple begin/endpoints for these full event "scopes" for + * future use, as it seems like it'll probably be the most performant way + * to do rapid-quick checks for the primary Wii-mote as to multiple-button + * press scenarios (among some other things). + */ + primaryWiimoteEvts: ['mouseup', 'mousedown', 'keyup', 'keydown', 'keypress'], }; /** + * Wii.installListeners() + * * Install some basic low-level event listeners to monitor how * the primary wii_remote is interacting with the browser; it's treated * differently than the other wii_remotes, more as a "browsing" tool than * a controller. Doesn't mean we can't try and mend the gap... */ -Wii.installKeyListeners = function() { - document.addEventListener('mouseup', Wii.parsePrimaryWiimote, false); - document.addEventListener('keydown', Wii.parsePrimaryWiimote, false); - document.addEventListener('mousedown', Wii.parsePrimaryWiimote, false); - document.addEventListener('keyup', Wii.parsePrimaryWiimote, false); - +Wii.installListeners = function() { + for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) { + document.addEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false); + } + /** - * Some keys, like the directional ones, get... multiple events? - * In this case, just shut. down. everything. - * - * ...and let the programmer deal with it. + * Since the Wii is already a fairly low-spec system, it's definitely worth + * cleaning up after ourselves if we can get around to it. This should (hopefully) + * take care of most of what we need to worry about. */ - document.addEventListener('keypress', Wii.parsePrimaryWiimote, false); - + window.onbeforeunload = function() { + for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) { + document.removeEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false); + } + }; + + /** + * If this is all listening in debug mode, we wanna try and catch everything that could + * possibly go wrong in the stack. try/catch is very expensive for the entire program, and can + * crash the Wii pretty easily if you push it too much. + * + * What we'll do instead is just patch the seemingly un-documented window.Error function to suit our + * debugging needs, and only try/catch while in debug mode in critical places (e.g, the constant polling + * section would be... yeah, not a fun idea). + * + * With this, "throw new Error(error)" will actually hit over to what we want, and anything else (outside code) + * using it will get the on-screen Wii debug which is actually useful. That's why we bother doing this, instead + * of just calling Wii.util.debug() everywhere. ;) + */ + if(Wii.debug) { + Wii.util.originalErrFunction = window.Error; + window.Error = function() { + if(arguments.length > 0) Wii.util.debug(arguments[0]); + else Wii.util.originalErrFunction.apply(this, arguments); + } + } + return true; }; @@ -57,8 +112,12 @@ Wii.installKeyListeners = function() { * The main game loop. This must stay very performant; try to keep things as absolutely * low-level as possible here. */ -Wii.listen = function() { - if(!Wii.setKeyListeners) Wii.setKeyListeners = Wii.installKeyListeners(); +Wii.listen = function(optional_opts) { + if(typeof optional_opts !== 'undefined') { + if(typeof optional_opts.debug !== 'undefined' && optional_opts.debug) Wii.debug = true; + } + + if(!Wii.setListeners) Wii.setListeners = Wii.installListeners(); var i = Wii.extraRemotes.length; diff --git a/js/wii.js b/js/wii.js index 7acf000..9c13578 100644 --- a/js/wii.js +++ b/js/wii.js @@ -46,31 +46,86 @@ var Wii = { * through on each loop/iteration and poll for a new status on it. */ extraRemotes: [], + + /** + * A "global" reference to the (current) primary Wiimote. This can change if the + * primary Wiimote runs out of battery, and the library shoul transparently account + * for this. + */ currentBrowsingRemote: null, - setKeyListeners: false, - debuggerDiv: null + + /** + * Internal flag for whether or not we've actually set some document event listeners. + * A little messy, sure, but not the biggest guffaw in the world. + */ + setListeners: false, + + /** + * A global debug flag. If this is enabled/set to true, any errors raised will be thrown + * up on the screen for the Wii. Should be set when the initial .listen() request is fired. + * + * e.g, Wii.listen({debug: true}); + */ + debug: false, + + /** + * The primary Wiimote depends on typical DOM-esque events to communicate what actions it's + * doing, and the other three use a whole bitmask-esque scenario. This is a "global" Array of + * the events we're interested in for the primary Wiimote. + * + * We catch multiple begin/endpoints for these full event "scopes" for + * future use, as it seems like it'll probably be the most performant way + * to do rapid-quick checks for the primary Wii-mote as to multiple-button + * press scenarios (among some other things). + */ + primaryWiimoteEvts: ['mouseup', 'mousedown', 'keyup', 'keydown', 'keypress'], }; /** + * Wii.installListeners() + * * Install some basic low-level event listeners to monitor how * the primary wii_remote is interacting with the browser; it's treated * differently than the other wii_remotes, more as a "browsing" tool than * a controller. Doesn't mean we can't try and mend the gap... */ -Wii.installKeyListeners = function() { - document.addEventListener('mouseup', Wii.parsePrimaryWiimote, false); - document.addEventListener('keydown', Wii.parsePrimaryWiimote, false); - document.addEventListener('mousedown', Wii.parsePrimaryWiimote, false); - document.addEventListener('keyup', Wii.parsePrimaryWiimote, false); - +Wii.installListeners = function() { + for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) { + document.addEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false); + } + /** - * Some keys, like the directional ones, get... multiple events? - * In this case, just shut. down. everything. - * - * ...and let the programmer deal with it. + * Since the Wii is already a fairly low-spec system, it's definitely worth + * cleaning up after ourselves if we can get around to it. This should (hopefully) + * take care of most of what we need to worry about. */ - document.addEventListener('keypress', Wii.parsePrimaryWiimote, false); - + window.onbeforeunload = function() { + for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) { + document.removeEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false); + } + }; + + /** + * If this is all listening in debug mode, we wanna try and catch everything that could + * possibly go wrong in the stack. try/catch is very expensive for the entire program, and can + * crash the Wii pretty easily if you push it too much. + * + * What we'll do instead is just patch the seemingly un-documented window.Error function to suit our + * debugging needs, and only try/catch while in debug mode in critical places (e.g, the constant polling + * section would be... yeah, not a fun idea). + * + * With this, "throw new Error(error)" will actually hit over to what we want, and anything else (outside code) + * using it will get the on-screen Wii debug which is actually useful. That's why we bother doing this, instead + * of just calling Wii.util.debug() everywhere. ;) + */ + if(Wii.debug) { + Wii.util.originalErrFunction = window.Error; + window.Error = function() { + if(arguments.length > 0) Wii.util.debug(arguments[0]); + else Wii.util.originalErrFunction.apply(this, arguments); + } + } + return true; }; @@ -80,8 +135,12 @@ Wii.installKeyListeners = function() { * The main game loop. This must stay very performant; try to keep things as absolutely * low-level as possible here. */ -Wii.listen = function() { - if(!Wii.setKeyListeners) Wii.setKeyListeners = Wii.installKeyListeners(); +Wii.listen = function(optional_opts) { + if(typeof optional_opts !== 'undefined') { + if(typeof optional_opts.debug !== 'undefined' && optional_opts.debug) Wii.debug = true; + } + + if(!Wii.setListeners) Wii.setListeners = Wii.installListeners(); var i = Wii.extraRemotes.length; @@ -298,6 +357,19 @@ Wii.DISPATCHER = { */ Wii.util = { + /** + * A placeholder for the original Error function, since we pretty much overwrite it to actually + * be useful to us. See "Wii.installListeners()" for more information on this. + */ + originalErrFunction: null, + + /** + * Upon first call to Wii.util.debug(), this becomes a div that we keep + * a reference to. It's primarily used for logging information to the screen + * on the Wii itself. + */ + msgNode: null, + /** * Wii.util.debug(err); * @@ -307,37 +379,46 @@ Wii.util = { * try { ... } catch(e) { Wii.util.debug(e); } */ debug: function(err) { - if(Wii.debuggerDiv === null) { - Wii.debuggerDiv = document.createElement('div'); + if(Wii.util.msgNode === null) { + Wii.util.msgNode = document.createElement('div'); - Wii.debuggerDiv.style.cssText = [ - 'width: 90%;', - 'height: 90%;', + Wii.util.msgNode.style.cssText = [ + 'min-width: 756px;', 'padding: 10px;', - 'font-size: 26px;', + 'font-size: 28px;', + 'line-height: 32px;', 'font-family: monospace;', - 'overflow: scroll', 'position: absolute;', 'top: 10px;', 'left: 10px;', 'color: #f9f9f9;', - 'background-color: #010101;' + 'background-color: rgba(44, 44, 44, .7);', + 'border: 2px solid #42a2cc;' ].join(''); - document.body.appendChild(Wii.debuggerDiv); + Wii.util.msgNode.addEventListener('click', Wii.util.hideDebugger, false); + document.body.appendChild(Wii.util.msgNode); } if(typeof err === 'string') { Wii.debuggerDiv.innerHTML = err; } else { var msg = ''; - for(var e in err) { msg += e + '=' + err[e] + '
'; } + for(var e in err) { msg += '' + e + '=' + err[e] + '
'; } Wii.debuggerDiv.innerHTML = msg; } Wii.debuggerDiv.style.display = 'block'; }, + /** + * Wii.util.hideDebugger() + * + * Keep this around so we've got an easy reference to use for proper unloading + * of event handlers once someone leaves this page. + */ + hideDebugger: function() { this.style.display = 'none'; }, + /** * Wiimote.util.bind(bindReference, fn) * diff --git a/js/wii.min.js b/js/wii.min.js index 7bee3f7..9d162b0 100644 --- a/js/wii.min.js +++ b/js/wii.min.js @@ -1 +1 @@ -(function(a){if(!a){return false}var b={extraRemotes:[],currentBrowsingRemote:null,setKeyListeners:false,debuggerDiv:null};b.installKeyListeners=function(){document.addEventListener("mouseup",b.parsePrimaryWiimote,false);document.addEventListener("keydown",b.parsePrimaryWiimote,false);document.addEventListener("mousedown",b.parsePrimaryWiimote,false);document.addEventListener("keyup",b.parsePrimaryWiimote,false);document.addEventListener("keypress",b.parsePrimaryWiimote,false);return true};b.listen=function(){if(!b.setKeyListeners){b.setKeyListeners=b.installKeyListeners()}var e=b.extraRemotes.length;while(e--){var g=b.extraRemotes[e],f=g.isEnabled();if(f){if(f.isBrowsing){b.currentBrowsingRemote=g}else{g.x=f.dpdScreenX;g.y=f.dpdScreenY;for(var c in g.evtsInterestedIn){var d=b.DISPATCHER[c](g,f);if(d){g.evtsInterestedIn[c](g,f)}}}}}return setTimeout(b.listen,100)};b.parsePrimaryWiimote=function(g){g.preventDefault();var f=b.currentBrowsingRemote,d=f.isEnabled(),c=b.PRIMARY_CONTROLLER_DISPATCHER[f.opts.horizontal?"horizontal":"vertical"][g.keyCode];f.x=d.dpdScreenX;f.y=d.dpdScreenY;if(typeof c!=="undefined"&&typeof f.evtsInterestedIn[c]==="function"){f.evtsInterestedIn[c](f,d)}if(typeof f.evtsInterestedIn.roll_change==="function"){if(b.DISPATCHER.roll_change(f,d)){f.evtsInterestedIn.roll_change(f,d)}}if(typeof f.evtsInterestedIn.distance_change==="function"){if(b.DISPATCHER.distance_change(f,d)){f.evtsInterestedIn.distance_change(f,d)}}return false};b.PRIMARY_CONTROLLER_DISPATCHER={vertical:{0:"pressed_a",13:"pressed_a",170:"pressed_minus",171:"pressed_b",172:"pressed_1",173:"pressed_2",174:"pressed_plus",175:"pressed_up",176:"pressed_down",177:"pressed_right",178:"pressed_left"},horizontal:{0:"pressed_a",13:"pressed_a",170:"pressed_minus",171:"pressed_b",172:"pressed_1",173:"pressed_2",174:"pressed_plus",175:"pressed_left",176:"pressed_right",177:"pressed_up",178:"pressed_down"}};b.DISPATCHER={pressed_up:function(d,c){if(d.opts.horizontal){return c.hold&2}return c.hold&8},pressed_right:function(d,c){if(d.opts.horizontal){return c.hold&4}return c.hold&2},pressed_down:function(d,c){if(d.opts.horizontal){return c.hold&1}return c.hold&4},pressed_left:function(d,c){if(d.opts.horizontal){return c.hold&8}return c.hold&1},pressed_plus:function(d,c){return c.hold&16},pressed_minus:function(d,c){return c.hold&4096},pressed_2:function(d,c){return c.hold&256},pressed_1:function(d,c){return c.hold&512},pressed_b:function(d,c){return c.hold&1024},pressed_a:function(d,c){return c.hold&2048},roll_change:function(e,d){var c=Math.atan2(d.dpdRollY,d.dpdRollX);if(c!==e.roll){e.roll=c;return true}return false},distance_change:function(d,c){if(c.dpdDistance!==d.last_known_distance_from_screen){d.last_known_distance_from_screen=c.dpdDistance;return true}return false},pressed_z:function(d,c){return c.hold&8192},pressed_c:function(d,c){return c.hold&16384}};b.util={debug:function(c){if(b.debuggerDiv===null){b.debuggerDiv=document.createElement("div");b.debuggerDiv.style.cssText=["width: 90%;","height: 90%;","padding: 10px;","font-size: 26px;","font-family: monospace;","overflow: scroll","position: absolute;","top: 10px;","left: 10px;","color: #f9f9f9;","background-color: #010101;"].join("");document.body.appendChild(b.debuggerDiv)}if(typeof c==="string"){b.debuggerDiv.innerHTML=c}else{var f="";for(var d in c){f+=d+"="+c[d]+"
"}b.debuggerDiv.innerHTML=f}b.debuggerDiv.style.display="block"},bind:function(c,d){return function(){return d.apply(c,arguments)}}};b.Remote=function(e,d){this.remote_id=e;this.opts=d;this.x=undefined;this.y=undefined;this.roll=undefined;this.last_known_distance_from_screen=undefined;var c=this.isEnabled();if(c){if(!c.isBrowsing){b.extraRemotes.push(this)}else{b.currentBrowsingRemote=this}}};b.Remote.prototype={opts:{horizontal:false},evtsInterestedIn:undefined,isEnabled:function(){var c=opera.wiiremote.update(this.remote_id-1);return(c.isEnabled&&c.isDataValid?c:false)},when:function(d,c){if(typeof b.DISPATCHER[d]!=="undefined"){if(this.evtsInterestedIn===undefined){this.evtsInterestedIn={}}this.evtsInterestedIn[d]=b.util.bind(this,c);return this}return undefined}};window.Wii=b})(window.opera&&opera.wiiremote); \ No newline at end of file +(function(a){if(!a){return false}var b={extraRemotes:[],currentBrowsingRemote:null,setListeners:false,debug:false,primaryWiimoteEvts:["mouseup","mousedown","keyup","keydown","keypress"],};b.installListeners=function(){for(var d=0,c=b.primaryWiimoteEvts.length;d0){b.util.debug(arguments[0])}else{b.util.originalErrFunction.apply(this,arguments)}}}return true};b.listen=function(h){if(typeof h!=="undefined"){if(typeof h.debug!=="undefined"&&h.debug){b.debug=true}}if(!b.setListeners){b.setListeners=b.installListeners()}var e=b.extraRemotes.length;while(e--){var g=b.extraRemotes[e],f=g.isEnabled();if(f){if(f.isBrowsing){b.currentBrowsingRemote=g}else{g.x=f.dpdScreenX;g.y=f.dpdScreenY;for(var c in g.evtsInterestedIn){var d=b.DISPATCHER[c](g,f);if(d){g.evtsInterestedIn[c](g,f)}}}}}return setTimeout(b.listen,100)};b.parsePrimaryWiimote=function(g){g.preventDefault();var f=b.currentBrowsingRemote,d=f.isEnabled(),c=b.PRIMARY_CONTROLLER_DISPATCHER[f.opts.horizontal?"horizontal":"vertical"][g.keyCode];f.x=d.dpdScreenX;f.y=d.dpdScreenY;if(typeof c!=="undefined"&&typeof f.evtsInterestedIn[c]==="function"){f.evtsInterestedIn[c](f,d)}if(typeof f.evtsInterestedIn.roll_change==="function"){if(b.DISPATCHER.roll_change(f,d)){f.evtsInterestedIn.roll_change(f,d)}}if(typeof f.evtsInterestedIn.distance_change==="function"){if(b.DISPATCHER.distance_change(f,d)){f.evtsInterestedIn.distance_change(f,d)}}return false};b.PRIMARY_CONTROLLER_DISPATCHER={vertical:{0:"pressed_a",13:"pressed_a",170:"pressed_minus",171:"pressed_b",172:"pressed_1",173:"pressed_2",174:"pressed_plus",175:"pressed_up",176:"pressed_down",177:"pressed_right",178:"pressed_left"},horizontal:{0:"pressed_a",13:"pressed_a",170:"pressed_minus",171:"pressed_b",172:"pressed_1",173:"pressed_2",174:"pressed_plus",175:"pressed_left",176:"pressed_right",177:"pressed_up",178:"pressed_down"}};b.DISPATCHER={pressed_up:function(d,c){if(d.opts.horizontal){return c.hold&2}return c.hold&8},pressed_right:function(d,c){if(d.opts.horizontal){return c.hold&4}return c.hold&2},pressed_down:function(d,c){if(d.opts.horizontal){return c.hold&1}return c.hold&4},pressed_left:function(d,c){if(d.opts.horizontal){return c.hold&8}return c.hold&1},pressed_plus:function(d,c){return c.hold&16},pressed_minus:function(d,c){return c.hold&4096},pressed_2:function(d,c){return c.hold&256},pressed_1:function(d,c){return c.hold&512},pressed_b:function(d,c){return c.hold&1024},pressed_a:function(d,c){return c.hold&2048},roll_change:function(e,d){var c=Math.atan2(d.dpdRollY,d.dpdRollX);if(c!==e.roll){e.roll=c;return true}return false},distance_change:function(d,c){if(c.dpdDistance!==d.last_known_distance_from_screen){d.last_known_distance_from_screen=c.dpdDistance;return true}return false},pressed_z:function(d,c){return c.hold&8192},pressed_c:function(d,c){return c.hold&16384}};b.util={originalErrFunction:null,msgNode:null,debug:function(c){if(b.util.msgNode===null){b.util.msgNode=document.createElement("div");b.util.msgNode.style.cssText=["min-width: 756px;","padding: 10px;","font-size: 28px;","line-height: 32px;","font-family: monospace;","position: absolute;","top: 10px;","left: 10px;","color: #f9f9f9;","background-color: rgba(44, 44, 44, .7);","border: 2px solid #42a2cc;"].join("");b.util.msgNode.addEventListener("click",b.util.hideDebugger,false);document.body.appendChild(b.util.msgNode)}if(typeof c==="string"){b.debuggerDiv.innerHTML=c}else{var f="";for(var d in c){f+=''+d+"="+c[d]+"
"}b.debuggerDiv.innerHTML=f}b.debuggerDiv.style.display="block"},hideDebugger:function(){this.style.display="none"},bind:function(c,d){return function(){return d.apply(c,arguments)}}};b.Remote=function(e,d){this.remote_id=e;this.opts=d;this.x=undefined;this.y=undefined;this.roll=undefined;this.last_known_distance_from_screen=undefined;var c=this.isEnabled();if(c){if(!c.isBrowsing){b.extraRemotes.push(this)}else{b.currentBrowsingRemote=this}}};b.Remote.prototype={opts:{horizontal:false},evtsInterestedIn:undefined,isEnabled:function(){var c=opera.wiiremote.update(this.remote_id-1);return(c.isEnabled&&c.isDataValid?c:false)},when:function(d,c){if(typeof b.DISPATCHER[d]!=="undefined"){if(this.evtsInterestedIn===undefined){this.evtsInterestedIn={}}this.evtsInterestedIn[d]=b.util.bind(this,c);return this}return undefined}};window.Wii=b})(window.opera&&opera.wiiremote); \ No newline at end of file