moebius-web

web based ansi art editor

moebius-web

public/scripts/keyboard.js


function createFKeyShorcut(canvas, charCode) {
    "use strict";
    function update() {
        canvas.style.width = font.getWidth() + "px";
        canvas.style.height = font.getHeight() + "px";
        font.draw(charCode, palette.getForegroundColour(), palette.getBackgroundColour(), canvas.getContext("2d"), 0, 0);
    }
    document.addEventListener("onForegroundChange", update);
    document.addEventListener("onBackgroundChange", update);
    document.addEventListener("onFontChange", update);

    update();
}

function createFKeysShortcut() {
    "use strict";
    var shortcuts = [176, 177, 178, 219, 223, 220, 221, 222, 254, 249, 7, 0];
    
    for (var i = 0; i < 12; i++) {
        createFKeyShorcut($("fkey" + i), shortcuts[i]);
    }

    function keyDown(evt) {
        var keyCode = (evt.keyCode || evt.which);
        if (evt.altKey === false && evt.ctrlKey === false && evt.metaKey === false && keyCode >= 112 && keyCode <= 124) {
            evt.preventDefault();
            textArtCanvas.startUndo();
            textArtCanvas.draw((callback) => {
                callback(shortcuts[keyCode - 112], palette.getForegroundColour(), palette.getBackgroundColour(), cursor.getX(), cursor.getY());
            }, false);
            cursor.right();
        }
    }

    function enable() {
        document.addEventListener("keydown", keyDown);
            
    }

    function disable() {
        document.removeEventListener("keydown", keyDown);
    }

    return {
        "enable": enable,
        "disable": disable
    };
}

