KMLibrary

KMLibrary for interacting with Mac KM

Этот скрипт недоступен для установки пользователем. Он является библиотекой, которая подключается к другим скриптам мета-ключом // @require https://update.greasyfork.org/scripts/571968/1787733/KMLibrary.js

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         KMLibrary
// @namespace    https://greasyfork.org/users/28298
// @version      0.6
// @description  KMLibrary for interacting with Mac KM
// @author       Jerry
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @license      GNU GPLv3
// @noframes
// @require      https://greasyfork.org/scripts/456410-gmlibrary/code/GMLibrary.js
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @connect      localhost
// @run-at       document-start
// ==/UserScript==

// KM -> Hotkey (Mousetrap.bindGlobal) -> UserScript -> KM (requestKM webserver)
// ── Shared KM helpers ─────────────────────────────────────────────────────
function isInEditbox() {
    const activeEl = unsafeWindow.document.activeElement;
    if (!activeEl) return false;
    const tagName = activeEl.tagName.toLowerCase();
    if (tagName === 'textarea') return true;
    if (tagName === 'input') {
        const type = (activeEl.type || '').toLowerCase();
        return ['text', 'search', 'email', 'url', 'tel', 'password', 'number'].includes(type);
    }
    if (activeEl.isContentEditable) return true;
    const contentEditable = activeEl.getAttribute('contenteditable');
    return contentEditable === 'true' || contentEditable === '';
}

function getPageContext() {
    const sel = unsafeWindow.getSelection();
    return {
        url: unsafeWindow.location.href,
        title: unsafeWindow.document.title,
        isInEditbox: isInEditbox(),
        selectedText: sel ? sel.toString() : ''
    };
}

function requestKM(macroId) {
    GM_xmlhttpRequest({
        method: 'GET',
        url: 'https://localhost:3011/action.html?macro=' + macroId +
             '&value=' + encodeURIComponent(JSON.stringify(getPageContext())),
        timeout: 2000,
        onerror: function() {},
        ontimeout: function() {}
    });
}

/**
* triggerKM(trigger, macroID, mode)
*
* @param {string|string[]} trigger  - hotkey (e.g. 'mod+d') or hotstring (e.g. 'hello')
* @param {string}          macroID  - KM macro UUID
* @param {number}          mode     - 1 = outside editbox only
*                                     2 = inside editbox only
*                                     3 = anywhere
*/
function triggerKM(trigger, macroID, mode=3) {
    Mousetrap.bindGlobal(trigger, function () {
        const inBox = isInEditbox();

        if (mode === 1 && inBox)  return true;  // pass through — let editbox handle it
        if (mode === 2 && !inBox) return false; // swallow — not in an editbox

        requestKM(macroID);
        return false; // prevent default / stop propagation
    });
}

function isAppleSilicon() {
    try {
        const canvas = document.createElement('canvas');
        const gl =
            canvas.getContext('webgl') ||
            canvas.getContext('experimental-webgl');
        if (!gl) return false;

        const renderer = gl.getParameter(gl.RENDERER) || '';
        const r = renderer.toLowerCase();

        // "Apple M1, or similar"
        if (r.includes('apple m1')) {
            return true;
        }

        // Fallback: not confidently Apple Silicon
        return false;
    } catch (e) {
        return false;
    }
}