src/keys.js
function Combo(key, meta) {
        var keys = null;
        if (arguments.length === 2 && meta instanceof Array) {
            keys = meta;
        }
        else if (arguments.length >= 2) {
            keys = Array.prototype.slice.call(arguments, 1);
        }
        else if (arguments.length === 1) {
            this.key   = key;
            this.ctrl  = key.eq(Key.CTRL);
            this.shift = key.eq(Key.SHIFT);
            this.alt   = key.eq(Key.ALT);
            this.meta  = key.eq(Key.META) || key.eq(Key.META_RIGHT);
            return;
        }
        else {
            throw new Error('Combo: Invalid number of arguments provided.');
        }

        var invalid = find(keys, function(k) {
            switch (k.code) {
                case Key.CTRL.code:
                case Key.SHIFT.code:
                case Key.ALT.code:
                case Key.META.code:
                case Key.META_RIGHT.code:
                    return false;
                default:
                    return true;
            }
        });

        if (invalid) {
            throw new Error('Combo: Attempted to create a Combo with multiple non-meta Keys. This is not supported.');
        }

        this.key   = key;
        this.ctrl  = hasKey(keys, Key.CTRL)  || key.eq(Key.CTRL);
        this.shift = hasKey(keys, Key.SHIFT) || key.eq(Key.SHIFT);
        this.alt   = hasKey(keys, Key.ALT)   || key.eq(Key.ALT);
        this.meta  = hasKey(keys, Key.META)  || hasKey(keys, Key.META_RIGHT);
        this.meta  = this.meta || (key.eq(Key.META) || key.eq(Key.META_RIGHT));

        function hasKey(collection, k) {
            return find(collection, function(x) { return k.eq(x); }) !== null;
        }
    }
function Combo(key, meta) {
        var keys = null;
        if (arguments.length === 2 && meta instanceof Array) {
            keys = meta;
        }
        else if (arguments.length >= 2) {
            keys = Array.prototype.slice.call(arguments, 1);
        }
        else if (arguments.length === 1) {
            this.key   = key;
            this.ctrl  = key.eq(Key.CTRL);
            this.shift = key.eq(Key.SHIFT);
            this.alt   = key.eq(Key.ALT);
            this.meta  = key.eq(Key.META) || key.eq(Key.META_RIGHT);
            return;
        }
        else {
            throw new Error('Combo: Invalid number of arguments provided.');
        }

        var invalid = find(keys, function(k) {
            switch (k.code) {
                case Key.CTRL.code:
                case Key.SHIFT.code:
                case Key.ALT.code:
                case Key.META.code:
                case Key.META_RIGHT.code:
                    return false;
                default:
                    return true;
            }
        });

        if (invalid) {
            throw new Error('Combo: Attempted to create a Combo with multiple non-meta Keys. This is not supported.');
        }

        this.key   = key;
        this.ctrl  = hasKey(keys, Key.CTRL)  || key.eq(Key.CTRL);
        this.shift = hasKey(keys, Key.SHIFT) || key.eq(Key.SHIFT);
        this.alt   = hasKey(keys, Key.ALT)   || key.eq(Key.ALT);
        this.meta  = hasKey(keys, Key.META)  || hasKey(keys, Key.META_RIGHT);
        this.meta  = this.meta || (key.eq(Key.META) || key.eq(Key.META_RIGHT));

        function hasKey(collection, k) {
            return find(collection, function(x) { return k.eq(x); }) !== null;
        }
    }
function Combo ( key , meta ) { var keys = null ; if ( arguments . length === 2 && meta instanceof Array ) { keys = meta ; } else if ( arguments . length >= 2 ) { keys = Array . prototype . slice . call ( arguments , 1 ) ; } else if ( arguments . length === 1 ) { this . key = key ; this . ctrl = key . eq ( Key . CTRL ) ; this . shift = key . eq ( Key . SHIFT ) ; this . alt = key . eq ( Key . ALT ) ; this . meta = key . eq ( Key . META ) || key . eq ( Key . META_RIGHT ) ; return ; } else { throw new Error ( 'Combo: Invalid number of arguments provided.' ) ; } var invalid = find ( keys , function ( k ) { switch ( k . code ) { case Key . CTRL . code : case Key . SHIFT . code : case Key . ALT . code : case Key . META . code : case Key . META_RIGHT . code : return false ; default : return true ; } } ) ; if ( invalid ) { throw new Error ( 'Combo: Attempted to create a Combo with multiple non-meta Keys. This is not supported.' ) ; } this . key = key ; this . ctrl = hasKey ( keys , Key . CTRL ) || key . eq ( Key . CTRL ) ; this . shift = hasKey ( keys , Key . SHIFT ) || key . eq ( Key . SHIFT ) ; this . alt = hasKey ( keys , Key . ALT ) || key . eq ( Key . ALT ) ; this . meta = hasKey ( keys , Key . META ) || hasKey ( keys , Key . META_RIGHT ) ; this . meta = this . meta || ( key . eq ( Key . META ) || key . eq ( Key . META_RIGHT ) ) ; function hasKey ( collection , k ) { return find ( collection , function ( x ) { return k . eq ( x ) ; } ) !== null ; } }
Creates a new Combo from a key code and array of meta key codes

@class
@classdesc Combo represents the physical combination of a single key and any meta keys
that ultimately are used to trigger a keybinding. It is at the Combo level
that we match a configured keybinding with the current set of pressed keys.

@example
var combo = new Combo(Key.A, [ Key.CTRL, Key.SHIFT ]);

@namespace Combo
@constructor
@param {Key} key - The primary Key for this Combo.
@param {array} meta - An array of meta Keys needed for this Combo to be activated. {optional}
Creates a new Combo from a key code and array of meta key codes