function createCursor(canvasContainer) {
    "use strict";
    var canvas = createCanvas(font.getWidth(), font.getHeight());
    var x = 0;
    var y = 0;
    var dx = 0;
    var dy = 0;
    var visible = false;

    function show() {
        canvas.style.display = "block";
        visible = true;
    }

    function hide() {
        canvas.style.display = "none";
        visible = false;
    }

    function startSelection() {
        selectionCursor.setStart(x, y);
        dx = x;
        dy = y;
        hide();
    }

    function endSelection() {
        selectionCursor.hide();
        show();
    }

    function move(newX, newY) {
        if (selectionCursor.isVisible() === true) {
            endSelection();
        }
        x = Math.min(Math.max(newX, 0), textArtCanvas.getColumns() - 1);
        y = Math.min(Math.max(newY, 0), textArtCanvas.getRows() - 1);
        var canvasWidth = font.getWidth();
        canvas.style.left = (x * canvasWidth) - 1 + "px";
        canvas.style.top = (y * font.getHeight()) - 1 + "px";
        positionInfo.update(x, y);
        pasteTool.setSelection(x, y, 1, 1);
    }

    function updateDimensions() {
        canvas.width = font.getWidth() + 1;
        canvas.height = font.getHeight() + 1;
        move(x, y);
    }

    function getX() {
        return x;
    }

    function getY() {
        return y;
    }

    function left() {
        move(x - 1 , y);
    }

    function right() {
        move(x + 1 , y);
    }

    function up() {
        move(x, y - 1);
    }

    function down() {
        move(x, y + 1);
    }

    function newLine() {
        move(0, y + 1);
    }

    function startOfCurrentRow() {
        move(0, y);
    }

    function endOfCurrentRow() {
        move(textArtCanvas.getColumns() - 1, y);
    }

    function shiftLeft() {
        if (selectionCursor.isVisible() === false) {
            startSelection();
        }
        dx = Math.max(dx - 1, 0);
        selectionCursor.setEnd(dx, dy);
    }

    function shiftRight() {
        if (selectionCursor.isVisible() === false) {
            startSelection();
        }
        dx = Math.min(dx + 1, textArtCanvas.getColumns() - 1);
        selectionCursor.setEnd(dx, dy);
    }

    function shiftUp() {
        if (selectionCursor.isVisible() === false) {
            startSelection();
        }
        dy = Math.max(dy - 1, 0);
        selectionCursor.setEnd(dx, dy);
    }

    function shiftDown() {
        if (selectionCursor.isVisible() === false) {
            startSelection();
        }
        dy = Math.min(dy + 1, textArtCanvas.getRows() - 1);
        selectionCursor.setEnd(dx, dy);
    }

    function keyDown(evt) {
        var keyCode = (evt.keyCode || evt.which);
        if (evt.ctrlKey === false && evt.altKey === false) {
            if (evt.shiftKey === false && evt.metaKey === false) {
                switch(keyCode) {
                case 13:
                    evt.preventDefault();
                    newLine();
                    break;
                case 35:
                    evt.preventDefault();
                    endOfCurrentRow();
                    break;
                case 36:
                    evt.preventDefault();
                    startOfCurrentRow();
                    break;
                case 37:
                    evt.preventDefault();
                    left();
                    break;
                case 38:
                    evt.preventDefault();
                    up();
                    break;
                case 39:
                    evt.preventDefault();
                    right();
                    break;
                case 40:
                    evt.preventDefault();
                    down();
                    break;
                default:
                    break;
                }
            } else if (evt.metaKey === true && evt.shiftKey === false) {
                switch(keyCode) {
                case 37:
                    evt.preventDefault();
                    startOfCurrentRow();
                    break;
                case 39:
                    evt.preventDefault();
                    endOfCurrentRow();
                    break;
                default:
                    break;
                }
            } else if (evt.shiftKey === true && evt.metaKey === false) {
                switch(keyCode) {
                case 37:
                    evt.preventDefault();
                    shiftLeft();
                    break;
                case 38:
                    evt.preventDefault();
                    shiftUp();
                    break;
                case 39:
                    evt.preventDefault();
                    shiftRight();
                    break;
                case 40:
                    evt.preventDefault();
                    shiftDown();
                    break;
                default:
                    break;
                }
            }
        }
    }

    function enable() {
        document.addEventListener("keydown", keyDown);
        show();
        pasteTool.setSelection(x, y, 1, 1);
    }

    function disable() {
        document.removeEventListener("keydown", keyDown);
        hide();
        pasteTool.disable();
    }

    function isVisible() {
        return visible;
    }

    canvas.classList.add("cursor");
    hide();
    canvasContainer.insertBefore(canvas, canvasContainer.firstChild);
    document.addEventListener("onLetterSpacingChange", updateDimensions);
    document.addEventListener("onTextCanvasSizeChange", updateDimensions);
    document.addEventListener("onFontChange", updateDimensions);
    document.addEventListener("onOpenedFile", updateDimensions);
    move(x, y);

    return {
        "show": show,
        "hide": hide,
        "move": move,
        "getX": getX,
        "getY": getY,
        "left": left,
        "right": right,
        "up": up,
        "down": down,
        "newLine": newLine,
        "startOfCurrentRow": startOfCurrentRow,
        "endOfCurrentRow": endOfCurrentRow,
        "shiftLeft": shiftLeft,
        "shiftRight": shiftRight,
        "enable": enable,
        "disable": disable,
        "isVisible": isVisible
    };
}

