// ==UserScript==
// @name ZenzaGamePad
// @namespace https://github.com/segabito/
// @description ZenzaWatchをゲームパッドで操作
// @include http://www.nicovideo.jp/*
// @version 1.2.4
// @author segabito macmoto
// @license public domain
// @grant none
// @noframes
// ==/UserScript==
// 推奨
//
// XInput系 (XboxOne, Xbox360コントローラ等)
// DualShock4
// USBサターンパッド
// 8bitdo FC30系
(function() {
var monkey = function(ZenzaWatch) {
if (!window.navigator.getGamepads) {
window.console.log('%cGamepad APIがサポートされていません', 'background: red; color: yellow;');
return;
}
var _ = ZenzaWatch.lib._;
var $ = ZenzaWatch.lib.$;
var isZenzaWatchOpen = false;
var console;
var debugMode = !true;
var dummyConsole = {
log: _.noop, error: _.noop, time: _.noop, timeEnd: _.noop, trace: _.noop
};
console = debugMode ? window.console : dummyConsole;
var isPauseButtonDown = false;
var isRate1ButtonDown = false;
var execCommand = function(command, param) {
ZenzaWatch.external.execCommand(command, param);
};
var speedUp = function() {
// TODO:
// configを直接参照するのはお行儀が悪いのでexternalのインターフェースをつける
var current = parseFloat(ZenzaWatch.config.getValue('playbackRate'), 10);
window.console.log('speedUp', current);
execCommand('playbackRate', Math.floor(Math.min(current + 0.1, 3) * 10) / 10);
};
var speedDown = function() {
// TODO:
// configを直接参照するのはお行儀が悪いのでexternalのインターフェースをつける
var current = parseFloat(ZenzaWatch.config.getValue('playbackRate'), 10);
window.console.log('speedDown', current);
execCommand('playbackRate', Math.floor(Math.max(current - 0.1, 0.1) * 10) / 10);
};
var swapABXY_FC30 = function(btn) {
switch (btn) {
case 0: return 1;
case 1: return 0;
case 3: return 4;
case 4: return 3;
}
return btn;
};
var onButtonDown = function(button, deviceId) {
if (!isZenzaWatchOpen) { return; }
if (deviceId.match(/Vendor: 04b4 Product: 010a/i)) {
//USB Gamepad (Vendor: 04b4 Product: 010a)"
return onButtonDownSaturn(button, deviceId);
}
// FC30なのにみんなVendor違うってどういうことだよ
if (deviceId.match(/Vendor: (3810|05a0|1235)/i)) {
return onButtonDownFC30(button, deviceId);
}
switch (button) {
case 0: // A
isPauseButtonDown = true;
execCommand('togglePlay');
break;
case 1: // B
execCommand('toggleMute');
break;
case 2: // X
execCommand('toggleComment');
break;
case 3: // Y
isRate1ButtonDown = true;
execCommand('playbackRate', 0.1);
break;
case 4: // LB
execCommand('playPreviousVideo');
break;
case 5: // RB
execCommand('playNextVideo');
break;
case 6: // LT
execCommand('playbackRate', 0.5);
break;
case 7: // RT
execCommand('playbackRate', 3);
break;
case 8: // しいたけの左 ビューボタン (Back)
execCommand('close');
break;
case 9: // しいたけの右 メニューボタン (Start)
execCommand('deflistAdd');
break;
case 10: // Lスティック
execCommand('seek', 0);
break;
case 11: // Rスティック
break;
case 12: // up
if (isPauseButtonDown) {
speedUp();
} else {
execCommand('volumeUp');
}
break;
case 13: // down
if (isPauseButtonDown) {
speedUp();
} else {
execCommand('volumeDown');
}
break;
case 14: // left
execCommand('seekBy', isRate1ButtonDown ? -1 : -5);
break;
case 15: // right
execCommand('seekBy', isRate1ButtonDown ? +1 : +5);
break;
}
};
var onButtonDownSaturn = function(button, deviceId) {
switch (button) {
case 0: // A
isPauseButtonDown = true;
execCommand('togglePlay');
break;
case 1: // B
execCommand('toggleMute');
break;
case 2: // C
execCommand('toggleComment');
break;
case 3: // X
execCommand('playbackRate', 0.5);
break;
case 4: // Y
isRate1ButtonDown = true;
execCommand('playbackRate', 0.1);
break;
case 5: // Z
execCommand('playbackRate', 3);
break;
case 6: // L
execCommand('playPreviousVideo');
break;
case 7: // R
execCommand('playNextVideo');
break;
case 8: // START
execCommand('deflistAdd');
break;
}
};
var onButtonDownFC30 = function(button, deviceId) {
if (deviceId.match(/Product: (3232)/i)) { // FC30 Zero / FC30
button = swapABXY_FC30(button);
}
switch (button) {
case 0: // B
execCommand('toggleMute');
break;
case 1: // A
isPauseButtonDown = true;
execCommand('togglePlay');
break;
case 2: // ???
//execCommand('toggleComment');
break;
case 3: // X
isRate1ButtonDown = true;
execCommand('playbackRate', 0.1);
break;
case 4: // Y
execCommand('toggleComment');
break;
case 5: //
break;
case 6: // L1
if (isPauseButtonDown) {
execCommand('playPreviousVideo');
} else {
execCommand('playbackRate', 0.5);
}
break;
case 7: // R1
if (isPauseButtonDown) {
execCommand('playNextVideo');
} else {
execCommand('playbackRate', 3);
}
break;
case 8: // L2
execCommand('playPreviousVideo');
break;
case 9: // R2
execCommand('playNextVideo');
break;
case 10: // SELECT
execCommand('close');
break;
case 11: // START
execCommand('deflistAdd');
break;
case 13: // Lスティック
execCommand('seek', 0);
break;
case 14: // Rスティック
break;
}
};
var onButtonUp = function(button, deviceId) {
if (!isZenzaWatchOpen) { return; }
if (deviceId.match(/Vendor: 04b4 Product: 010a/i)) {
//USB Gamepad (Vendor: 04b4 Product: 010a)"
return onButtonUpSaturn(button, deviceId);
}
if (deviceId.match(/Vendor: (3810|05a0|1235)/i)) {
return onButtonUpFC30(button, deviceId);
}
switch (button) {
case 0: // A
isPauseButtonDown = false;
break;
case 1: // B
break;
case 2: // X
break;
case 3: // Y
isRate1ButtonDown = false;
execCommand('playbackRate', 1.0);
break;
case 4: // LB
break;
case 5: // RB
break;
case 6: // LT
break;
case 7: // RT
execCommand('playbackRate', 1.5);
break;
case 8: // しいたけの左 ビューボタン (Back)
break;
case 9: // しいたけの右 メニューボタン (Start)
break;
case 10: // Lスティック
break;
case 11: // Rスティック
break;
case 12: // up
break;
case 13: // down
break;
case 14: // left
break;
case 15: // right
break;
}
};
var onButtonUpSaturn = function(button, deviceId) {
switch (button) {
case 0: // A
isPauseButtonDown = false;
break;
case 1: // B
break;
case 2: // C
break;
case 3: // X
break;
case 4: // Y
isRate1ButtonDown = false;
execCommand('playbackRate', 1.0);
break;
case 5: // Z
execCommand('playbackRate', 1.5);
break;
case 6: // L
break;
case 7: // R
break;
case 8: // START
break;
}
};
var onButtonUpFC30 = function(button, deviceId) {
if (deviceId.match(/Product: (3232)/i)) { // FC30Zero / FC30
button = swapABXY_FC30(button);
}
switch (button) {
case 0: // B
break;
case 1: // A
isPauseButtonDown = false;
break;
case 2: // ???
break;
case 3: // X
isRate1ButtonDown = false;
execCommand('playbackRate', 1.0);
break;
case 4: // Y
break;
case 5: //
break;
case 6: // L1
break;
case 7: // R1
if (isPauseButtonDown) { return; }
execCommand('playbackRate', 1.5);
break;
case 8: // L2
break;
case 9: // R2
break;
case 10: // SELECT
break;
case 11: // START
break;
case 13: // Lスティック
break;
case 14: // Rスティック
break;
}
};
var onButtonRepeat = function(button) {
if (!isZenzaWatchOpen) { return; }
switch (button) {
case 12: // up
if (isPauseButtonDown) {
speedUp();
} else {
execCommand('volumeUp');
}
break;
case 13: // down
if (isPauseButtonDown) {
speedUp();
} else {
execCommand('volumeDown');
}
break;
case 14: // left
execCommand('seekBy', isRate1ButtonDown ? -1 : -5);
break;
case 15: // right
execCommand('seekBy', isRate1ButtonDown ? +1 : +5);
break;
}
};
var onAxisChange = function(axis, value, deviceId) {
if (!isZenzaWatchOpen) { return; }
if (Math.abs(value) < 0.1) { return; }
var isFC30 = deviceId.match(/Vendor: 3810/i) ? true : false;
if (isFC30) {
switch (axis) {
case 3: // L2なぜか反応する
case 4: // R2なぜか反応する
return;
case 5: // FC30のRスティック上下?
axis = 3;
break;
}
}
switch (axis) {
case 0: // Lスティック X
var step = isRate1ButtonDown ? 1 : 5;
execCommand('seekBy', (value < 0 ? -1 : 1) * step);
break;
case 1: // Lスティック Y
if (isPauseButtonDown) {
if (value < 0) { speedUp(); }
else { speedDown(); }
} else {
execCommand(value < 0 ? 'volumeUp' : 'volumeDown');
}
break;
case 2: // Rスティック X
break;
case 3: // Rスティック Y
if (value < 0) { speedUp(); }
else { speedDown(); }
break;
}
};
var onAxisRepeat = function(axis, value) {
if (!isZenzaWatchOpen) { return; }
if (Math.abs(value) < 0.1) { return; }
switch (axis) {
case 0: // Lスティック X
var step = isRate1ButtonDown ? 1 : +5;
execCommand('seekBy', (value < 0 ? -1 : 1) * step);
break;
case 1: // Lスティック Y
if (isPauseButtonDown) {
if (value < 0) { speedUp(); }
else { speedDown(); }
} else {
execCommand(value < 0 ? 'volumeUp' : 'volumeDown');
}
break;
case 2: // Rスティック X
break;
case 3: // Rスティック Y
if (value < 0) { speedUp(); }
else { speedDown(); }
break;
}
};
var onPovChange = function(pov) {
switch(pov) {
case 'up':
execCommand('volumeUp');
break;
case 'down':
execCommand('volumeDown');
break;
case 'left':
execCommand('seekBy', isRate1ButtonDown ? -1 : -5);
break;
case 'right':
execCommand('seekBy', isRate1ButtonDown ? +1 : +5);
break;
}
};
var onPovRepeat = function(pov) {
switch(pov) {
case 'up':
execCommand('volumeUp');
break;
case 'down':
execCommand('volumeDown');
break;
case 'left':
execCommand('seekBy', isRate1ButtonDown ? -1 : -5);
break;
case 'right':
execCommand('seekBy', isRate1ButtonDown ? +1 : +5);
break;
}
};
var PollingTimer = (function() {
var id = 0;
var PollingTimer = function(callback, interval) {
this._id = id++;
this.initialize(callback, interval);
};
_.assign(PollingTimer.prototype, {
initialize: function(callback, interval) {
this._timer = null;
this._callback = callback;
if (typeof interval === 'number') {
this.changeInterval(interval);
}
},
changeInterval: function(interval) {
if (this._timer) {
if (this._currentInterval === interval) {
return;
}
window.clearInterval(this._timer);
}
console.log('%cupdate Interval:%s', 'background: lightblue;', interval);
this._currentInterval = interval;
this._timer = window.setInterval(this._callback, interval);
},
pause: function() {
window.clearInterval(this._timer);
this._timer = null;
},
start: function() {
if (typeof this._currentInterval !== 'number') {
return;
}
this.changeInterval(this._currentInterval);
}
});
return PollingTimer;
})();
var GamePadModel = (function($, _, emitter) {
var GamePadModel = function(gamepadStatus) {
this._gamepadStatus = gamepadStatus;
this._buttons = [];
this._axes = [];
this._pov = '';
this._povRepeat = 0;
this.initialize(gamepadStatus);
};
_.extend(GamePadModel.prototype, emitter.prototype);
_.assign(GamePadModel.prototype, {
initialize: function(gamepadStatus) {
this._buttons.length = gamepadStatus.buttons.length;
this._axes.length = gamepadStatus.axes.length;
this._id = gamepadStatus.id;
this._index = gamepadStatus.index;
this.reset();
},
reset: function() {
var i, len;
this._pov = '';
this._povRepeat = 0;
for (i = 0, len = this._gamepadStatus.buttons.length + 16; i < len; i++) {
this._buttons[i] = {pressed: false, repeat: 0};
}
for (i = 0, len = this._gamepadStatus.axes.length; i < len; i++) {
this._axes[i] = {value: null, repeat: 0};
}
},
update: function() {
var gamepadStatus = (navigator.getGamepads())[this._index];
// gp || this._gamepadStatus;
if (!gamepadStatus) { console.log('no status'); return; }
this._gamepadStatus = gamepadStatus;
var buttons = gamepadStatus.buttons, axes = gamepadStatus.axes;
var i, len, axis;
for (i = 0, len = Math.min(this._buttons.length, buttons.length); i < len; i++) {
var buttonStatus = buttons[i].pressed ? 1 : 0;
if (this._buttons[i].pressed !== buttonStatus) {
var eventName = (buttonStatus === 1) ? 'onButtonDown' : 'onButtonUp';
//console.log('%cbutton%s:%s', 'background: lightblue;', i, buttonStatus, 0);
this.emit(eventName, i, 0);
this.emit('onButtonStatusChange', i, buttonStatus);
}
this._buttons[i].pressed = buttonStatus;
if (buttonStatus) {
this._buttons[i].repeat++;
if (this._buttons[i].repeat % 5 === 0) {
//console.log('%cbuttonRepeat%s', 'background: lightblue;', i);
this.emit('onButtonRepeat', i);
}
} else {
this._buttons[i].repeat = 0;
}
}
for (i = 0, len = Math.min(8, this._axes.length); i < len; i++) {
axis = Math.round(axes[i] * 1000) / 1000;
if (this._axes[i].value === null) {
this._axes[i].value = axis;
continue;
}
var diff = Math.round(Math.abs(axis - this._axes[i].value));
if (diff >= 1) {
//window.console.log(
// '%c%s %s',
// 'background: lightblue;', 'onAxisChange',
// i, axis, 0, this._axes[i]);
this.emit('onAxisChange', i, axis);
}
if (Math.abs(axis) <= 0.1) {
this._axes[i].repeat = 0;
this.emit('onAxisRelease', i);
} else {
this._axes[i].repeat++;
//if (this._axes[i].repeat % 5 === 0) {
// //window.console.log('%caxisRepeat%s:%s', 'background: lightblue;', i, axis);
// this.emit('onAxisRepeat', i, axis);
//}
}
this._axes[i].value = axis;
}
// ハットスイッチ? FC30だけ?
if (axes[9]) {
var p = Math.round(axes[9] * 1000);
var d;
if (p < -500) { d = 'up';
} else if (p < 0) { d = 'right';
} else if (p > 3000) { d = '';
} else if (p > 500){ d = 'left';
} else { d = 'down'; }
//if (d) { window.console.log('pov?:', axes[9], d, p); }
if (this._pov !== d) {
this._pov = d;
this._povRepeat = 0;
this.emit('onPovChange', this._pov);
} else if (d !== '') {
this._povRepeat++;
if (this._povRepeat % 5 === 0) {
this.emit('onPovRepeat', this._pov);
}
}
}
//console.log(JSON.stringify(this.dump()));
},
dump: function() {
var gamepadStatus = this._gamepadStatus, buttons = gamepadStatus.buttons, axes = gamepadStatus.axes;
var i, len, btmp = [], atmp = [];
for (i = 0, len = axes.length; i < len; i++) {
atmp.push('ax' + i + ': ' + axes[i]);
}
for (i = 0, len = buttons.length; i < len; i++) {
btmp.push('bt' + i + ': ' + (buttons[i].pressed ? 1 : 0));
}
return atmp.join('\n') + '\n' + btmp.join(', ');
},
getX: function() {
return this._axes.length > 0 ? this._axes[0] : 0;
},
getY: function() {
return this._axes.length > 1 ? this._axes[1] : 0;
},
getZ: function() {
return this._axes.length > 2 ? this._axes[2] : 0;
},
getButtonCount: function() {
return this._buttons ? this._buttons.length : 0;
},
getButtonStatus: function(index) {
return this._buttons[index] || 0;
},
getAxisCount: function() {
return this._axes ? this._axes.length : 0;
},
getAxisValue: function(index) {
return this._axes[index] || 0;
},
isConnected: function() {
return !!this._gamepadStatus.connected;
},
getDeviceIndex: function() {
return this._index;
},
getDeviceId: function() {
return this._id;
},
getPov: function() {
return this._pov;
},
release: function() {
// TODO: clear events
}
});
return GamePadModel;
})($, _, ZenzaWatch.lib.AsyncEmitter);
var ZenzaGamePad = (function ($, PollingTimer, GamePadModel) {
var primaryGamepad = null;
var pollingTimer = null;
var ZenzaGamePad = new ZenzaWatch.lib.AsyncEmitter();
var detectGamepad = function() {
if (primaryGamepad) {
return;
}
var gamepads = navigator.getGamepads();
if (gamepads.length > 0) {
var pad = _.find(gamepads, (pad) => {
return pad !== undefined &&
pad.id &&
// windowsにDualShock4を繋ぐとあらわれる謎のデバイス
!pad.id.match(/Vendor: 00ff/i);
});
if (!pad) { return; }
window.console.log(
'%cdetect gamepad index: %s, id: "%s"',
'background: lightgreen; font-weight: bolder;',
pad.index, pad.id
);
var gamepad = new GamePadModel(pad);
primaryGamepad = gamepad;
var self = ZenzaGamePad;
var onButtonDown = function(number) {
self.emit('onButtonDown', number, gamepad.getDeviceIndex());
};
var onButtonRepeat = function(number) {
self.emit('onButtonRepeat', number, gamepad.getDeviceIndex());
};
var onButtonUp = function(number) {
self.emit('onButtonUp', number, gamepad.getDeviceIndex());
};
var onAxisChange = function(number, value) {
self.emit('onAxisChange', number, value, gamepad.getDeviceIndex());
};
var onAxisRepeat = function(number, value) {
self.emit('onAxisRepeat', number, value, gamepad.getDeviceIndex());
};
var onAxisRelease = function(number) {
self.emit('onAxisRelease', number, gamepad.getDeviceIndex());
};
var onPovChange = function(pov) {
self.emit('onPovChange', pov, gamepad.getDeviceIndex());
};
var onPovRepeat = function(pov) {
self.emit('onPovRepeat', pov, gamepad.getDeviceIndex());
};
gamepad.on('onButtonDown', onButtonDown);
gamepad.on('onButtonRepeat', onButtonRepeat);
gamepad.on('onButtonUp', onButtonUp);
gamepad.on('onAxisChange', onAxisChange);
gamepad.on('onAxisRepeat', onAxisRepeat);
gamepad.on('onAxisRelease', onAxisRelease);
gamepad.on('onPovChange', onPovChange);
gamepad.on('onPovRepeat', onPovRepeat);
self.emit('onDeviceConnect', gamepad.getDeviceIndex(), gamepad.getDeviceId());
pollingTimer.changeInterval(30);
}
};
var onGamepadConnectStatusChange = function(e, isConnected) {
console.log('onGamepadConnetcStatusChange', e, isConnected);
if (e.gamepad.index !== 0) {
return;
}
if (isConnected) {
console.log('%cgamepad connected id:"%s"', 'background: lightblue;', e.gamepad.id);
detectGamepad();
} else {
ZenzaGamePad.emit('onDeviceDisconnect', primaryGamepad.getDeviceIndex());
if (primaryGamepad) {
primaryGamepad.release();
}
primaryGamepad = null;
console.log('%cgamepad disconneced id:"%s"', 'background: lightblue;', e.gamepad.id);
}
};
var initializeTimer = function() {
console.log('%cinitializeGamepadTimer', 'background: lightgreen;');
var onTimerInterval = function() {
if (!primaryGamepad) {
detectGamepad();
return;
}
if (!primaryGamepad.isConnected) {
return;
}
primaryGamepad.update();
};
pollingTimer = new PollingTimer(onTimerInterval, 1000);
};
var initializeGamepadConnectEvent = function() {
console.log('%cinitializeGamepadConnectEvent', 'background: lightgreen;');
window.addEventListener('gamepadconnected',
function(e) { onGamepadConnectStatusChange(e, true); }, false);
window.addEventListener('gamepaddisconnected',
function(e) { onGamepadConnectStatusChange(e, false); }, false);
if (primaryGamepad) {
return;
}
window.setTimeout(detectGamepad, 1000);
};
ZenzaGamePad.startDetect = function() {
ZenzaGamePad.startDetect = _.noop;
initializeTimer();
initializeGamepadConnectEvent();
};
ZenzaGamePad.startPolling = function() {
if (pollingTimer) { pollingTimer.start(); }
};
ZenzaGamePad.stopPolling = function() {
if (pollingTimer) { pollingTimer.pause(); }
};
return ZenzaGamePad;
})($, PollingTimer, GamePadModel);
var initGamePad = function() {
initGamePad = _.noop;
var isActivated = false;
var deviceId, deviceIndex;
var notifyDetect = function() {
if (!document.hasFocus()) { return; }
isActivated = true;
notifyDetect = _.noop;
// 初めてボタンかキーが押されたタイミングで通知する
execCommand(
'notify',
'ゲームパッド "' + deviceId + '" が検出されました'
);
};
var _onButtonDown = function(number /*, deviceIndex*/) {
notifyDetect();
if (!isActivated) { return; }
onButtonDown(number, deviceId);
//console.log('%conButtonDown: number=%s, device=%s', 'background: lightblue;', number, deviceIndex);
};
var _onButtonRepeat = function(number /*, deviceIndex*/) {
if (!isActivated) { return; }
onButtonRepeat(number, deviceId);
//console.log('%conButtonRepeat: number=%s, device=%s', 'background: lightblue;', number, deviceIndex);
};
var _onButtonUp = function(number /*, deviceIndex*/) {
//console.log('%conButtonUp: number=%s, device=%s', 'background: lightblue;', number, deviceIndex);
if (!isActivated) { return; }
onButtonUp(number, deviceId);
};
var _onAxisChange = function(number, value /*, deviceIndex */) {
notifyDetect();
if (!isActivated) { return; }
onAxisChange(number, value, deviceId);
//console.log('%conAxisChange: number=%s, value=%s, device=%s', 'background: lightblue;', number, value, deviceIndex);
};
var _onAxisRepeat = function(number, value /*, deviceIndex */) {
//console.log('%conAxisChange: number=%s, value=%s, device=%s', 'background: lightblue;', number, value, deviceIndex);
if (!isActivated) { return; }
onAxisRepeat(number, value, deviceId);
};
var _onAxisRelease = function(/* number, deviceIndex */) {
if (!isActivated) { return; }
};
var _onPovChange = function(pov /*, deviceIndex */) {
notifyDetect();
if (!isActivated) { return; }
onPovChange(pov, deviceId);
};
var _onPovRepeat = function(pov /*, deviceIndex */) {
if (!isActivated) { return; }
onPovRepeat(pov, deviceId);
};
var bindEvents = function() {
bindEvents = _.noop;
ZenzaGamePad.on('onButtonDown', _onButtonDown);
ZenzaGamePad.on('onButtonRepeat', _onButtonRepeat);
ZenzaGamePad.on('onButtonUp', _onButtonUp);
ZenzaGamePad.on('onAxisChange', _onAxisChange);
ZenzaGamePad.on('onAxisRepeat', _onAxisRepeat);
ZenzaGamePad.on('onAxisRelease', _onAxisRelease);
ZenzaGamePad.on('onPovChange', _onPovChange);
ZenzaGamePad.on('onPovRepeat', _onPovRepeat);
};
var onDeviceConnect = function(index, id) {
deviceIndex = index;
deviceId = id;
bindEvents();
};
ZenzaGamePad.on('onDeviceConnect', onDeviceConnect);
//ZenzaGamePad.on('onDeviceDisConnect', onDeviceDisConnect);
ZenzaGamePad.startDetect();
};
var onZenzaWatchOpen = function() {
isZenzaWatchOpen = true;
initGamePad();
ZenzaGamePad.startPolling();
};
var onZenzaWatchClose = function() {
isZenzaWatchOpen = false;
ZenzaGamePad.stopPolling();
};
var initialize = function() {
ZenzaWatch.emitter.on('DialogPlayerOpen', onZenzaWatchOpen);
ZenzaWatch.emitter.on('DialogPlayerClose', onZenzaWatchClose);
};
initialize();
};
var loadMonkey = function() {
var script = document.createElement('script');
script.id = 'ZenzaGamePadLoader';
script.setAttribute('type', 'text/javascript');
script.setAttribute('charset', 'UTF-8');
script.appendChild(document.createTextNode('(' + monkey + ')(window.ZenzaWatch);'));
document.body.appendChild(script);
};
var waitForZenzaWatch = function() {
if (window.ZenzaWatch && window.ZenzaWatch.ready) {
window.console.log('ZenzaWatch is Ready');
loadMonkey();
} else {
window.jQuery('body').on('ZenzaWatchReady', function() {
window.console.log('onZenzaWatchReady');
loadMonkey();
});
}
};
waitForZenzaWatch();
})();