Pr0gramm Joystick Controls

Enables joystick controls for pr0gramm.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name       Pr0gramm Joystick Controls
// @namespace  http://skipcast.net
// @version    0.21
// @description  Enables joystick controls for pr0gramm.
// @match      *pr0gramm.com/*
// @copyright  2014+, Jonathan Lindahl
// ==/UserScript==

/*
 * Controls:
 * DPad Left = Previous Image.
 * DPad Right = Next Image.
 * DPad Up/Down = Scroll up/down the page.
 * L1 + R1 = Reload page to latest entries.
 * Y = Toggle mode.
 * 
 * Scroll mode:
 * Left stick = Scroll up/down the page with better accuracy.
 * Right stick = Scroll up/down the page faster combined with left stick.
 * 
 * Mouse mode:
 * Left stick = Scroll up/down the page.
 * Right stick: Move mouse.
 * X: Click.
 * B: Back.
 * */

// Use this to get button indices: http://www.html5rocks.com/en/tutorials/doodles/gamepad/gamepad-tester/tester.html
var BTN_X = 0;
var BTN_B = 1;
var BTN_Y = 3;
var BTN_TAB_LEFT = 4;
var BTN_TAB_RIGHT = 5;
var BTN_UP = 12;
var BTN_DOWN = 13;
var BTN_LEFT = 14;
var BTN_RIGHT = 15;
var SCROLL_SPEED = 15;
var MOUSE_SPEED = 20;

var oldLeft = false;
var oldRight = false;
var oldX = false;
var oldY = false;
var oldB = false;

var State = {
    scroll: 0,
    mouse: 1
};

var currentState = State.scroll;
var cursorNode = null;
var overlayNode = null;
var mousePosition = [0.5, 0.5];
var mouseHotzone = [0, 0];

function scrollUp(multiplier)
{
    var top = $("body").scrollTop();
    $("body").scrollTop(top - (SCROLL_SPEED * multiplier));
}

function scrollDown(multiplier)
{
    var top = $("body").scrollTop();
    $("body").scrollTop(top + (SCROLL_SPEED * multiplier));
}

function scrollLeft()
{
    var streamPrevNode = $("#stream-prev");
    
    if (window.location.pathname != "/")
        streamPrevNode.click();
}

function scrollRight()
{
    var streamNextNode = $("#stream-next");
    
    if (window.location.pathname != "/")
    {
        try
        {
            streamNextNode.click();
        }
        catch (error) {}
    }
    else
    {
        $(".stream-row a img").first().click();
    }
}

function pollJoystickInput()
{
    var gamepads = navigator.getGamepads();
    
    for(var i = 0; i < gamepads.length; ++i)
    {
        var gamepad = gamepads.item(i);
        
        if (gamepad != null)
        {
            var buttons = gamepad.buttons;
            var axes = gamepad.axes;
            var upKey = buttons[BTN_UP];
            var downKey = buttons[BTN_DOWN];
            var leftKey = buttons[BTN_LEFT];
            var rightKey = buttons[BTN_RIGHT];
            var tabLeft = buttons[BTN_TAB_LEFT];
            var tabRight = buttons[BTN_TAB_RIGHT];
            var yKey = buttons[BTN_Y];
            var xKey = buttons[BTN_X];
            var bKey = buttons[BTN_B];
            
            if (leftKey.pressed && !oldLeft)
            {
                scrollLeft();
            }
            else if (rightKey.pressed && !oldRight)
            {
                scrollRight();
            }
            
            if (upKey.pressed)
            {
                scrollUp(1);
            }
            if (downKey.pressed)
            {
                scrollDown(1);
            }
            
            if (Math.abs(axes[0]) > 0.01 || Math.abs(axes[1]) > 0.01 || Math.abs(axes[2]) > 0.01 || Math.abs(axes[3]) > 0.01)
            {
                var multiplier = axes[3];
                
                if (currentState == State.scroll)
                    multiplier += axes[1];
                
                if (Math.abs(multiplier) > 1)
                    multiplier *= (Math.abs(multiplier) - 1) + 1;
                
                if (currentState == State.mouse)
                {
                    moveMouse(axes[0] * MOUSE_SPEED, axes[1] * MOUSE_SPEED);
                }
                
                scrollDown(multiplier);
            }
            
            if (tabLeft.pressed && tabRight.pressed)
            {
                window.location.href = "/";
            }
            
            if (yKey.pressed && !oldY)
            {
                toggleState();
            }
            
            if (bKey.pressed && !oldB)
            {
                if (window.location.pathname != "/")
                	window.history.back();
                else
                    window.location.reload();
            }
            
            if (currentState == State.mouse && xKey.pressed && !oldX)
            {
                var mousePos = getFixedMousePos();
                
                cursorNode.hide(); // Prevent elementFromPoint from getting cursor element.
                var elmAtMouse = document.elementFromPoint(mousePos[0] + mouseHotzone[0], mousePos[1] + mouseHotzone[1]);
                cursorNode.show();
                $(elmAtMouse).click();
            }
            
            oldLeft = leftKey.pressed;
            oldRight = rightKey.pressed;
            oldY = yKey.pressed;
            oldX = xKey.pressed;
            oldB = bKey.pressed;
        }
    }
    
    requestAnimationFrame(pollJoystickInput);
}