function createSelectionCursor(divElement) {
    "use strict";
    var cursor = createCanvas(0, 0);
    var sx, sy, dx, dy, x, y, width, height;
    var visible = false;

    function processCoords() {
        x = Math.min(sx, dx);
        y = Math.min(sy, dy);
        x = Math.max(x, 0);
        y = Math.max(y, 0);
        var columns = textArtCanvas.getColumns();
        var rows = textArtCanvas.getRows();
        width = Math.abs(dx - sx) + 1;
        height = Math.abs(dy - sy) + 1;
        width = Math.min(width, columns - x);
        height = Math.min(height, rows - y);
    }

    function show() {
        cursor.style.display = "block";
    }

    function hide() {
        cursor.style.display = "none";
        visible = false;
        pasteTool.disable();
    }

    function updateCursor() {
        var fontWidth = font.getWidth();
        var fontHeight = font.getHeight();
        cursor.style.left = x * fontWidth - 1 + "px";
        cursor.style.top = y * fontHeight - 1 + "px";
        cursor.width = width * fontWidth + 1;
        cursor.height = height * fontHeight + 1;
    }

    function setStart(startX, startY) {
        sx = startX;
        sy = startY;
        processCoords();
        x = startX;
        y = startY;
        width = 1;
        height = 1;
        updateCursor();
    }

    function setEnd(endX, endY) {
        show();
        dx = endX;
        dy = endY;
        processCoords();
        updateCursor();
        pasteTool.setSelection(x, y, width, height);
        visible = true;
    }

    function isVisible() {
        return visible;
    }

    cursor.classList.add("selection-cursor");
    cursor.style.display = "none";
    divElement.appendChild(cursor);

    return {
        "show": show,
        "hide": hide,
        "setStart": setStart,
        "setEnd": setEnd,
        "isVisible": isVisible
    };
}

