Greasy Fork镜像 支持简体中文。

Pixiv-JoystickControl

Implement joystick control in Pixiv using the HTML5 Gamepad API.

  1. // ==UserScript==
  2. // @name Pixiv-JoystickControl
  3. // @name:zh-CN Pixiv-摇杆控制
  4. // @name:ja Pixiv-コントローラー制御
  5. // @namespace https://github.com/Mehver
  6. // @version 1.0
  7. // @description Implement joystick control in Pixiv using the HTML5 Gamepad API.
  8. // @description:zh-CN 使用HTML5 Gamepad API在Pixiv上实现操纵杆控制。
  9. // @description:ja HTML5 Gamepad APIを使用してPixivでジョイスティックコントロールを実装します。
  10. // @author https://github.com/Mehver
  11. // @icon data:image/png;base64,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
  12. // @match http*://pixiv.net
  13. // @match http*://pixiv.net/*
  14. // @match http*://www.pixiv.net
  15. // @match http*://www.pixiv.net/*
  16. // @license MPL-2.0
  17. // @license Mozilla Public License 2.0
  18. // @homepageURL https://github.com/SynRGB/Pixiv-JoystickControl
  19. // @contributionURL https://github.com/SynRGB/Pixiv-JoystickControl
  20. // @copyright Copyright © 2022-PRESENT, Mehver (https://github.com/Mehver)
  21. // @charset UTF-8
  22. // @grant GM_registerMenuCommand
  23. // @grant GM_setValue
  24. // @grant GM_getValue
  25. // @grant unsafeWindow
  26. // @run-at document-end
  27. // ==/UserScript==
  28.  
  29. (function () {
  30. 'use strict';
  31.  
  32. let buttonA, buttonB, buttonX, buttonY, buttonRB, buttonLB, buttonRT, buttonLT;
  33. let buttonESC, buttonLike, buttonPageBack, buttonPageForward;
  34. // let buttonTabindexExit, buttonShiftTab, buttonTab, buttonEnter;
  35.  
  36. let buttonPageBackPrevious = false;
  37. let buttonPageForwardPrevious = false;
  38.  
  39. let buttonTabindexExitPrevious = false;
  40. let buttonShiftTabPrevious = false;
  41. let buttonTabPrevious = false;
  42. let buttonEnterPrevious = false;
  43.  
  44.  
  45. let preset = GM_getValue("preset", "Xbox");
  46.  
  47. function setupPreset() {
  48. buttonA = preset === "Xbox" ? 0 : 2;
  49. buttonB = preset === "Xbox" ? 1 : 1;
  50. buttonX = preset === "Xbox" ? 2 : 0;
  51. buttonY = preset === "Xbox" ? 3 : 3;
  52. buttonRB = preset === "Xbox" ? 5 : 5;
  53. buttonLB = preset === "Xbox" ? 4 : 4;
  54. buttonRT = preset === "Xbox" ? 7 : 7;
  55. buttonLT = preset === "Xbox" ? 6 : 6;
  56.  
  57. // buttonESC = buttonA;
  58. // buttonLike = buttonB;
  59. // buttonPageBack = buttonX;
  60. // buttonPageForward = buttonY;
  61. }
  62.  
  63. function switchToXbox() {
  64. preset = "Xbox";
  65. GM_setValue("preset", "Xbox");
  66. setupPreset();
  67. }
  68.  
  69. function switchToPlayStation() {
  70. preset = "PlayStation";
  71. GM_setValue("preset", "PlayStation");
  72. setupPreset();
  73. }
  74.  
  75. GM_registerMenuCommand("Switch to Xbox preset", switchToXbox);
  76. GM_registerMenuCommand("Switch to PlayStation preset", switchToPlayStation);
  77.  
  78. setupPreset();
  79.  
  80. window.addEventListener("gamepadconnected", (event) => {
  81. console.log("A gamepad was connected:", event.gamepad);
  82. });
  83.  
  84. let lastAxis0 = null;
  85. let lastAxis1 = null;
  86.  
  87. function simulateKeyPress(key, extraParams = {}) {
  88. const eventInitDict = {bubbles: true, cancelable: true, composed: true, ...extraParams};
  89. document.dispatchEvent(new KeyboardEvent('keydown', {...eventInitDict, key}));
  90. document.dispatchEvent(new KeyboardEvent('keyup', {...eventInitDict, key}));
  91. }
  92.  
  93. function focusNextElement(reverse = false) {
  94. const focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
  95. const focusables = Array.from(document.querySelectorAll(focusableElements));
  96.  
  97. const currentIndex = focusables.findIndex(el => el === document.activeElement);
  98. let nextIndex = reverse ? currentIndex - 1 : currentIndex + 1;
  99.  
  100. if (nextIndex < 0) nextIndex = focusables.length - 1;
  101. if (nextIndex >= focusables.length) nextIndex = 0;
  102.  
  103. focusables[nextIndex]?.focus();
  104. }
  105.  
  106. function pollGamepad() {
  107. const gamepads = navigator.getGamepads();
  108. if (gamepads[0]) {
  109. const gp = gamepads[0];
  110.  
  111. if (lastAxis0 === null) lastAxis0 = gp.axes[0];
  112. if (lastAxis1 === null) lastAxis1 = gp.axes[1];
  113.  
  114. if (Math.abs(gp.axes[0] - lastAxis0) > 0.7) {
  115. if (gp.axes[0] > 0.7) {
  116. simulateKeyPress("ArrowRight");
  117. } else if (gp.axes[0] < -0.7) {
  118. simulateKeyPress("ArrowLeft");
  119. }
  120. lastAxis0 = gp.axes[0];
  121. }
  122.  
  123. if (Math.abs(gp.axes[1] - lastAxis1) > 0.7) {
  124. if (gp.axes[1] > 0.7) {
  125. simulateKeyPress("ArrowDown");
  126. } else if (gp.axes[1] < -0.7) {
  127. simulateKeyPress("ArrowUp");
  128. }
  129. lastAxis1 = gp.axes[1];
  130. }
  131.  
  132. if (gp.buttons[buttonESC].pressed) {
  133. simulateKeyPress("Escape");
  134. }
  135.  
  136. if (gp.buttons[buttonLike].pressed) {
  137. const url = window.location.href;
  138. const artworksRegex1 = /\/artworks\/\d+/;
  139. if (artworksRegex1.test(url)) {
  140. const xpath1 = '//*[@id="root"]/div[2]/div/div[3]/div/div/div[1]/main/section/div[1]/div/div[4]/div/div[2]/section/div[3]/button';
  141. const xpath2 = '//*[@id="root"]/div[2]/div/div[3]/div/div/div[1]/main/section/div[1]/div/div[4]/div/div[2]/section/div[3]/a';
  142. const xpath3 = '//*[@id="root"]/div[2]/div/div[3]/div/div/div[1]/main/section/div[1]/div/div[5]/div/div[2]/section/div[3]/a';
  143. const element1 = document.evaluate(xpath1, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  144. const element2 = document.evaluate(xpath2, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  145. const element3 = document.evaluate(xpath3, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  146. if (element1) {
  147. element1.click();
  148. } else if (element2) {
  149. element2.click();
  150. } else if (element3) {
  151. element3.click();
  152. }
  153. }
  154. const artworksRegex2 = /\/bookmark_add\.php\?type=illust&illust_id=\d+/;
  155. if (artworksRegex2.test(url)) {
  156. const xpath = '//*[@id="wrapper"]/div[1]/section/form[2]/input[7]';
  157. const element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  158. if (element) {
  159. element.click();
  160. }
  161. }
  162. }
  163.  
  164. if (gp.buttons[buttonPageBack].pressed && !buttonPageBackPrevious) {
  165. window.history.back();
  166. }
  167. buttonPageBackPrevious = gp.buttons[buttonPageBack].pressed;
  168.  
  169. if (gp.buttons[buttonPageForward].pressed && !buttonPageForwardPrevious) {
  170. window.history.forward();
  171. }
  172. buttonPageForwardPrevious = gp.buttons[buttonPageForward].pressed;
  173.  
  174. // if (gp.buttons[buttonTabindexExit].pressed) {
  175. // document.elementFromPoint(10, 10)?.click();
  176. // }
  177. // buttonTabindexExitPrevious = gp.buttons[buttonTabindexExit].pressed;
  178. //
  179. // if (gp.buttons[buttonEnter].pressed && !buttonEnterPrevious) {
  180. // simulateKeyPress("Enter");
  181. // }
  182. // buttonEnterPrevious = gp.buttons[buttonEnter].pressed;
  183. //
  184. // if (gp.buttons[buttonShiftTab].pressed && !buttonShiftTabPrevious) {
  185. // focusNextElement(true);
  186. // }
  187. // buttonShiftTabPrevious = gp.buttons[buttonShiftTab].pressed;
  188. //
  189. // if (gp.buttons[buttonTab].pressed && !buttonTabPrevious) {
  190. // focusNextElement();
  191. // }
  192. // buttonTabPrevious = gp.buttons[buttonTab].pressed;
  193. }
  194. requestAnimationFrame(pollGamepad);
  195. }
  196.  
  197. pollGamepad();
  198.  
  199. console.log("JS script Pixiv-JoystickControl (Pixiv-摇杆控制) loaded. See more details at https://github.com/SynRGB/Pixiv-JoystickControl");
  200. })();

QingJ © 2025

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