您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
jホールドでリピート開始/リピート中にjで加速/他キーで停止
// ==UserScript== // @name Repeat Key // @author to // @namespace https://github.com/to // @version 0.2 // @match https://twitter.com/* // @description jホールドでリピート開始/リピート中にjで加速/他キーで停止 // @icon https://www.google.com/s2/favicons?domain=twitter.com // @license MIT // ==/UserScript== (function() { const opt = { hold: 250, interval: 800, decrement: 200, min: 400, key: 'j', }; // keypressイベントではcharCode(小文字)が使われる opt.charCode = opt.key.charCodeAt(0); opt.keyCode = opt.charCode - 32; var repeater = { onMouseDown: function name(params) { this.state.stop(); }, onKeyDown: function (e) { if (e.fake) return; // 対象外のキーか? if (e.keyCode != opt.keyCode) { this.state.stop(); return; } if (e.repeat) repeater.cancelEvent(e); this.state.onKeyDown(e); }, onKeyPress: function (e) { // 対象外のキーか? if (e.fake || e.keyCode != opt.charCode) return; this.state.onKeyPress(e); }, onKeyUp: function (e) { // 対象外のキーか? if (e.fake || e.keyCode != opt.keyCode) return; this.state.onKeyUp(e); }, startRepeat: function () { // 既存のリピートを停止する this.stopRepeat(); this.timer = setInterval(() => { repeater.dispatchEvent(); }, repeater.interval); }, dispatchEvent: function () { document.dispatchEvent(repeater.createEvent('keydown')); document.dispatchEvent(repeater.createEvent('keypress')); document.dispatchEvent(repeater.createEvent('keyup')); }, createEvent: function (type) { let event = new KeyboardEvent(type, { keyCode: type == 'keypress' ? opt.charCode : opt.keyCode, key: opt.key, bubbles: true, }); // 生成したイベントにフラグを付加し、判別に用いる event.fake = true; return event; }, stopRepeat: function () { clearInterval(this.timer); }, cancelEvent: function (event) { // 他ハンドラも含めて伝播を完全に停止する event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); }, states: { normal: { onKeyDown: function (e) { // ホールド開始時刻を保存する repeater.start = Date.now(); repeater.state = repeater.states.holding; }, onKeyPress: function (e) { }, onKeyUp: function (e) { }, stop: function () { }, }, holding: { onKeyDown: function (e) { // ホールド開始から一定時間が経過していないか? if (Date.now() < (repeater.start + opt.hold)) return; // リピート開始前にkeyupを発生させ、一連のキー押下を終わらせる document.dispatchEvent(repeater.createEvent('keyup')); repeater.interval = opt.interval; repeater.startRepeat(); repeater.state = repeater.states.repeating; }, onKeyPress: function e() { }, onKeyUp: function (e) { repeater.state = repeater.states.normal; }, stop: function () { }, }, repeating: { onKeyDown: function (e) { if (e.repeat) return; repeater.cancelEvent(e); // リピート間隔を減らす repeater.interval = Math.max(repeater.interval - opt.decrement, opt.min); repeater.startRepeat(); }, onKeyPress: function (e) { repeater.cancelEvent(e); }, onKeyUp: function (e) { repeater.cancelEvent(e); }, stop: function () { repeater.stopRepeat(); repeater.state = repeater.states.normal; }, }, } }; repeater.state = repeater.states.normal; document.addEventListener('keydown', repeater.onKeyDown.bind(repeater), true); document.addEventListener('keypress', repeater.onKeyPress.bind(repeater), true); document.addEventListener('keyup', repeater.onKeyUp.bind(repeater), true); document.addEventListener('mousedown', repeater.onMouseDown.bind(repeater), true); })();