function createKeyboardController() {
    "use strict";
    var fkeys = createFKeysShortcut();
    var enabled = false;
    var ignored = false;

    function draw(charCode) {
        textArtCanvas.startUndo();
        textArtCanvas.draw((callback) => {
            callback(charCode, palette.getForegroundColour(), palette.getBackgroundColour(), cursor.getX(), cursor.getY());
        }, false);
        cursor.right();
    }

    function deleteText() {
        textArtCanvas.startUndo();
        textArtCanvas.draw((callback) => {
            callback(0, 7, 0, cursor.getX() - 1, cursor.getY());
        }, false);
        cursor.left();
    }

    function keyDown(evt) {
        var keyCode = (evt.keyCode || evt.which);
        if (ignored === false) {
            if (evt.altKey === false && evt.ctrlKey === false && evt.metaKey === false) {
                if (keyCode === 9) {
                    evt.preventDefault();
                    draw(keyCode);
                } else if (keyCode === 8) {
                    evt.preventDefault();
                    if (cursor.getX() > 0) {
                        deleteText();
                    }
                }
            }
        }
    }

    function convertUnicode(keyCode) {
        switch (keyCode) {
        case 0x2302: return 127;
        case 0x00C7: return 128;
        case 0x00FC: return 129;
        case 0x00E9: return 130;
        case 0x00E2: return 131;
        case 0x00E4: return 132;
        case 0x00E0: return 133;
        case 0x00E5: return 134;
        case 0x00E7: return 135;
        case 0x00EA: return 136;
        case 0x00EB: return 137;
        case 0x00E8: return 138;
        case 0x00EF: return 139;
        case 0x00EE: return 140;
        case 0x00EC: return 141;
        case 0x00C4: return 142;
        case 0x00C5: return 143;
        case 0x00C9: return 144;
        case 0x00E6: return 145;
        case 0x00C6: return 146;
        case 0x00F4: return 147;
        case 0x00F6: return 148;
        case 0x00F2: return 149;
        case 0x00FB: return 150;
        case 0x00F9: return 151;
        case 0x00FF: return 152;
        case 0x00D6: return 153;
        case 0x00DC: return 154;
        case 0x00A2: return 155;
        case 0x00A3: return 156;
        case 0x00A5: return 157;
        case 0x20A7: return 158;
        case 0x0192: return 159;
        case 0x00E1: return 160;
        case 0x00ED: return 161;
        case 0x00F3: return 162;
        case 0x00FA: return 163;
        case 0x00F1: return 164;
        case 0x00D1: return 165;
        case 0x00AA: return 166;
        case 0x00BA: return 167;
        case 0x00BF: return 168;
        case 0x2310: return 169;
        case 0x00AC: return 170;
        case 0x00BD: return 171;
        case 0x00BC: return 172;
        case 0x00A1: return 173;
        case 0x00AB: return 174;
        case 0x00BB: return 175;
        case 0x2591: return 176;
        case 0x2592: return 177;
        case 0x2593: return 178;
        case 0x2502: return 179;
        case 0x2524: return 180;
        case 0x2561: return 181;
        case 0x2562: return 182;
        case 0x2556: return 183;
        case 0x2555: return 184;
        case 0x2563: return 185;
        case 0x2551: return 186;
        case 0x2557: return 187;
        case 0x255D: return 188;
        case 0x255C: return 189;
        case 0x255B: return 190;
        case 0x2510: return 191;
        case 0x2514: return 192;
        case 0x2534: return 193;
        case 0x252C: return 194;
        case 0x251C: return 195;
        case 0x2500: return 196;
        case 0x253C: return 197;
        case 0x255E: return 198;
        case 0x255F: return 199;
        case 0x255A: return 200;
        case 0x2554: return 201;
        case 0x2569: return 202;
        case 0x2566: return 203;
        case 0x2560: return 204;
        case 0x2550: return 205;
        case 0x256C: return 206;
        case 0x2567: return 207;
        case 0x2568: return 208;
        case 0x2564: return 209;
        case 0x2565: return 210;
        case 0x2559: return 211;
        case 0x2558: return 212;
        case 0x2552: return 213;
        case 0x2553: return 214;
        case 0x256B: return 215;
        case 0x256A: return 216;
        case 0x2518: return 217;
        case 0x250C: return 218;
        case 0x2588: return 219;
        case 0x2584: return 220;
        case 0x258C: return 221;
        case 0x2590: return 222;
        case 0x2580: return 223;
        case 0x03B1: return 224;
        case 0x00DF: return 225;
        case 0x0393: return 226;
        case 0x03C0: return 227;
        case 0x03A3: return 228;
        case 0x03C3: return 229;
        case 0x00B5: return 230;
        case 0x03C4: return 231;
        case 0x03A6: return 232;
        case 0x0398: return 233;
        case 0x03A9: return 234;
        case 0x03B4: return 235;
        case 0x221E: return 236;
        case 0x03C6: return 237;
        case 0x03B5: return 238;
        case 0x2229: return 239;
        case 0x2261: return 240;
        case 0x00B1: return 241;
        case 0x2265: return 242;
        case 0x2264: return 243;
        case 0x2320: return 244;
        case 0x2321: return 245;
        case 0x00F7: return 246;
        case 0x2248: return 247;
        case 0x00B0: return 248;
        case 0x2219: return 249;
        case 0x00B7: return 250;
        case 0x221A: return 251;
        case 0x207F: return 252;
        case 0x00B2: return 253;
        case 0x25A0: return 254;
        case 0x00A0: return 255;
        default: return keyCode;
        }
    }

    function keyPress(evt) {
        var keyCode = (evt.keyCode || evt.which);
        if (ignored === false) {
            if (evt.altKey === false && evt.ctrlKey === false && evt.metaKey === false) {
                if (keyCode >= 32) {
                    evt.preventDefault();
                    draw(convertUnicode(keyCode));
                } else if (keyCode === 13) {
                    evt.preventDefault();
                    cursor.newLine();
                } else if (keyCode === 8) {
                    evt.preventDefault();
                    if (cursor.getX() > 0) {
                        deleteText();
                    }
                } else if (keyCode === 167) {
                    evt.preventDefault();
                    draw(21);
                }
            } else if (evt.ctrlKey === true) {
                if (keyCode === 21) {
                    evt.preventDefault();
                    var block = textArtCanvas.getBlock(cursor.getX(), cursor.getY());
                    palette.setForegroundColour(block.foregroundColour);
                    palette.setBackgroundColour(block.backgroundColour);
                }
            }
        }
    }

    function textCanvasDown(evt) {
        cursor.move(evt.detail.x, evt.detail.y);
        selectionCursor.setStart(evt.detail.x, evt.detail.y);
    }

    function textCanvasDrag(evt) {
        cursor.hide();
        selectionCursor.setEnd(evt.detail.x, evt.detail.y);
    }

    function enable() {
        document.addEventListener("keydown", keyDown);
        document.addEventListener("keypress", keyPress);
        document.addEventListener("onTextCanvasDown", textCanvasDown);
        document.addEventListener("onTextCanvasDrag", textCanvasDrag);
        cursor.enable();
        fkeys.enable();
        positionInfo.update(cursor.getX(), cursor.getY());
        enabled = true;
    }

    function disable() {
        document.removeEventListener("keydown", keyDown);
        document.removeEventListener("keypress", keyPress);
        document.removeEventListener("onTextCanvasDown", textCanvasDown);
        document.removeEventListener("onTextCanvasDrag", textCanvasDrag);
        selectionCursor.hide();
        cursor.disable();
        fkeys.disable();
        enabled = false;
    }

    function ignore() {
        ignored = true;
        if (enabled === true) {
            cursor.disable();
            fkeys.disable();
        }
    }

    function unignore() {
        ignored = false;
        if (enabled === true) {
            cursor.enable();
            fkeys.enable();
        }
    }

    return {
        "enable": enable,
        "disable": disable,
        "ignore": ignore,
        "unignore": unignore
    };
}

