Colemak-DH Remapper for Remote Desktop

Remaps QWERTY key codes to Colemak-DH for Google Remote Desktop

// ==UserScript==
// @name         Colemak-DH Remapper for Remote Desktop
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  Remaps QWERTY key codes to Colemak-DH for Google Remote Desktop
// @author       Michael M
// @license      LGPL-3.0-or-later
// @match        https://remotedesktop.google.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    const keyMap = {
        'Digit7': 'Equal',
        'Digit8': 'Digit7',
        'Digit9': 'Digit8',
        'Digit0': 'Digit9',
        'Minus': 'Digit0',
        'Equal': 'Minus',
        'KeyQ': 'KeyQ',
        'KeyW': 'KeyW',
        'KeyE': 'KeyF',
        'KeyR': 'KeyP',
        'KeyT': 'KeyB',
        'KeyY': 'BracketLeft',
        'KeyU': 'KeyJ',
        'KeyI': 'KeyL',
        'KeyO': 'KeyU',
        'KeyP': 'KeyY',
        'BracketLeft': 'Colon',
        'BracketRight': 'Slash',
        'KeyA': 'KeyA',
        'KeyS': 'KeyR',
        'KeyD': 'KeyS',
        'KeyF': 'KeyT',
        'KeyG': 'KeyG',
        'KeyH': 'BracketRight',
        'KeyJ': 'KeyM',
        'KeyK': 'KeyN',
        'KeyL': 'KeyE',
        'Semicolon': 'KeyI',
        'Quote': 'KeyO',
        'Backslash': 'Quote',
        'IntlBackslash': 'KeyZ',
        'KeyZ': 'KeyX',
        'KeyX': 'KeyC',
        'KeyC': 'KeyD',
        'KeyV': 'KeyV',
        'KeyB': 'Backslash',
        'KeyN': 'KeyN', // KeyN is handled separately since the #/~ key has no code
        'KeyM': 'KeyK',
        'Comma': 'KeyH',
        'Period': 'Comma',
        'Slash': 'Period',
    };

    const remapper = (e) => {
        // Only process events generated by the user, not by this script.
        if (!e.isTrusted) {
            return;
        }

        if (keyMap[e.code] && e.target.getAttribute('jsname') === 'fQxT4c') {
            e.preventDefault();
            e.stopPropagation();

            // Handle 'n' and 'N' mapping
            let newCode = (e.code === 'KeyN') ? (e.shiftKey ? 'Backquote' : 'Digit3') : keyMap[e.code]

            const newEvent = new KeyboardEvent('keydown', {
                key: e.key,
                code: newCode,
                bubbles: true,
                cancelable: true,
                composed: true,
                location: e.location,
                ctrlKey: e.ctrlKey,
                shiftKey: ((e.code === 'KeyN') || (e.shiftKey)),
                altKey: e.altKey,
                metaKey: e.metaKey,
                repeat: e.repeat,
            });
            if (e.code === 'KeyN' && !e.shiftKey) {
                e.target.dispatchEvent(new KeyboardEvent('keydown', {
                    key: 'Shift',
                    code: 'ShiftLeft',
                    bubbles: true,
                    cancelable: true,
                    composed: true,
                    location: 1, // left shift
                }));
                e.target.dispatchEvent(newEvent);
                e.target.dispatchEvent(new KeyboardEvent('keyup', {
                    key: 'Shift',
                    code: 'ShiftLeft',
                    bubbles: true,
                    cancelable: true,
                    composed: true,
                    location: 1
                }));
            } else {
                e.target.dispatchEvent(newEvent);
            }
        }
    };

    document.addEventListener('keydown', remapper, true);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址