requestAnimationFrame(pollJoystickInput);

var overlayTimeout = null;
function alertOverlay(message)
{
    if (overlayTimeout != null)
        clearTimeout(overlayTimeout);
    
    $("#joystickOverlay").html(message);
    $("#joystickOverlay").stop().fadeIn(50, function()
                                 {
                                     overlayTimeout = setTimeout(function()
                                                {
                                                    $("#joystickOverlay").fadeOut(200);
                                                }, 1250);
                                 });
}

function toggleState(doAlert)
{
    doAlert = doAlert != null ? doAlert : true;
    
    if (currentState == State.scroll)
    {
        $("#cursor").show();
        
        currentState = State.mouse;
        
        if (doAlert)
        	alertOverlay("Changed mode to mouse.");
    }
    else
    {
        $("#cursor").hide();
        
        currentState = State.scroll;
        
        if (doAlert)
        	alertOverlay("Changed mode to scroll.");
    }
    
    saveState();
}

function saveState()
{
    localStorage.setItem("joystick_LastState", currentState);
}

function loadState()
{
    var lastState = parseInt(localStorage.joystick_LastState);
    var lastMousePosX = parseFloat(sessionStorage.getItem("joystick_LastMousePosX"));
    var lastMousePosY = parseFloat(sessionStorage.getItem("joystick_LastMousePosY"));
    mousePosition[0] = isNaN(lastMousePosX) ? 0.5 : lastMousePosX;
    mousePosition[1] = isNaN(lastMousePosY) ? 0.5 : lastMousePosY;
    setMousePos();
    
    if (isNaN(lastState))
    {
        localStorage.setItem("joystick_LastState", State.scroll);
    }
    else
    {
        if (lastState == State.mouse) // Is scroll by default.
            toggleState(false);
    }
}

function moveMouse(x, y)
{
   	var addX = x / window.innerWidth;
    var addY = y / window.innerHeight;
    mousePosition = [mousePosition[0] + addX, mousePosition[1] + addY];
    if (mousePosition[0] < 0)
        mousePosition[0] = 0;
    else if (mousePosition[0] > 1)
        mousePosition[0] = 1;
        
    if (mousePosition[1] < 0)
        mousePosition[1] = 0;
    else if (mousePosition[1] > 1)
        mousePosition[1] = 1;
    
    sessionStorage.setItem("joystick_LastMousePosX", mousePosition[0]);
    sessionStorage.setItem("joystick_LastMousePosY", mousePosition[1]);
    setMousePos();
}

function setMousePos()
{
    $("#cursor").css(
    {
        left: (window.innerWidth * mousePosition[0]) - mouseHotzone[0],
        top: (window.innerHeight * mousePosition[1]) - mouseHotzone[1]
    });
}

function getFixedMousePos()
{
    var cursorNode = $("#cursor");
    var pos = cursorNode.position();
    
    return [pos.left, pos.top];
}

$(function()
{
    cursorNode = $(document.createElement("div"));
    cursorNode.attr("id", "cursor");
    cursorNode.css(
        {
            backgroundImage: "url(http://i.imgur.com/asuC1of.png)", // Better way to get image? base64 strings doesn't work for some reason.
            position: "fixed",
            top: "50%",
            left: "50%",
            width: 16,
            height: 24,
            "z-index": 1000001,
            display: "none"
        });
    
    $("body").append(cursorNode);
    
    overlayNode = $(document.createElement("div"));
    overlayNode.attr("id", "joystickOverlay");
    overlayNode.css(
        {
            backgroundColor: "rgba(0, 0, 0, 0.75)",
            position: "fixed",
            left: 0,
            right: 0,
            top: 200,
            height: 100,
            "line-height": "100px",
            color: "#FFF",
            "text-align": "center",
            "font-size": 30,
            "z-index": 1000000,
            display: "none"
        });
    
    $("body").append(overlayNode);
    
    $(window).resize(function()
    {
        setMousePos();
    });
    
    loadState();
});