function createPasteTool(cutItem, copyItem, pasteItem, deleteItem) {
    "use strict";
    var buffer;
    var x = 0;
    var y = 0;
    var width = 0;
    var height = 0;
    var enabled = false;

    function setSelection(newX, newY, newWidth, newHeight) {
        x = newX;
        y = newY;
        width = newWidth;
        height = newHeight;
        if (buffer !== undefined) {
            pasteItem.classList.remove("disabled");
        }
        cutItem.classList.remove("disabled");
        copyItem.classList.remove("disabled");
        deleteItem.classList.remove("disabled");
        enabled = true;
    }

    function disable() {
        pasteItem.classList.add("disabled");
        cutItem.classList.add("disabled");
        copyItem.classList.add("disabled");
        deleteItem.classList.add("disabled");
        enabled = false;
    }

    function copy() {
        buffer = textArtCanvas.getArea(x, y, width, height);
        pasteItem.classList.remove("disabled");
    }

    function deleteSelection() {
        if (selectionCursor.isVisible() || cursor.isVisible()) {
            textArtCanvas.startUndo();
            textArtCanvas.deleteArea(x, y, width, height, palette.getBackgroundColour());
        }
    }

    function cut() {
        if (selectionCursor.isVisible() || cursor.isVisible()) {
            copy();
            deleteSelection();
        }
    }

    function paste() {
        if (buffer !== undefined && (selectionCursor.isVisible() || cursor.isVisible())) {
            textArtCanvas.startUndo();
            textArtCanvas.setArea(buffer, x, y);
        }
    }

    function keyDown(evt) {
        var keyCode = (evt.keyCode || evt.which);
        if (enabled) {
            if ((evt.ctrlKey === true || evt.metaKey === true) && evt.altKey === false && evt.shiftKey === false) {
                switch(keyCode) {
                case 88:
                    evt.preventDefault();
                    cut();
                    break;
                case 67:
                    evt.preventDefault();
                    copy();
                    break;
                case 86:
                    evt.preventDefault();
                    paste();
                    break;
                default:
                    break;
                }
            }
        }
        if ((evt.ctrlKey === true || evt.metaKey === true) && keyCode === 8) {
            evt.preventDefault();
            deleteSelection();
        }
    }


    document.addEventListener("keydown", keyDown);

    return {
        "setSelection": setSelection,
        "cut": cut,
        "copy": copy,
        "paste": paste,
        "deleteSelection": deleteSelection,
        "disable": disable
    };
}

Download

raw zip tar