Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial push; huzzah.

  • Loading branch information...
commit 0b1c7ff386c26baa5687819f68938ea702fd2779 0 parents
@ryanmcgrath authored
21 LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2009 - 2011 Ryan McGrath
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
64 build.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+
+"""
+ Build-script that brings together all the JS files for wii.js and
+ takes care of minifying it down to a decent size.
+
+ Before you even ask, no, we're not using uglify.js or Closure. Both
+ of them are simply too aggressive for their own good; while normally this
+ is an excellent feature to have, the JS engine that the Opera version on the Wii
+ uses has a really odd set of quirks when you start trying to get smart with code,
+ and YUI is the only minifier that doesn't appear to totally destroy it all through
+ obfuscation. We'll forego a few bytes to have the thing working. ;P
+
+ Uglify also requires Node.js. While I *love* Node, I'll wait until it's more readily
+ available on Windows - there are a large amount of Windows-based programmers that I'm
+ not keen on keeping out of development.
+"""
+
+import os
+from subprocess import call
+
+currdir = os.getcwd()
+
+# The names of our JS files (minus the .js) that we want to build into the
+# final distribution.
+DEPENDENCIES = [
+ 'wii',
+ 'util',
+ 'remote',
+]
+
+# What we're going to end up injecting as our core build, into core.js.
+inject_build = ''
+
+def minify_code(filename, final_filename):
+ """
+ Dips out to Java/YUI compressor and runs the minifier on the specified file, dumping the
+ output into the specified final_filename.
+ """
+ #cmd = 'java -jar %s/utilities/yuicompressor-2.4.2.jar %s -o %s' % (currdir, filename, final_filename)
+ call(['java', '-jar', '%s/utilities/yuicompressor-2.4.2.jar' % currdir, filename, '-o', final_filename])
+
+# Run through each dependency, read it into "inject build", then do a simple split on the
+# contents of core.js and wrap it all up.
+for dependency in DEPENDENCIES:
+ f = open('%s/js/src/%s.js' % (currdir, dependency), 'r')
+ inject_build += f.read()
+ f.close()
+
+# Open core.js, split it on our build spot, wrap junks.
+f = open('%s/js/src/core.js' % currdir, 'r')
+core = f.read()
+f.close()
+core = core.split('/*{{inject_build}}*/')
+
+# Write out a non-minified build.
+f = open('%s/js/wii.js' % currdir, 'w')
+f.write(core[0])
+f.write(inject_build)
+f.write(core[1])
+f.close()
+
+# Write out a minified build.
+minify_code('%s/js/wii.js' % currdir, '%s/js/wii.min.js' % currdir)
25 css/demo.css
@@ -0,0 +1,25 @@
+/**
+ * Wii Demo CSS
+ *
+ * Uses a basic CSS reset, and then some very rudimentary styles to make stuff easy
+ * on the eyes with the Wii console.
+ */
+
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, font, img, kbd, q, s, samp,
+small, strike, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
+margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
+:focus { outline: 0; }
+body { line-height: 1; }
+ol, ul { list-style: none; }
+table { border-collapse: separate; border-spacing: 0; }
+caption, th, td { text-align: left; font-weight: normal; }
+blockquote:before, blockquote:after, q:before, q:after { content: ""; }
+blockquote, q { quotes: "" ""; }
+
+html {
+ color: #333;
+ font: normal 30px/34px helvetica, arial, sans-serif;
+ padding: 0px;
+ text-align: center;
+ background: #f9f9f9;
+}
99 index.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Wii.js Demo</title>
+ <link rel="stylesheet" type="text/css" media="screen" href="css/demo.css">
+</head>
+<body>
+ <h1>Wii.js Demo</h1>
+ <p>
+ This is a demo page meant to show how easy it is to interact with the Nintendo Wii remotes using Javascript. It's
+ powered by <a href="http://github.com/ryanmcgrath/wii-js/">wii-js</a>, a Javascript library that abstracts the differences
+ and pain points associated with using the Wii remotes.
+ </p>
+
+ <p>
+ This demo is really simple, and works best with two Wii remotes (Wiimotes). Hold either Wiimote #1 or #2 horizontal (sideways), and use
+ the directional pad to move the box floating in the bottom right corner around. Wiimote #1 will turn the box red and fill it with a "1",
+ and Wiimote #2 will turn the box green and fill it with a "2". Have fun!
+ </p>
+
+ <p>
+ If you find bugs or want to get in touch, come find me at the project home on <a href="http://github.com/ryanmcgrath/wii-js/">GitHub</a>! You
+ can also find me on Twitter (<a href="http://twitter.com/ryanmcgrath">@ryanmcgrath</a>), or my <a href="http://venodesigns.net/">personal website</a>.
+ I'm always interested in what others are building!
+ </p>
+
+ <p>
+ - Ryan McGrath
+ </p>
+
+ <div id="x" style="border: 5px solid #010101; position: absolute; top: 300px; left: 300px; width: 100px; height: 100px; padding: 10px; color: #010101;">x</div>
+
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
+ <script src="js/wii.js"></script>
+ <script>
+ var wiimote = new Wii.Remote(1, {horizontal: true}),
+ wiimote2 = new Wii.Remote(2, {horizontal: true}),
+ x = $("#x");
+
+ wiimote2.when('pressed_up', function() {
+ x.html('2').css({
+ 'background-color': 'green',
+ 'top': parseInt(x[0].style.top) - 50
+ });
+ });
+
+ wiimote2.when('pressed_down', function() {
+ x.html('2').css({
+ 'background-color': 'green',
+ 'top': parseInt(x[0].style.top) + 50
+ });
+ });
+
+ wiimote2.when('pressed_right', function() {
+ x.html('2').css({
+ 'background-color': 'green',
+ 'left': parseInt(x[0].style.left) + 50
+ });
+
+ wiimote2.when('pressed_left', function() {
+ x.html('2').css({
+ 'background-color': 'green',
+ 'left': parseInt(x[0].style.left) - 50
+ });
+ });
+
+ wiimote.when('pressed_up', function() {
+ x.html('1').css({
+ 'background-color': 'red',
+ 'top': parseInt(x[0].style.top) - 50
+ });
+ });
+
+ wiimote.when('pressed_down', function() {
+ x.html('1').css({
+ 'background-color': 'red',
+ 'top': parseInt(x[0].style.top) + 50
+ });
+ });
+
+ wiimote.when('pressed_right', function() {
+ x.html('1').css({
+ 'background-color': 'red',
+ 'left': parseInt(x[0].style.left) + 50
+ });
+ });
+
+ wiimote.when('pressed_left', function() {
+ x.html('1').css({
+ 'background-color': 'red',
+ 'left': parseInt(x[0].style.left) - 50
+ });
+ });
+
+ Wii.listen();
+ </script>
+</body>
+</html>
27 js/src/core.js
@@ -0,0 +1,27 @@
+/**
+ * core.js
+ *
+ * This is the main template file for bringing together
+ * the various libraries that power this entire little eco-system.
+ *
+ * Building the releases requires Python (2.5+); simply run...
+ *
+ * python build.py
+ *
+ * ...from the /js/ directory.
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: Nothing, top-level file.
+ */
+
+;(function(running_inside_wii_browser) {
+ /**
+ * If we're not running inside the Nintendo Wii browser, bail out.
+ * In the future, branch here for touch-enabled devices...?
+ */
+ if(!running_inside_wii_browser) return false;
+
+ /*{{inject_build}}*/
+
+ window.Wii = Wii;
+})(window.opera && opera.wiiremote);
@jdalton
jdalton added a note

I dig stuff like opera.wiiremote, would you happen to know the value of ({}).toString.call(opera.wiiremote), if I had to guess it would be something like [[WiiRemote]]. I would use the value as part of platform.js detection.

@ryanmcgrath Owner

[object Wiiremote] is what you're looking for. Would be cool to see in platform.js!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
120 js/src/remote.js
@@ -0,0 +1,120 @@
+/**
+ * remote.js
+ *
+ * Handles the subscribing to events portion of a Wii remote. It's best to think of this
+ * as a "request" object; it asks to be notified of events, and the actual events are
+ * dispatched from the main wii.js file.
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: wii.js, util.js
+ */
+
+/**
+ * var wii_remote = new Wii.Remote(1, {...});
+ *
+ * Instantiates a Wii Remote object. Events can be set on each of these objects,
+ * and the internal game loop will fire events based on the properties subscribed
+ * to here.
+ *
+ * @param remote_id - Number, required. 1 - 4, dictates which Wiimote this object
+ * relates to.
+ * @param opts - Object, optional. Allows you to override internal settings and such,
+ * should you want different behavior.
+ * @returns Wii.Remote instance.
+ */
+Wii.Remote = function(remote_id, opts) {
+ this.remote_id = remote_id;
+ this.opts = opts;
+
+ /**
+ * If this is the "main" wii_remote, then the bitwise checks will fail
+ * because it's treated more as a "browsing" device. For these events,
+ * we'll just store the current wii_remote that's denoted as the "browsing"
+ * device and let the normal event/key delegation take care of things.
+ *
+ * The rest of the wii_remotes will go through the DISPATCHER checks that
+ * they've subscribed to.
+ */
+ var startupStatus = this.isEnabled();
+ if(startupStatus) {
+ if(!startupStatus.isBrowsing) {
+ Wii.extraRemotes.push(this);
+ } else {
+ Wii.currentBrowsingRemote = this;
+ }
+ }
+};
+
+Wii.Remote.prototype = {
+ opts: {
+ /**
+ * We default the controller to be in the vertical orientation; if
+ * it's overridden as "horizontal" (false), we'll catch it for the different key
+ * events and fire accordingly (e.g, the "up" button is different depending on
+ * how the player is holding the controller).
+ */
+ horizontal: false
+ },
+
+ /**
+ * A hash of events that this Wii remote is interested in. Each
+ * entry should be a key (evtName) with a value (response).
+ * "evtName" is the event name that corresponds with boolean functions
+ * in the DISPATCHER above, and the response is a remote-bound function
+ * to call on that event.
+ */
+ evtsInterestedIn: undefined,
+
+ /**
+ * Wiimote.isEnabled()
+ *
+ * Determines the status of the wii_remote this object is curious about. Will return
+ * an updated kPadStatus object if so, false if it's not responding or the data
+ * is sent back as "invalid". This makes it so we don't bother sending events
+ * where they're not applicable.
+ *
+ * @returns object or boolean.
+ */
+ isEnabled: function() {
+ var remote = opera.wiiremote.update(this.remote_id - 1);
+ return (remote.isEnabled && remote.isDataValid ? remote : false);
+ },
+
+ /**
+ * Wiimote.on(evtName, fn)
+ *
+ * Allows you to listen for an event on a given Wiimote. Call this on an instantiated
+ * Wiimote; "this" will be scoped to the Wiimote object. ;)
+ *
+ * @param evtName - String, a supported wii.js (DISPATCHER) event name.
+ * @param fn - Function, callback function to be executed on the event firing. Will be scoped to the Wiimote.
+ * @returns object or undefined - instantiated object this was called on to begin with, undefined if evtName is not supported.
+ */
+ when: function(evtName, fn) {
+ if(typeof Wii.DISPATCHER[evtName] !== 'undefined') {
+
+ /**
+ * THIS IS INCREDIBLY IMPORTANT, DO NOT REMOVE THIS!.
+ *
+ * The Wii's browser has an (odd...?) bug wherein if you have a prototype chain
+ * set up for a given object, and you default keys on the prototype chain to a blank object ("{}", for instance),
+ * it will _NOT_ make this a unique object, it keeps pointers to the original object that was created by the system
+ * for the first instantiated object.
+ *
+ * This is, needless to say, unlike just about any other JS environment and threw me for a loop for a good 6 hours.
+ * This line ensures that the first time this property is ever referenced, we get a fresh _CORRECTLY ALLOCATED_ chunk
+ * of memory to play with and store things in.
+ *
+ * Note that this also happens with Array structures, and conceivably anything else that would be using a copy-by-reference
+ * technique instead of a full clone. We want an object for this case, though, so we're not doing iterations on event dispatch,
+ * just a 1:1 lookup instead.
+ */
+ if(this.evtsInterestedIn === undefined) this.evtsInterestedIn = {};
+
+ this.evtsInterestedIn[evtName] = Wii.util.bind(this, fn);
+ return this;
+ }
+
+ return undefined;
+ }
+};
66 js/src/util.js
@@ -0,0 +1,66 @@
+/**
+ * util.js
+ *
+ * A basic utility wrapper; anything extra that's often re-used should
+ * find its way here (e.g, debuggerDiv, bind, etc).
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: wii.js
+ */
+
+Wii.util = {
+ /**
+ * Wii.util.debug(err);
+ *
+ * The Wii has... such little options for debugging, but we can try and make this a bit nicer.
+ * This accepts a stack trace (see example code below) and then outputs it to the screen.
+ *
+ * try { ... } catch(e) { Wii.util.debug(e); }
+ */
+ debug: function(err) {
+ if(Wii.debuggerDiv === null) {
+ Wii.debuggerDiv = document.createElement('div');
+
+ Wii.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(Wii.debuggerDiv);
+ }
+
+ if(typeof err === 'string') {
+ Wii.debuggerDiv.innerHTML = err;
+ } else {
+ var msg = '';
+ for(var e in err) { msg += e + '=' + err[e] + '<br>'; }
+ Wii.debuggerDiv.innerHTML = msg;
+ }
+
+ Wii.debuggerDiv.style.display = 'block';
+ },
+
+ /**
+ * Wiimote.util.bind(bindReference, fn)
+ *
+ * Takes a reference (an object to scope to "this" at a later runtime) and binds it to a function (fn).
+ *
+ * @param bindReference - An object to set as the "this" reference for a later function call.
+ * @param fn - A function to bind the "this" object for.
+ * @returns fn - A new function to pass around, wherein it's all scoped as you want it.
+ */
+ bind: function(bindReference, fn) {
+ return function() {
+ return fn.apply(bindReference, arguments);
+ };
+ }
+};
224 js/src/wii.js
@@ -0,0 +1,224 @@
+/**
+ * wii.js
+ *
+ * Provides a sane, event-based documented wrapper around the Wiimote controls
+ * and API inside the Opera-based Nintendo Wii web browser.
+ *
+ * This is not produced by nor endorsed by Nintendo or Opera. I've written it
+ * on my own because I see a device that's sitting in millions of living rooms
+ * but being sorely neglected because a company couldn't get their act together
+ * in regards to third party development. ;)
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: Nothing.
+ */
+
+/* Wii
+ *
+ * Top level namespace. Contains information about the main event loop, etc.
+ */
+var Wii = {
+ /**
+ * A "global" reference to the Wiimotes we're currently watching. Lets us run
+ * through on each loop/iteration and poll for a new status on it.
+ */
+ extraRemotes: [],
+ currentBrowsingRemote: null,
+ setKeyListeners: false,
+ debuggerDiv: null
+};
+
+/**
+ * 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);
+
+ /**
+ * Some keys, like the directional ones, get... multiple events?
+ * In this case, just shut. down. everything.
+ *
+ * ...and let the programmer deal with it.
+ */
+ document.addEventListener('keypress', Wii.parsePrimaryWiimote, false);
+
+ return true;
+};
+
+/**
+ * Wii.listen()
+ *
+ * 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();
+
+ var i = Wii.extraRemotes.length;
+
+ while(i--) {
+ /* Check if it's enabled; returns a kPadStatus object if so. */
+ var wii_remote = Wii.extraRemotes[i],
+ wii_remoteCurrStatus = wii_remote.isEnabled();
+
+ /* If it's enabled, huzzah, do some checks and fire appropriate events. */
+ if(wii_remoteCurrStatus) {
+ /**
+ * Do this check here as well, as the primary wiimote might've changed...
+ * Note that we don't remove it from the internal remote tracking Array; this is because
+ * if the remote that _was_ the primary one comes back online, it'll take over as the
+ * primary one again as it's the lowest ID in terms of all remotes. This check here will
+ * ensure that whatever remote is the current primary one will default to using other
+ * dispatched events instead of bitwise checks, but should all default back if another one
+ * comes online.
+ */
+ if(wii_remoteCurrStatus.isBrowsing()) {
+ Wii.currentBrowsingRemote = wii_remote;
+ } else {
+ for(var evt in wii_remote.evtsInterestedIn) {
+ var evtHappened = Wii.DISPATCHER[evt](wii_remote, wii_remoteCurrStatus);
+ if(evtHappened) wii_remote.evtsInterestedIn[evt](wii_remote, wii_remoteCurrStatus);
+ }
+ }
+ }
+ }
+
+ /**
+ * This is a better choice than working with intervals; it keeps the amount of "spasm" responses
+ * that one would normally get on the Wii to a bare minimum. This is due to how the two types of
+ * timers in JS work - intervals will queue up no matter what, and if there's a backlog, rapidly
+ * fire through all of them. Timeouts are guaranteed to always have their delay, even though at points
+ * it may end up being more (or less) than 100ms.
+ *
+ * Note that this is set to 100ms - any lower, and the Wii becomes very unresponsive for some reason. The
+ * web browser is... odd, not sure what the deal is. 100ms should be enough for most cases though...
+ */
+ return setTimeout(Wii.listen, 100);
+};
+
+/**
+ * Wii.parsePrimaryWiimote(e)
+ *
+ * The Wii browser environment is... quite oddball at times. You see, the
+ * primary Wii remote is treated differently than the other Wiimotes; it uses
+ * browser-based events (keydown, mouseup, etc) to communicate which buttons have
+ * been pressed.
+ *
+ * The "primary" Wiimote can also change at any given time (loss of battery in the main, etc).
+ *
+ * Luckily, it's not -impossible- to catch this internally. Our main library event loop catches
+ * if a given Wiimote is marked as the primary one, and will not attempt bitwise operations on it,
+ * merely wait for standard DOM events to trickle up and handle firing them appropriately.
+ *
+ * ...ugh.
+ *
+ * This method is a callback for any DOM-event listeners; accepts an event as its argument.
+ */
+Wii.parsePrimaryWiimote = function(e) {
+ /* Cancel whatever the default was, because we're going to try and normalize everything. */
+ e.preventDefault();
+
+ var wii_remote = Wii.currentBrowsingRemote,
+ wii_remoteCurrStatus = wii_remote.isEnabled(),
+ buttonPressed = Wii.PRIMARY_CONTROLLER_DISPATCHER[wii_remote.opts.horizontal ? 'horizontal' : 'vertical'][e.keyCode];
+
+ /**
+ * Filter down and figure out which "event" we're really looking at based on code
+ * matchups; this gets messy pretty quickly...
+ */
+ if(typeof buttonPressed !== 'undefined' && wii_remote.evtsInterestedIn[buttonPressed] !== 'undefined') {
+ wii_remote.evtsInterestedIn[buttonPressed](wii_remote, wii_remoteCurrStatus);
+ }
+
+ /* Doing this in conjunction with preventDefault() halts an odd clicking bug or two. */
+ return false;
+};
+
+/**
+ * Wii.PRIMARY_CONTROLLER_DISPATCHER
+ *
+ * In order to keep things as performant as possible, we want DOM events (for the primary controller)
+ * to also be a 1:1 hash map lookup. This is PRIMARILY for the primary ("browsing") controller; all other
+ * controllers get their operations routed through the DISPATCHER below.
+ */
+Wii.PRIMARY_CONTROLLER_DISPATCHER = {
+ vertical: {
+ 0: 'pressed_a',
+ 13: 'pressed_a', /* Older versions of the Wii Browser...? */
+ 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', /* Older versions of the Wii Browser...? */
+ 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'
+ }
+};
+
+/**
+ * Wii.DISPATCHER
+ *
+ * A table of the supported events that we watch for in our game loop, then fire off for respective
+ * Wiimotes. Each index is a function that does a check and returns true or false.
+ *
+ * Many of these functions use bitwise comparisons. Read up on it if you're not familiar. Note that
+ * we also take into account the orientation of the device here!
+ */
+Wii.DISPATCHER = {
+ /**
+ * These functions depend on whether or not the controller is meant to be in horizontal mode
+ * or not. Quite... different.
+ */
+ 'pressed_up': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 2;
+ return wii_remoteStatus.hold & 8;
+ },
+ 'pressed_right': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 4;
+ return wii_remoteStatus.hold & 2;
+ },
+ 'pressed_down': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 1;
+ return wii_remoteStatus.hold & 4;
+ },
+ 'pressed_left': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 8;
+ return wii_remoteStatus.hold & 1;
+ },
+
+ 'pressed_plus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16; },
+ 'pressed_minus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 4096; },
+ 'pressed_2': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 256; },
+ 'pressed_1': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 512; },
+ 'pressed_b': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 1024; },
+ 'pressed_a': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 2048; },
+
+ /**
+ * I'm keeping these noted here for legacy reasons, but by and large it's just not even
+ * worth trying to use the Nunchuk with anything in the browser; the primary controller
+ * can never read them, so there's a large chunk of functionality missing...
+ */
+ 'pressed_z': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 8192; },
+ 'pressed_c': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16384; }
+};
437 js/wii.js
@@ -0,0 +1,437 @@
+/**
+ * core.js
+ *
+ * This is the main template file for bringing together
+ * the various libraries that power this entire little eco-system.
+ *
+ * Building the releases requires Python (2.5+); simply run...
+ *
+ * python build.py
+ *
+ * ...from the /js/ directory.
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: Nothing, top-level file.
+ */
+
+;(function(running_inside_wii_browser) {
+ /**
+ * If we're not running inside the Nintendo Wii browser, bail out.
+ * In the future, branch here for touch-enabled devices...?
+ */
+ if(!running_inside_wii_browser) return false;
+
+ /**
+ * wii.js
+ *
+ * Provides a sane, event-based documented wrapper around the Wiimote controls
+ * and API inside the Opera-based Nintendo Wii web browser.
+ *
+ * This is not produced by nor endorsed by Nintendo or Opera. I've written it
+ * on my own because I see a device that's sitting in millions of living rooms
+ * but being sorely neglected because a company couldn't get their act together
+ * in regards to third party development. ;)
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: Nothing.
+ */
+
+/* Wii
+ *
+ * Top level namespace. Contains information about the main event loop, etc.
+ */
+var Wii = {
+ /**
+ * A "global" reference to the Wiimotes we're currently watching. Lets us run
+ * through on each loop/iteration and poll for a new status on it.
+ */
+ extraRemotes: [],
+ currentBrowsingRemote: null,
+ setKeyListeners: false,
+ debuggerDiv: null
+};
+
+/**
+ * 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);
+
+ /**
+ * Some keys, like the directional ones, get... multiple events?
+ * In this case, just shut. down. everything.
+ *
+ * ...and let the programmer deal with it.
+ */
+ document.addEventListener('keypress', Wii.parsePrimaryWiimote, false);
+
+ return true;
+};
+
+/**
+ * Wii.listen()
+ *
+ * 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();
+
+ var i = Wii.extraRemotes.length;
+
+ while(i--) {
+ /* Check if it's enabled; returns a kPadStatus object if so. */
+ var wii_remote = Wii.extraRemotes[i],
+ wii_remoteCurrStatus = wii_remote.isEnabled();
+
+ /* If it's enabled, huzzah, do some checks and fire appropriate events. */
+ if(wii_remoteCurrStatus) {
+ /**
+ * Do this check here as well, as the primary wiimote might've changed...
+ * Note that we don't remove it from the internal remote tracking Array; this is because
+ * if the remote that _was_ the primary one comes back online, it'll take over as the
+ * primary one again as it's the lowest ID in terms of all remotes. This check here will
+ * ensure that whatever remote is the current primary one will default to using other
+ * dispatched events instead of bitwise checks, but should all default back if another one
+ * comes online.
+ */
+ if(wii_remoteCurrStatus.isBrowsing()) {
+ Wii.currentBrowsingRemote = wii_remote;
+ } else {
+ for(var evt in wii_remote.evtsInterestedIn) {
+ var evtHappened = Wii.DISPATCHER[evt](wii_remote, wii_remoteCurrStatus);
+ if(evtHappened) wii_remote.evtsInterestedIn[evt](wii_remote, wii_remoteCurrStatus);
+ }
+ }
+ }
+ }
+
+ /**
+ * This is a better choice than working with intervals; it keeps the amount of "spasm" responses
+ * that one would normally get on the Wii to a bare minimum. This is due to how the two types of
+ * timers in JS work - intervals will queue up no matter what, and if there's a backlog, rapidly
+ * fire through all of them. Timeouts are guaranteed to always have their delay, even though at points
+ * it may end up being more (or less) than 100ms.
+ *
+ * Note that this is set to 100ms - any lower, and the Wii becomes very unresponsive for some reason. The
+ * web browser is... odd, not sure what the deal is. 100ms should be enough for most cases though...
+ */
+ return setTimeout(Wii.listen, 100);
+};
+
+/**
+ * Wii.parsePrimaryWiimote(e)
+ *
+ * The Wii browser environment is... quite oddball at times. You see, the
+ * primary Wii remote is treated differently than the other Wiimotes; it uses
+ * browser-based events (keydown, mouseup, etc) to communicate which buttons have
+ * been pressed.
+ *
+ * The "primary" Wiimote can also change at any given time (loss of battery in the main, etc).
+ *
+ * Luckily, it's not -impossible- to catch this internally. Our main library event loop catches
+ * if a given Wiimote is marked as the primary one, and will not attempt bitwise operations on it,
+ * merely wait for standard DOM events to trickle up and handle firing them appropriately.
+ *
+ * ...ugh.
+ *
+ * This method is a callback for any DOM-event listeners; accepts an event as its argument.
+ */
+Wii.parsePrimaryWiimote = function(e) {
+ /* Cancel whatever the default was, because we're going to try and normalize everything. */
+ e.preventDefault();
+
+ var wii_remote = Wii.currentBrowsingRemote,
+ wii_remoteCurrStatus = wii_remote.isEnabled(),
+ buttonPressed = Wii.PRIMARY_CONTROLLER_DISPATCHER[wii_remote.opts.horizontal ? 'horizontal' : 'vertical'][e.keyCode];
+
+ /**
+ * Filter down and figure out which "event" we're really looking at based on code
+ * matchups; this gets messy pretty quickly...
+ */
+ if(typeof buttonPressed !== 'undefined' && wii_remote.evtsInterestedIn[buttonPressed] !== 'undefined') {
+ wii_remote.evtsInterestedIn[buttonPressed](wii_remote, wii_remoteCurrStatus);
+ }
+
+ /* Doing this in conjunction with preventDefault() halts an odd clicking bug or two. */
+ return false;
+};
+
+/**
+ * Wii.PRIMARY_CONTROLLER_DISPATCHER
+ *
+ * In order to keep things as performant as possible, we want DOM events (for the primary controller)
+ * to also be a 1:1 hash map lookup. This is PRIMARILY for the primary ("browsing") controller; all other
+ * controllers get their operations routed through the DISPATCHER below.
+ */
+Wii.PRIMARY_CONTROLLER_DISPATCHER = {
+ vertical: {
+ 0: 'pressed_a',
+ 13: 'pressed_a', /* Older versions of the Wii Browser...? */
+ 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', /* Older versions of the Wii Browser...? */
+ 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'
+ }
+};
+
+/**
+ * Wii.DISPATCHER
+ *
+ * A table of the supported events that we watch for in our game loop, then fire off for respective
+ * Wiimotes. Each index is a function that does a check and returns true or false.
+ *
+ * Many of these functions use bitwise comparisons. Read up on it if you're not familiar. Note that
+ * we also take into account the orientation of the device here!
+ */
+Wii.DISPATCHER = {
+ /**
+ * These functions depend on whether or not the controller is meant to be in horizontal mode
+ * or not. Quite... different.
+ */
+ 'pressed_up': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 2;
+ return wii_remoteStatus.hold & 8;
+ },
+ 'pressed_right': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 4;
+ return wii_remoteStatus.hold & 2;
+ },
+ 'pressed_down': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 1;
+ return wii_remoteStatus.hold & 4;
+ },
+ 'pressed_left': function(wii_remote, wii_remoteStatus) {
+ if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 8;
+ return wii_remoteStatus.hold & 1;
+ },
+
+ 'pressed_plus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16; },
+ 'pressed_minus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 4096; },
+ 'pressed_2': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 256; },
+ 'pressed_1': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 512; },
+ 'pressed_b': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 1024; },
+ 'pressed_a': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 2048; },
+
+ /**
+ * I'm keeping these noted here for legacy reasons, but by and large it's just not even
+ * worth trying to use the Nunchuk with anything in the browser; the primary controller
+ * can never read them, so there's a large chunk of functionality missing...
+ */
+ 'pressed_z': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 8192; },
+ 'pressed_c': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16384; }
+};
+/**
+ * util.js
+ *
+ * A basic utility wrapper; anything extra that's often re-used should
+ * find its way here (e.g, debuggerDiv, bind, etc).
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: wii.js
+ */
+
+Wii.util = {
+ /**
+ * Wii.util.debug(err);
+ *
+ * The Wii has... such little options for debugging, but we can try and make this a bit nicer.
+ * This accepts a stack trace (see example code below) and then outputs it to the screen.
+ *
+ * try { ... } catch(e) { Wii.util.debug(e); }
+ */
+ debug: function(err) {
+ if(Wii.debuggerDiv === null) {
+ Wii.debuggerDiv = document.createElement('div');
+
+ Wii.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(Wii.debuggerDiv);
+ }
+
+ if(typeof err === 'string') {
+ Wii.debuggerDiv.innerHTML = err;
+ } else {
+ var msg = '';
+ for(var e in err) { msg += e + '=' + err[e] + '<br>'; }
+ Wii.debuggerDiv.innerHTML = msg;
+ }
+
+ Wii.debuggerDiv.style.display = 'block';
+ },
+
+ /**
+ * Wiimote.util.bind(bindReference, fn)
+ *
+ * Takes a reference (an object to scope to "this" at a later runtime) and binds it to a function (fn).
+ *
+ * @param bindReference - An object to set as the "this" reference for a later function call.
+ * @param fn - A function to bind the "this" object for.
+ * @returns fn - A new function to pass around, wherein it's all scoped as you want it.
+ */
+ bind: function(bindReference, fn) {
+ return function() {
+ return fn.apply(bindReference, arguments);
+ };
+ }
+};
+/**
+ * remote.js
+ *
+ * Handles the subscribing to events portion of a Wii remote. It's best to think of this
+ * as a "request" object; it asks to be notified of events, and the actual events are
+ * dispatched from the main wii.js file.
+ *
+ * @Author: Ryan McGrath <ryan@venodesigns.net>
+ * @Requires: wii.js, util.js
+ */
+
+/**
+ * var wii_remote = new Wii.Remote(1, {...});
+ *
+ * Instantiates a Wii Remote object. Events can be set on each of these objects,
+ * and the internal game loop will fire events based on the properties subscribed
+ * to here.
+ *
+ * @param remote_id - Number, required. 1 - 4, dictates which Wiimote this object
+ * relates to.
+ * @param opts - Object, optional. Allows you to override internal settings and such,
+ * should you want different behavior.
+ * @returns Wii.Remote instance.
+ */
+Wii.Remote = function(remote_id, opts) {
+ this.remote_id = remote_id;
+ this.opts = opts;
+
+ /**
+ * If this is the "main" wii_remote, then the bitwise checks will fail
+ * because it's treated more as a "browsing" device. For these events,
+ * we'll just store the current wii_remote that's denoted as the "browsing"
+ * device and let the normal event/key delegation take care of things.
+ *
+ * The rest of the wii_remotes will go through the DISPATCHER checks that
+ * they've subscribed to.
+ */
+ var startupStatus = this.isEnabled();
+ if(startupStatus) {
+ if(!startupStatus.isBrowsing) {
+ Wii.extraRemotes.push(this);
+ } else {
+ Wii.currentBrowsingRemote = this;
+ }
+ }
+};
+
+Wii.Remote.prototype = {
+ opts: {
+ /**
+ * We default the controller to be in the vertical orientation; if
+ * it's overridden as "horizontal" (false), we'll catch it for the different key
+ * events and fire accordingly (e.g, the "up" button is different depending on
+ * how the player is holding the controller).
+ */
+ horizontal: false
+ },
+
+ /**
+ * A hash of events that this Wii remote is interested in. Each
+ * entry should be a key (evtName) with a value (response).
+ * "evtName" is the event name that corresponds with boolean functions
+ * in the DISPATCHER above, and the response is a remote-bound function
+ * to call on that event.
+ */
+ evtsInterestedIn: undefined,
+
+ /**
+ * Wiimote.isEnabled()
+ *
+ * Determines the status of the wii_remote this object is curious about. Will return
+ * an updated kPadStatus object if so, false if it's not responding or the data
+ * is sent back as "invalid". This makes it so we don't bother sending events
+ * where they're not applicable.
+ *
+ * @returns object or boolean.
+ */
+ isEnabled: function() {
+ var remote = opera.wiiremote.update(this.remote_id - 1);
+ return (remote.isEnabled && remote.isDataValid ? remote : false);
+ },
+
+ /**
+ * Wiimote.on(evtName, fn)
+ *
+ * Allows you to listen for an event on a given Wiimote. Call this on an instantiated
+ * Wiimote; "this" will be scoped to the Wiimote object. ;)
+ *
+ * @param evtName - String, a supported wii.js (DISPATCHER) event name.
+ * @param fn - Function, callback function to be executed on the event firing. Will be scoped to the Wiimote.
+ * @returns object or undefined - instantiated object this was called on to begin with, undefined if evtName is not supported.
+ */
+ when: function(evtName, fn) {
+ if(typeof Wii.DISPATCHER[evtName] !== 'undefined') {
+
+ /**
+ * THIS IS INCREDIBLY IMPORTANT, DO NOT REMOVE THIS!.
+ *
+ * The Wii's browser has an (odd...?) bug wherein if you have a prototype chain
+ * set up for a given object, and you default keys on the prototype chain to a blank object ("{}", for instance),
+ * it will _NOT_ make this a unique object, it keeps pointers to the original object that was created by the system
+ * for the first instantiated object.
+ *
+ * This is, needless to say, unlike just about any other JS environment and threw me for a loop for a good 6 hours.
+ * This line ensures that the first time this property is ever referenced, we get a fresh _CORRECTLY ALLOCATED_ chunk
+ * of memory to play with and store things in.
+ *
+ * Note that this also happens with Array structures, and conceivably anything else that would be using a copy-by-reference
+ * technique instead of a full clone. We want an object for this case, though, so we're not doing iterations on event dispatch,
+ * just a 1:1 lookup instead.
+ */
+ if(this.evtsInterestedIn === undefined) this.evtsInterestedIn = {};
+
+ this.evtsInterestedIn[evtName] = Wii.util.bind(this, fn);
+ return this;
+ }
+
+ return undefined;
+ }
+};
+
+
+ window.Wii = Wii;
+})(window.opera && opera.wiiremote);
1  js/wii.min.js
@@ -0,0 +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{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];if(typeof c!=="undefined"&&f.evtsInterestedIn[c]!=="undefined"){f.evtsInterestedIn[c](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},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]+"<br>"}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;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);
104 readme.md
@@ -0,0 +1,104 @@
+wii-js
+==============================================================================================
+The Nintendo Wii is an entertainment system with an utterly _massive_ install base, and when
+you couple it with the fact that it's got a web browser (mostly) built in, there's a lot of
+potential for third party development. Sadly, few have opted to do any sort of development for
+it. While it doesn't help that Nintendo pretty much dropped the ball on this opportunity, the
+experience of browsing the web on the Wii isn't actually that compelling to begin with.
+
+That said, I think this can serve one other purpose: it's an ideal environment to teach children
+how to program! I created this library to sanitize Wii interaction with webpages in the browser,
+as it's notoriously crippled. It aims to offer a solid, documented, performant API that's easy to
+understand and pick up. With this library, you can have up to 4 Wii-motes interacting with your
+webpage at once, a dynamic not found in other web browsing mediums.
+
+Questions, comments, criticism and praise can be directed to me at the following outlets:
+
+- You can email me at **ryan [at] venodesigns (dot) net**.
+- You can hit me up on Twitter: [@ryanmcgrath](http://twitter.com/ryanmcgrath/)
+- Contact me through **[my website](http://venodesigns.net)**
+- **Technical issues can be filed on the [wii-js GitHub Issues Tracker](https://github.com/ryanmcgrath/wii-js/issues)**
+
+Example Usage
+----------------------------------------------------------------------------------------------
+``` javascript
+var wiimote = new Wii.Remote(1, {horizontal: true}),
+ wiimote2 = new Wii.Remote(2, {horizontal: true});
+
+wiimote.when('pressed_a', function() {
+ alert('Wiimote #1 pressed the A Button!');
+});
+
+wiimote2.when('pressed_a', function() {
+ alert('Wiimote #2 pressed the A Button!');
+});
+```
+
+Technical Documentation
+----------------------------------------------------------------------------------------------
+The largest issue with making interactive pages that work with the Wii has been that the API has
+been nothing short of a black hole. When you actually begin to dig in and figure out what's going on,
+it gets even uglier to see - the primary wiimote, for instance, has a totally different set of signals
+than the other three.
+
+wii-js abstracts away most of these differences and/or problems, and works on a very simple event-dispatch
+system. What this means is that you create an instance of a Wii Remote, subscribe to events, and provide a
+function to get called when that event has occurred. The following syntax should explain this:
+
+``` javascript
+wiimote.when('event_name_here', function() { /* My callback function */ });
+```
+
+When instantiating a Wii Remote instance, you can choose to have the library interpret directional pad controls
+in horizontal or vertical mode. You can change this at any point, if you want, by simply swapping the property.
+
+``` javascript
+var wiimote = new Wii.Remote(1, {horizontal: true}); // Horizontal controls
+var wiimote = new Wii.Remote(1, {horizontal: false}); // Vertical controls
+
+wiimote.opts.horizontal = true; // Change to horizontal scheme.
+```
+
+You can listen for the following events on all controllers:
+
+- **pressed_up** - The up button was pressed.
+- **pressed_down** - The down button was pressed.
+- **pressed_left** - The left button was pressed.
+- **pressed_right** - The right button was pressed.
+- **pressed_a** - The A button was pressed.
+- **pressed_1** - The 1 button was pressed. (_Note: On controller 1, this triggers a menu - work in progress..._)
+- **pressed_2** - The 2 button was pressed.
+- **pressed_plus** - The plus (+) button was pressed.
+- **pressed_minus** - The minus (-) button was pressed.
+- **roll_change** - The roll of the controller (balance) changed. You can get the current roll in radians with _"this.roll"_; positive is upright, negative is the other.
+- **distance_change** - The distance of the wiimote (in meters) from the TV/sensor bar has changed. This event isn't totally reliable, but should work for most cases.
+
+You can listen for the following events on _extra controllers_, but not the primary controller.
+
+- **pressed_b** - The B button was pressed.
+- **pressed_c** - The C button (on the Nunchuk) was pressed.
+- **pressed_z** - The Z button (on the Nunchuk) was pressed.
+
+You can also get the following properties from any Wii Remote instance; they will return "undefined" if the remote
+isn't able to see the TV/sensor bar, so be sure to check this!
+
+- **x** - The x coordinate where the Wii Remote is pointing to on the screen. Generally between 0 and 800, but can be more on wide pages.
+- **y** - The y coordinate where the Wii Remote is pointing to on the screen. Odd one; can be found as low as -48, as high as the height
+of the current webpage + toolbar height, if enabled. Tinker with this one for your purposes.
+
+Why the button limitations?
+------------------------------------------------------------------------------------------------------------------
+The Nintendo Wii treats the primary controller differently than the other ones, and doesn't report any action
+from the Nunchuk, nor does it report when someone has pressed the "B" button on the primary controller (as it's used
+for scrolling a page).
+
+The Wii Browser also doesn't report data for Gamecube controllers, the Classic controller, or any other accessories.
+
+It's a work in progress to see what can be done about these, but it's impossible to guarantee anything will come out
+of it unless Nintendo and/or Opera can come out with something new.
+
+
+Licensing, etc
+-------------------------------------------------------------------------------------------------------------------
+wii-js is released under an MIT license. Just provide credit where need be if you choose to use this, it's taken quite
+a bit of my time to decipher the utterly random pieces and intricacies of this Javascript engine. ;)
BIN  utilities/yuicompressor-2.4.2.jar
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.