KMLibrary

KMLibrary for interacting with Mac KM

Ezt a szkriptet nem ajánlott közvetlenül telepíteni. Ez egy könyvtár más szkriptek számára, amik tartalmazzák a // @require https://update.greasyfork.org/scripts/571968/1788810/KMLibrary.js hivatkozást.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         KMLibrary
// @namespace    https://greasyfork.org/users/28298
// @version      1.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
// @grant        GM_setClipboard
// @connect      localhost
// @run-at       document-start
// ==/UserScript==

// KM -> Hotkey (Mousetrap.bindGlobal) -> UserScript -> KM (requestKM webserver)
// ── Shared KM helpers ─────────────────────────────────────────────────────
// Possible return values: "windows", "macos-arm", "macos-intel", "ios", "android", "linux", "unknown"
function getOS() {
    const platform = navigator.platform?.toLowerCase() ?? '';
    const ua = navigator.userAgent?.toLowerCase() ?? '';

    if (platform.startsWith('win')) return 'windows';
    if (platform.startsWith('iphone') || platform.startsWith('ipad') || ua.includes('iphone') || ua.includes('ipad')) return 'ios';
    if (platform.startsWith('mac')) {
        // navigator.platform is 'MacIntel' for both Intel and Apple Silicon —
        // WebGL renderer is the most reliable client-side signal
        try {
            const canvas = document.createElement('canvas');
            const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
            if (gl) {
                const renderer = (gl.getParameter(gl.RENDERER) ?? '').toLowerCase();
                if (renderer.includes('apple m')) return 'macos-arm';
            }
        } catch (_) {}
        return 'macos-intel';
    }
    if (platform.startsWith('linux') || ua.includes('linux')) {
        return ua.includes('android') ? 'android' : 'linux';
    }

    return 'unknown';
}
const OS = getOS();
const isWindows   = OS === 'windows';
const isMacARM    = OS === 'macos-arm';
const isMacIntel  = OS === 'macos-intel';
const isMac       = OS === 'macos-arm' || OS === 'macos-intel';
const isIOS       = OS === 'ios';
const isAndroid   = OS === 'android';
const isLinux     = OS === 'linux';

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() : '',
        os: OS
    };
}

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

function requestKM(macroId, extraText = '') {
    GM_xmlhttpRequest({
        method: 'GET',
        url: (isWindows ? 'http://localhost:3010' : 'https://localhost:3011') +
             '/action.html?macro=' + macroId +
             '&value=' + encodeURIComponent(JSON.stringify({ ...getPageContext(), extraText })),
        timeout: 60000,
        onload: isWindows ? function(res) {
            const text = res.responseText;
            if (!text) return;
            const lines = text.split('\n');
            lines.forEach((line, i) => {
                document.execCommand('insertText', false, line);
                if (i < lines.length - 1) document.execCommand('insertParagraph', false);
            });
        } : function() {},
        onerror: function() {},
        ontimeout: function() {}
    });
}

/**
* triggerKM(trigger, macroID, mode, extraText, copySelection)
*
* Binds a hotkey or hotstring to a Keyboard Maestro macro via Mousetrap.
*
* @param {string|string[]} trigger        - Hotkey (e.g. 'mod+d', ['mod+d','ctrl+d']) or
*                                           hotstring (e.g. 'hello'). 'mod' resolves to
*                                           Cmd on Mac, Ctrl on Windows/Linux.
* @param {string}          macroID        - KM macro UUID
*                                           (e.g. '97649BB0-C8D9-43BB-89DF-420DD20B3DFE')
* @param {number}          [mode=3]       - Focus context filter:
*                                             1 = outside editbox only
*                                             2 = inside editbox only
*                                             3 = anywhere (default)
* @param {string}          [extraText=''] - Optional text passed along in the KM payload.
*                                           Accessible in KM via the %TriggerValue% token.
* @param {boolean}         [copySelection=true] - If true, copies the current selection to
*                                           the clipboard (via execCommand('copy')) before
*                                           firing the KM macro. Useful when the macro needs
*                                           the selected text available on the clipboard (for history purpose).
*
*/
function triggerKM(trigger, macroID, mode = 3, extraText = '', copySelection = true) {
    Mousetrap.bindGlobal(trigger, function () {
        const inBox = isInEditbox();
        if (mode === 1 && inBox)  return true;
        if (mode === 2 && !inBox) return true;
        if (copySelection) document.execCommand('copy');
        requestKM(macroID, extraText);
        return false;
    });
}