SHOW:
|
|
- or go back to the newest paste.
1 | // ==UserScript== | |
2 | // @name keyboard controls | |
3 | // @namespace majsoul_script | |
4 | // @version 1.0 | |
5 | // @author anon | |
6 | // @match https://www.majsoul.com/* | |
7 | // @match https://game.maj-soul.com/* | |
8 | // @match https://majsoul.union-game.com/ | |
9 | // @match https://game.mahjongsoul.com/ | |
10 | // @match https://mahjongsoul.game.yo-star.com/ | |
11 | // @description RTFM | |
12 | // ==/UserScript== | |
13 | // v3 | |
14 | // get keycodes here: https://keycode.info/ | |
15 | // skip and discard hotkeys will also press the Confirm button at the end of round/game | |
16 | ||
17 | ||
18 | // planned: | |
19 | // selector for multi-wait chi calls | |
20 | ||
21 | // maybe: | |
22 | // tsumogiri + cancel on same button? might be conflicts such as tenpai state | |
23 | // correctly switch selected tile after calling if tile moved | |
24 | // allow skipping of quest/reward screen | |
25 | ||
26 | ||
27 | // If CONFIRM_DISCARDS is false tile hotkeys will discard immediately. | |
28 | var CONFIRM_DISCARDS = false; | |
29 | // show the hotkeys underneath the tiles. | |
30 | var SHOW_TILE_HOTKEYS = true; | |
31 | // 1 2 3 4 5 6 7 8 9 0 - = bksp | | |
32 | var TILE_HOTKEYS = [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 189, 187, 8, 220]; | |
33 | // some may not display correctly, override below: | |
34 | var TILE_DISP = ['', '', '', '', '', '', '', '', '', '', '', '=', '←', '\\']; | |
35 | var HOTKEYS = { | |
36 | // skip and discard hotkeys will also press the Confirm button at the end of round/game | |
37 | 'left': 37, // left arrow | |
38 | 'right': 39, // right arrow | |
39 | 'discard': 13, // enter | |
40 | 'tsumogiri': 84, // t | |
41 | 'skip': 83, // s | |
42 | 'pon': 80, // p | |
43 | 'chi': 67, // c | |
44 | 'kan': 75, // k | |
45 | 'win': 87, // w | |
46 | 'riichi': 82, // r | |
47 | 'pei': 78, // n | |
48 | 'nineterminalsabort': 188, // , | |
49 | 'autowin': 72, // h | |
50 | 'nocall': 70, // f | |
51 | 'autogiri': 68, // d | |
52 | } | |
53 | // NUMPAD KEYS: 7 8 9 4 5 6 1 2 3 0 . + | |
54 | var EMOJI_HOTKEYS = [103, 104, 105, 100, 101, 102, 97, 98, 99, 96, 110, 107]; | |
55 | ////////////////////////////////////////////// | |
56 | ////////////////////////////////////////////// | |
57 | ////////////////////////////////////////////// | |
58 | var waitkbmod = setInterval(() => { | |
59 | try { | |
60 | uiscript.UI_DesktopInfo.Inst.block_emo | |
61 | view.ViewPlayer_Me.Inst.hand | |
62 | ||
63 | window.onkeydown = function(e) { | |
64 | // should enable spamming while key is held down (might be system/browser dependant) | |
65 | var key = e.keyCode ? e.keyCode : e.which; | |
66 | switch (key) { | |
67 | case HOTKEYS.left: | |
68 | // move 1 tile left | |
69 | move_left(); | |
70 | break; | |
71 | case HOTKEYS.right: | |
72 | // move 1 tile right | |
73 | move_right(); | |
74 | break; | |
75 | } | |
76 | } | |
77 | window.onkeyup = function(e) { | |
78 | var key = e.keyCode ? e.keyCode : e.which; | |
79 | switch (key) { | |
80 | case HOTKEYS.discard: | |
81 | discardTile(selectedTile); | |
82 | pressConfirm(); | |
83 | break; | |
84 | case HOTKEYS.tsumogiri: | |
85 | discardTile(view.ViewPlayer_Me.Inst.hand.length - 1); | |
86 | break; | |
87 | case HOTKEYS.skip: | |
88 | callOperation('btn_cancel') | |
89 | pressConfirm(); | |
90 | break; | |
91 | case HOTKEYS.pon: | |
92 | callOperation('btn_peng') | |
93 | break; | |
94 | case HOTKEYS.chi: | |
95 | callOperation('btn_chi') | |
96 | // if there are multiple, check this._data.chi.length > 1, see i.prototype.onBtn_Chi | |
97 | break; | |
98 | case HOTKEYS.kan: | |
99 | callOperation('btn_gang') | |
100 | break; | |
101 | case HOTKEYS.win: | |
102 | callOperation('btn_hu') | |
103 | callOperation('btn_zimo') | |
104 | break; | |
105 | case HOTKEYS.riichi: | |
106 | callOperation('btn_lizhi') | |
107 | break; | |
108 | case HOTKEYS.pei: | |
109 | callOperation('btn_babei') | |
110 | break; | |
111 | case HOTKEYS.nineterminalsabort: | |
112 | callOperation('btn_jiuzhongjiupai') | |
113 | break; | |
114 | case HOTKEYS.autowin: | |
115 | toggleAuto('btn_autohu') | |
116 | break; | |
117 | case HOTKEYS.nocall: | |
118 | toggleAuto('btn_autonoming') | |
119 | break; | |
120 | case HOTKEYS.autogiri: | |
121 | toggleAuto('btn_automoqie') | |
122 | break; | |
123 | } | |
124 | // send emojis | |
125 | if (EMOJI_HOTKEYS.includes(key)) { | |
126 | sendEmoji(EMOJI_HOTKEYS.indexOf(key)); | |
127 | } | |
128 | // choose tile directly | |
129 | if (TILE_HOTKEYS.includes(key)) { | |
130 | var tile = TILE_HOTKEYS.indexOf(key); | |
131 | if (tile < view.ViewPlayer_Me.Inst.hand.length) { | |
132 | if (CONFIRM_DISCARDS) | |
133 | selectTile(tile); | |
134 | else | |
135 | discardTile(tile); | |
136 | ||
137 | } | |
138 | } | |
139 | ||
140 | } | |
141 | ||
142 | function toggleAuto(op) { | |
143 | uiscript.UI_DesktopInfo.Inst._container_fun.getChildByName(op)._clickHandler.method() | |
144 | } | |
145 | ||
146 | function discardTile(index) { | |
147 | view.ViewPlayer_Me.Inst._choose_pai = view.ViewPlayer_Me.Inst.hand[index]; | |
148 | view.ViewPlayer_Me.Inst.can_discard && view.ViewPlayer_Me.Inst._choose_pai.valid && (view.ViewPlayer_Me.Inst.DoDiscardTile(), | |
149 | view.ViewPlayer_Me.Inst.resetMouseState()) | |
150 | } | |
151 | ||
152 | function pressConfirm() { | |
153 | if (uiscript.UIMgr.Inst && uiscript.UIMgr.Inst._ui_liuju && uiscript.UIMgr.Inst._ui_liuju._enable) | |
154 | uiscript.UIMgr.Inst._ui_liuju.onBtnConfirm(); | |
155 | if (uiscript.UIMgr.Inst && uiscript.UIMgr.Inst._ui_gameend && uiscript.UIMgr.Inst._ui_gameend._enable) | |
156 | uiscript.UIMgr.Inst._ui_gameend.onConfirm(); | |
157 | if (uiscript.UI_Huleshow.Inst && uiscript.UI_Huleshow.Inst._enable) | |
158 | uiscript.UI_Huleshow.Inst.onBtnConfirm(); | |
159 | if (uiscript.UI_ScoreChange.Inst && uiscript.UI_ScoreChange.Inst._enable) | |
160 | uiscript.UI_ScoreChange.Inst.onBtnConfirm(); | |
161 | if (uiscript.UIMgr.Inst && uiscript.UIMgr.Inst._ui_win && uiscript.UIMgr.Inst._ui_win._enable) | |
162 | uiscript.UIMgr.Inst._ui_win.onConfirm(); | |
163 | } | |
164 | ||
165 | function sendEmoji(index) { | |
166 | var validc = 0; | |
167 | if (!uiscript.UI_DesktopInfo.Inst.block_emo.allgray) | |
168 | uiscript.UI_DesktopInfo.Inst.block_emo.scrollview._container_items._childs.some((e, i) => { | |
169 | if (e.getChildByName('btn')._clickHandler) { | |
170 | if (validc == index) { | |
171 | uiscript.UI_DesktopInfo.Inst.block_emo.muted = true; | |
172 | uiscript.UI_DesktopInfo.Inst.block_emo.scrollview._container_items._childs[i].getChildByName('btn')._clickHandler.method() | |
173 | return true; | |
174 | } | |
175 | validc++; | |
176 | } | |
177 | }); | |
178 | } | |
179 | uiscript.UI_DesktopInfo.Inst.block_emo.__proto__.switchShow = (function() { | |
180 | var cacheF = uiscript.UI_DesktopInfo.Inst.block_emo.__proto__.switchShow; | |
181 | return function() { | |
182 | if (this.muted) | |
183 | this.muted = false; | |
184 | else | |
185 | return cacheF.apply(this, arguments); | |
186 | }; | |
187 | })(); | |
188 | ||
189 | var selectedTile = 0; | |
190 | ||
191 | function selectTile(index) { | |
192 | var n = 0, | |
193 | a = 0; | |
194 | Laya.Browser.width / 1920 < Laya.Browser.height / 1080 ? a = (Laya.Browser.height - Laya.Browser.width / 1920 * 1080) / 2 : n = (Laya.Browser.width - Laya.Browser.height / 1080 * 1920) / 2; | |
195 | Laya.MouseManager.instance.mouseX = ((index * view.ViewPlayer_Me.Inst.handwidth + view.ViewPlayer_Me.Inst.handorigin_x) - view.ViewPlayer_Me.Inst.screen_left) / (view.ViewPlayer_Me.Inst.screen_right - view.ViewPlayer_Me.Inst.screen_left) * (Laya.Browser.width - 2 * n); | |
196 | Laya.MouseManager.instance.mouseY = (-view.ViewPlayer_Me.Inst.screen_top) / (view.ViewPlayer_Me.Inst.screen_bottom - view.ViewPlayer_Me.Inst.screen_top) * (Laya.Browser.height - 2 * a) | |
197 | selectedTile = index; | |
198 | } | |
199 | ||
200 | function move_left() { | |
201 | selectedTile = (selectedTile + view.ViewPlayer_Me.Inst.hand.length - 1) % view.ViewPlayer_Me.Inst.hand.length; | |
202 | while (!view.ViewPlayer_Me.Inst.hand[selectedTile].valid) { | |
203 | selectedTile = (selectedTile + view.ViewPlayer_Me.Inst.hand.length - 1) % view.ViewPlayer_Me.Inst.hand.length; | |
204 | } | |
205 | selectTile(selectedTile); | |
206 | } | |
207 | ||
208 | function move_right() { | |
209 | selectedTile = (selectedTile + 1) % view.ViewPlayer_Me.Inst.hand.length; | |
210 | while (!view.ViewPlayer_Me.Inst.hand[selectedTile].valid) { | |
211 | selectedTile = (selectedTile + 1) % view.ViewPlayer_Me.Inst.hand.length; | |
212 | } | |
213 | selectTile(selectedTile); | |
214 | } | |
215 | ||
216 | function callOperation(opname) { | |
217 | this.GameMgr.Inst._pre_mouse_point = new Laya.Point(1, 1); | |
218 | if (uiscript.UI_LiQiZiMo.Inst.enable && uiscript.UI_LiQiZiMo.Inst._oplist.includes(opname)) { | |
219 | uiscript.UI_LiQiZiMo.Inst.onClickOpBtn(opname) | |
220 | } else if (uiscript.UI_ChiPengHu.Inst.enable && uiscript.UI_ChiPengHu.Inst._oplist.includes(opname)) { | |
221 | uiscript.UI_ChiPengHu.Inst.onClickOpBtn(opname) | |
222 | } | |
223 | } | |
224 | ||
225 | var keycss = ` | |
226 | :root { | |
227 | --keySize: 2.5vw; | |
228 | --keySizeH: 2.5vh; | |
229 | } | |
230 | .key__button { | |
231 | box-sizing: border-box; | |
232 | line-height: min(var(--keySize),calc(1.778*var(--keySizeH))); | |
233 | font-size: calc(.8*min(var(--keySize),calc(1.778*var(--keySizeH)))); | |
234 | text-align: center; | |
235 | width: var(--keySize); | |
236 | color: #555; | |
237 | height: var(--keySize); | |
238 | max-width: calc(1.778*var(--keySizeH)); | |
239 | max-height: calc(1.778*var(--keySizeH)); | |
240 | border-color: #f2f2f2; | |
241 | border-style: solid; | |
242 | text-shadow: 0 0.5px 1px #777, 0 2px 6px #f2f2f2; | |
243 | border-width: 1px; | |
244 | border-radius: calc(.25*min(var(--keySize),calc(1.778*var(--keySizeH)))); | |
245 | background: -webkit-linear-gradient(top, #f9f9f9 0%, #D2D2D2 80%, #c0c0c0 100%); | |
246 | font-family: sans-serif; | |
247 | display: inline-block; | |
248 | transition: box-shadow 0.3s ease, transform 0.15s ease; | |
249 | box-shadow: 0 0 1px #888,0 1px 0 #fff, 0 6px 0 #C0C0C0, 0 8px 17px rgba(#444, 0.4), 2px 1px 4px rgba(#444, 0.25), -2px 1px 4px rgba(#444, 0.25), 0 9px 16px rgba(#444, 0.1); | |
250 | } | |
251 | #tileLabels { | |
252 | display: flex; | |
253 | justify-content: space-around; | |
254 | align-items: flex-end; | |
255 | height: 100%; | |
256 | width: var(--labelsWidth); | |
257 | margin-left: var(--offsetLeft); | |
258 | pointer-events: none; | |
259 | } | |
260 | #tileWrapper | |
261 | { | |
262 | width: 100vw; | |
263 | height: 56.25vw; /* 100/56.25 = 1.778 */ | |
264 | max-height: 100vh; | |
265 | max-width: 177.78vh; /* 16/9 = 1.778 */ | |
266 | margin: auto; | |
267 | position: absolute; | |
268 | top:0;bottom:0; /* vertical center */ | |
269 | left:0;right:0; /* horizontal center */ | |
270 | pointer-events: none; | |
271 | } | |
272 | `, | |
273 | head = document.head || document.getElementsByTagName('head')[0], | |
274 | style = document.getElementById('tileStyle') || document.createElement("STYLE"); | |
275 | style.setAttribute('id', 'tileStyle'); | |
276 | style.innerHTML = ''; | |
277 | style.type = 'text/css'; | |
278 | head.appendChild(style); | |
279 | var n = 0, | |
280 | a = 0; | |
281 | ||
282 | Laya.Browser.width / 1920 < Laya.Browser.height / 1080 ? a = (Laya.Browser.height - Laya.Browser.width / 1920 * 1080) / 2 : n = (Laya.Browser.width - Laya.Browser.height / 1080 * 1920) / 2; | |
283 | var x = (view.ViewPlayer_Me.Inst.handorigin_x - view.ViewPlayer_Me.Inst.screen_left - view.ViewPlayer_Me.Inst.handwidth / 2) / (view.ViewPlayer_Me.Inst.screen_right - view.ViewPlayer_Me.Inst.screen_left), | |
284 | w = view.ViewPlayer_Me.Inst.handwidth * 14 / (view.ViewPlayer_Me.Inst.screen_right - view.ViewPlayer_Me.Inst.screen_left); | |
285 | var keycssvars = ':root {--offsetLeft: ' + x * 100 + '%; --labelsWidth:' + w * 100 + '%; --maxWidth:' + w * 100 * 16 / 9 + 'vh}'; | |
286 | style.appendChild(document.createTextNode(keycssvars)); | |
287 | style.appendChild(document.createTextNode(keycss)); | |
288 | ||
289 | ||
290 | var tileWrapper = document.getElementById('tileWrapper') || document.createElement("DIV"); | |
291 | var tileLabels = document.getElementById('tileLabels') || document.createElement("DIV"); | |
292 | tileWrapper.innerHTML = ''; | |
293 | tileWrapper.setAttribute('id', 'tileWrapper') | |
294 | tileLabels.innerHTML = ''; | |
295 | tileLabels.setAttribute('id', 'tileLabels') | |
296 | tileWrapper.appendChild(tileLabels); | |
297 | var TILE_ELEMENTS = []; | |
298 | TILE_HOTKEYS.forEach((key, i) => { | |
299 | let kdiv = document.createElement('DIV'); | |
300 | kdiv.setAttribute('class', 'key__button'); | |
301 | if (TILE_DISP[i]) | |
302 | kdiv.innerHTML = TILE_DISP[i]; | |
303 | else { | |
304 | let chrCode = key - 48 * Math.floor(key / 48); | |
305 | let chr = String.fromCharCode((96 <= key) ? chrCode : key); | |
306 | kdiv.innerHTML = chr; | |
307 | } | |
308 | tileLabels.appendChild(kdiv); | |
309 | TILE_ELEMENTS.push(kdiv); | |
310 | }); | |
311 | document.body.appendChild(tileWrapper); | |
312 | ||
313 | function isInGame() { | |
314 | - | if (isInGame()) { |
314 | + | |
315 | } | |
316 | setInterval(() => { | |
317 | if (isInGame() && SHOW_TILE_HOTKEYS) { | |
318 | tileLabels.style.display = 'flex'; | |
319 | // hide unneeded hotkeys | |
320 | TILE_ELEMENTS.forEach((e, i) => { | |
321 | if (i < view.ViewPlayer_Me.Inst.hand.length) | |
322 | e.style.visibility = 'visible'; | |
323 | else | |
324 | e.style.visibility = 'hidden'; | |
325 | }); | |
326 | ||
327 | } else | |
328 | tileLabels.style.display = 'none'; | |
329 | }, 500); | |
330 | ||
331 | clearInterval(waitkbmod); | |
332 | } catch (TypeError) {} | |
333 | }, 1000); |