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.
// ==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;
});
}