├── .clang-format ├── .github ├── pull_request_template.md └── workflows │ └── auto-assign.yml ├── .gitignore ├── LICENSE ├── README.md ├── examples ├── Pokemon_BDSP │ ├── auto-hatch-eggs │ │ └── auto-hatch-eggs.ino │ └── auto-release-pokemons │ │ └── auto-release-pokemons.ino ├── Pokemon_Legends_Arceus │ └── auto-level-up │ │ └── auto-level-up.ino ├── Pokemon_SWSH │ ├── auto-gain-watt │ │ └── auto-gain-watt.ino │ ├── auto-hatch-eggs │ │ └── auto-hatch-eggs.ino │ ├── auto-hatch-eggs_shiny │ │ └── auto-hatch-eggs_shiny.ino │ ├── auto-receive-eggs │ │ └── auto-receive-eggs.ino │ ├── battle-tower-automation │ │ └── battle-tower-automation.ino │ ├── collect-fossils │ │ └── collect-fossils.ino │ ├── dynamax-adventure │ │ └── dynamax-adventure.ino │ ├── fossil-pokemons │ │ ├── arctovish │ │ │ └── arctovish.ino │ │ ├── arctozolt │ │ │ └── arctozolt.ino │ │ ├── dracovish │ │ │ └── dracovish.ino │ │ └── dracozolt │ │ │ └── dracozolt.ino │ └── hatch-eggs-in-the-box │ │ └── hatch-eggs-in-the-box.ino ├── Splatoon3 │ └── get-ikura │ │ └── get-ikura.ino └── Xenoblade3 │ ├── auto-get-nopon-coins │ └── auto-get-nopon-coins.ino │ └── auto-leveling │ └── auto-leveling.ino ├── library.properties └── src ├── NintendoSwitchControlLibrary.cpp ├── NintendoSwitchControlLibrary.h └── SwitchControlLibrary ├── .clang-format ├── CustomHID.cpp ├── CustomHID.h ├── SwitchControlLibrary.cpp └── SwitchControlLibrary.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveBitFields: false 9 | AlignConsecutiveDeclarations: false 10 | AlignEscapedNewlines: Left 11 | AlignOperands: Align 12 | AlignTrailingComments: true 13 | AllowAllArgumentsOnNextLine: true 14 | AllowAllConstructorInitializersOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortBlocksOnASingleLine: Never 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: All 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortIfStatementsOnASingleLine: WithoutElse 22 | AllowShortLoopsOnASingleLine: true 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: true 26 | AlwaysBreakTemplateDeclarations: Yes 27 | BinPackArguments: true 28 | BinPackParameters: true 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: false 32 | AfterControlStatement: Never 33 | AfterEnum: false 34 | AfterFunction: false 35 | AfterNamespace: false 36 | AfterObjCDeclaration: false 37 | AfterStruct: false 38 | AfterUnion: false 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakBeforeBinaryOperators: None 49 | BreakBeforeBraces: Attach 50 | BreakBeforeInheritanceComma: false 51 | BreakInheritanceList: BeforeColon 52 | BreakBeforeTernaryOperators: true 53 | BreakConstructorInitializersBeforeComma: false 54 | BreakConstructorInitializers: BeforeColon 55 | BreakAfterJavaFieldAnnotations: false 56 | BreakStringLiterals: true 57 | ColumnLimit: 0 58 | CommentPragmas: '^ IWYU pragma:' 59 | CompactNamespaces: false 60 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 61 | ConstructorInitializerIndentWidth: 4 62 | ContinuationIndentWidth: 4 63 | Cpp11BracedListStyle: true 64 | DeriveLineEnding: true 65 | DerivePointerAlignment: true 66 | DisableFormat: false 67 | ExperimentalAutoDetectBinPacking: false 68 | FixNamespaceComments: true 69 | ForEachMacros: 70 | - foreach 71 | - Q_FOREACH 72 | - BOOST_FOREACH 73 | IncludeBlocks: Regroup 74 | IncludeCategories: 75 | - Regex: '^' 76 | Priority: 2 77 | SortPriority: 0 78 | - Regex: '^<.*\.h>' 79 | Priority: 1 80 | SortPriority: 0 81 | - Regex: '^<.*' 82 | Priority: 2 83 | SortPriority: 0 84 | - Regex: '.*' 85 | Priority: 3 86 | SortPriority: 0 87 | IncludeIsMainRegex: '([-_](test|unittest))?$' 88 | IncludeIsMainSourceRegex: '' 89 | IndentCaseLabels: true 90 | IndentCaseBlocks: false 91 | IndentGotoLabels: true 92 | IndentPPDirectives: None 93 | IndentExternBlock: AfterExternBlock 94 | IndentWidth: 4 95 | IndentWrappedFunctionNames: false 96 | InsertTrailingCommas: None 97 | JavaScriptQuotes: Leave 98 | JavaScriptWrapImports: true 99 | KeepEmptyLinesAtTheStartOfBlocks: false 100 | MacroBlockBegin: '' 101 | MacroBlockEnd: '' 102 | MaxEmptyLinesToKeep: 1 103 | NamespaceIndentation: None 104 | ObjCBinPackProtocolList: Never 105 | ObjCBlockIndentWidth: 2 106 | ObjCBreakBeforeNestedBlockParam: true 107 | ObjCSpaceAfterProperty: false 108 | ObjCSpaceBeforeProtocolList: true 109 | PenaltyBreakAssignment: 2 110 | PenaltyBreakBeforeFirstCallParameter: 1 111 | PenaltyBreakComment: 300 112 | PenaltyBreakFirstLessLess: 120 113 | PenaltyBreakString: 1000 114 | PenaltyBreakTemplateDeclaration: 10 115 | PenaltyExcessCharacter: 1000000 116 | PenaltyReturnTypeOnItsOwnLine: 200 117 | PointerAlignment: Left 118 | RawStringFormats: 119 | - Language: Cpp 120 | Delimiters: 121 | - cc 122 | - CC 123 | - cpp 124 | - Cpp 125 | - CPP 126 | - 'c++' 127 | - 'C++' 128 | CanonicalDelimiter: '' 129 | BasedOnStyle: google 130 | - Language: TextProto 131 | Delimiters: 132 | - pb 133 | - PB 134 | - proto 135 | - PROTO 136 | EnclosingFunctions: 137 | - EqualsProto 138 | - EquivToProto 139 | - PARSE_PARTIAL_TEXT_PROTO 140 | - PARSE_TEST_PROTO 141 | - PARSE_TEXT_PROTO 142 | - ParseTextOrDie 143 | - ParseTextProtoOrDie 144 | - ParseTestProto 145 | - ParsePartialTestProto 146 | CanonicalDelimiter: '' 147 | BasedOnStyle: google 148 | ReflowComments: true 149 | SortIncludes: true 150 | SortUsingDeclarations: true 151 | SpaceAfterCStyleCast: false 152 | SpaceAfterLogicalNot: false 153 | SpaceAfterTemplateKeyword: true 154 | SpaceBeforeAssignmentOperators: true 155 | SpaceBeforeCpp11BracedList: false 156 | SpaceBeforeCtorInitializerColon: true 157 | SpaceBeforeInheritanceColon: true 158 | SpaceBeforeParens: ControlStatements 159 | SpaceBeforeRangeBasedForLoopColon: true 160 | SpaceInEmptyBlock: false 161 | SpaceInEmptyParentheses: false 162 | SpacesBeforeTrailingComments: 2 163 | SpacesInAngles: false 164 | SpacesInConditionalStatement: false 165 | SpacesInContainerLiterals: true 166 | SpacesInCStyleCastParentheses: false 167 | SpacesInParentheses: false 168 | SpacesInSquareBrackets: false 169 | SpaceBeforeSquareBrackets: false 170 | Standard: Auto 171 | StatementMacros: 172 | - Q_UNUSED 173 | - QT_REQUIRE_VERSION 174 | TabWidth: 8 175 | UseCRLF: false 176 | UseTab: Never 177 | WhitespaceSensitiveMacros: 178 | - STRINGIZE 179 | - PP_STRINGIZE 180 | - BOOST_PP_STRINGIZE 181 | ... 182 | 183 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## やったこと 4 | 5 | 6 | ## 補足(任意) 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/auto-assign.yml: -------------------------------------------------------------------------------- 1 | name: Auto Assign 2 | 3 | on: 4 | pull_request: 5 | types: [opened] 6 | issues: 7 | types: [opened] 8 | 9 | jobs: 10 | assign: 11 | name: Assign author 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Assign author to created issue or PR 15 | uses: technote-space/assign-author@v1 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # General 35 | .DS_Store 36 | .AppleDouble 37 | .LSOverride 38 | 39 | # Icon must end with two \r 40 | Icon 41 | 42 | 43 | # Thumbnails 44 | ._* 45 | 46 | # Files that might appear in the root of a volume 47 | .DocumentRevisions-V100 48 | .fseventsd 49 | .Spotlight-V100 50 | .TemporaryItems 51 | .Trashes 52 | .VolumeIcon.icns 53 | .com.apple.timemachine.donotpresent 54 | 55 | # Directories potentially created on remote AFP share 56 | .AppleDB 57 | .AppleDesktop 58 | Network Trash Folder 59 | Temporary Items 60 | .apdisk 61 | 62 | # Private Files 63 | demo.gif 64 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 lefmarna 4 | 5 | Copyright (c) 2019 celclow 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NintendoSwitchControlLibrary 2 | 3 | Arduino を使って Nintendo Switch のゲームを自動化する、マイコン用のライブラリです。 4 | 5 | ![demo](https://user-images.githubusercontent.com/49473970/107502281-d0cc6c80-6bdb-11eb-9928-fb0a29744df6.gif) 6 | 7 | ## ⭐️ このライブラリについて 8 | 9 | このライブラリは celclow 氏の[SwitchControlLibrary](https://github.com/celclow/SwitchControlLibrary)を参考にして作られています。 10 | 11 | SwitchControlLibrary は自由度が高いものの、コードが冗長になりやすい点、ArduinoSTL を使用するためコンパイルに時間がかかる点などがネックでした。 12 | 13 | そこで、一般的によく使われる入力のパターンを厳選して関数にまとめることにしました。 14 | 15 | ボタンを押して離すまでの処理が 1 行で書けるようになり、より効率的に自動化プログラムを組むことができるようになります。連打や長押しの処理にも対応させ、汎用性の高いプログラムに仕上げました。 16 | 17 | そしてなにより、ArduinoSTL を使わずにこれらの処理を実装することに成功しています。これによりコンパイルが高速に行えるほか、依存関係に悩まされなくなっていることも特徴です。 18 | 19 | ## 🔹 導入方法 20 | 21 | ### 必要なもの 22 | 23 | - Arduino Leonardo 24 | - USB ケーブル(Arduino Leonardo と Switch や PC を接続するのに必要) 25 | 26 | ### 動作環境 27 | 28 | - Arduino IDE(1.8.13 推奨) 29 | - Arduino AVR Boards(1.8.3 推奨) 30 | 31 | 詳しい導入の手順については、ブログで解説していますので、そちらをご覧ください。 32 | 33 | [マイコンを導入して、ポケモン剣盾を自動化しよう!【Mac・Windows】|ポケモニット](https://pokemonit.com/micon-introduction/) 34 | 35 | ## ⚠️ 注意点 36 | 37 | Arduino Leonardo については、ブログ内で紹介しているものを推奨しています。その他の Arduino では動作確認を行っておりません。異なるものを使用している場合には、質問にも一切答えられませんので予めご了承ください。 38 | 39 | Arduino IDE やボードのバージョンは、基本的に最新の安定版のものを使って動作確認しています。古いバージョンでも使えるとは思いますが、動作を保証するものではありません。 40 | 41 | なお、Nintendo Switch のバージョンには指定がありません。どのバージョンでも問題なく動作するはずです。 42 | 43 | ## 📄 使い方 44 | 45 | ライブラリを使いたいファイルの先頭に以下のように記載してください。 46 | 47 | ``` 48 | #include 49 | ``` 50 | 51 | これでライブラリを読み込み、各種コマンドを使うことができるようになります。 52 | 53 | 単体で完結しているため、ArduinoSTL や [SwitchControlLibrary](https://github.com/celclow/SwitchControlLibrary) といった別のライブラリを読み込む必要はありません。 54 | 55 | **SwitchControlLibrary とは競合するため、同時に読み込むことはできません**が、NintendoSwitchControlLibrary は SwitchControlLibrary(v2 系)を継承して作られているため、SwitchControlLibrary のコマンドも使用することが可能となっています。(ArduinoSTL を使用していない都合で、十字キーのコマンドのみ動作が少し異なりますが、基本的には同じように使うことができます) 56 | 57 | ## ⌨️ コマンド一覧 58 | 59 | ### ボタン 60 | 61 | - ボタンを押すコマンド(連打にも対応) 62 | 63 | - `pushButton(uint16_t button, int delay_time = 0, int loop = 1)` 64 | 65 | - button: 押すボタン 66 | - delay_time: ボタンを押した後の待ち時間(1 秒 = 1000) 67 | - loop: ボタンを押す回数(省略可、デフォルトは 1) 68 | 69 | - 使用例 70 | 71 | ``` 72 | pushButton(Button::HOME); // HOMEボタンを入力する 73 | pushButton(Button::A, 500); // Aボタンを入力後、0.5秒待機する 74 | pushButton(Button::B, 3000, 10); // 3秒おきにBボタンを入力する、それを10回繰り返す 75 | ``` 76 | 77 | - ボタンを長押しするコマンド 78 | 79 | - `holdButton(uint16_t button, int hold_time)` 80 | 81 | - button: 押し続けるボタン 82 | - hold_time: ボタンを押す時間の長さ(1 秒 = 1000) 83 | 84 | - 使用例 85 | 86 | ``` 87 | holdButton(Button::L, 2000); // Lボタンを2秒間押し続けてから離す 88 | holdButton(Button::CAPTURE, 1500); // キャプチャーボタンを1.5秒間押し続けてから離す 89 | ``` 90 | 91 | - `Button` 定義一覧 92 | 93 | ``` 94 | Button::Y 95 | Button::B 96 | Button::A 97 | Button::X 98 | Button::L 99 | Button::R 100 | Button::ZL 101 | Button::ZR 102 | Button::MINUS 103 | Button::PLUS 104 | Button::LCLICK 105 | Button::RCLICK 106 | Button::HOME 107 | Button::CAPTURE 108 | ``` 109 | 110 | ### 十字キー(方向ボタン) 111 | 112 | - 十字キー(方向ボタン)を押すコマンド(連打にも対応) 113 | 114 | - `pushHat(uint8_t hat, int delay_time = 0, int loop = 1);` 115 | 116 | - hat: 押す十字キーのボタン 117 | - delay_time: ボタンを押した後の待ち時間(1 秒 = 1000) 118 | - loop: ボタンを押す回数(省略可、デフォルトは 1) 119 | 120 | - 使用例 121 | 122 | ``` 123 | pushHat(Hat::UP); // 上キーを1回だけ入力する 124 | pushHat(Hat::LEFT, 1000); // 左キーを入力後、1秒待機する 125 | pushHat(Hat::DOWN, 25, 5); // 0.25秒おきに下キーを入力する、それを5回繰り返す 126 | ``` 127 | 128 | - 十字キー(方向ボタン)を長押しするコマンド 129 | 130 | - `holdHat(uint8_t hat, int hold_time);` 131 | 132 | - hat: 押し続ける十字キーのボタン 133 | - hold_time: ボタンを押す時間の長さ(1 秒 = 1000) 134 | 135 | - 使用例 136 | 137 | ``` 138 | holdHat(Hat::RIGHT, 5000); // 右キーを5秒間押し続けてから離す 139 | holdHat(Hat::UP_LEFT, 2500); // 十字キーを左上方向に2.5秒間押し続けてから離す 140 | ``` 141 | 142 | - `Hat` 定義一覧 143 | 144 | ``` 145 | Hat::UP 146 | Hat::UP_RIGHT 147 | Hat::RIGHT 148 | Hat::DOWN_RIGHT 149 | Hat::DOWN 150 | Hat::DOWN_LEFT 151 | Hat::LEFT 152 | Hat::UP_LEFT 153 | Hat::NEUTRAL 154 | ``` 155 | 156 | ### スティック 157 | 158 | スティックの座標は、128 を基点として 0〜255 の値を指定します。 159 | 160 | 0・128・255 の 3 つの値は Stick で定義されているため、置き換えて使用することもできます(0 = MIN, NEUTRAL = 128, MAX = 255) 161 | 162 | また、引数にボタンを渡すことでボタンを連打しながらスティックを傾ける操作を行うことができます。 163 | 164 | - 左スティックを操作するコマンド 165 | 166 | - `tiltLeftStick(uint8_t lx, uint8_t ly, int tilt_time, uint16_t button = NULL);` 167 | 168 | - lx: 左スティックの x 軸 169 | - ly: 左スティックの y 軸 170 | - tilt_time: スティックを傾ける時間の長さ 171 | - button: 連打するボタン 172 | 173 | - 使用例 174 | 175 | ``` 176 | tiltLeftStick(0, 128, 5000); // 左スティックを左に5秒間倒す 177 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, 15000); // 左スティックを下に15秒間倒す 178 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 8000, Button::A); // Aボタンを連打しながら、左スティックを上に8秒間倒す 179 | ``` 180 | 181 | - 右スティックを操作するコマンド 182 | 183 | - `tiltRightStick(uint8_t rx, uint8_t ry, int tilt_time, uint16_t button = NULL);` 184 | 185 | - rx: 右スティックの x 軸 186 | - ry: 右スティックの y 軸 187 | - tilt_time: スティックを傾ける時間の長さ 188 | - button: 連打するボタン 189 | 190 | - 使用例 191 | 192 | ``` 193 | tiltRightStick(255, 128, 100); // 右スティックを右に0.1秒間倒す 194 | tiltRightStick(Stick::MAX, Stick::MIN, 10000); // 右スティックを右上に10秒間倒す 195 | tiltRightStick(Stick::NEUTRAL, Stick::MAX, 30000, Button::X); // Xボタンを連打しながら、右スティックを下に30秒間倒す 196 | ``` 197 | 198 | - 左右のスティックを同時に操作するコマンド 199 | 200 | - `tiltLeftAndRightStick(uint8_t lx, uint8_t ly, uint8_t rx, uint8_t ry, int tilt_time, uint16_t button = NULL);` 201 | 202 | - lx: 左スティックの x 軸 203 | - ly: 左スティックの y 軸 204 | - rx: 右スティックの x 軸 205 | - ry: 右スティックの y 軸 206 | - tilt_time: スティックを傾ける時間の長さ 207 | - button: 連打するボタン 208 | 209 | - 使用例 210 | 211 | ``` 212 | tiltLeftAndRightStick(128, 255, 0, 128, 1000); // 左スティックを下に、右スティックを左に1秒間倒す 213 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, 30000); // 左スティックを右下に、右スティックは左上に、30秒間倒す 214 | tiltLeftAndRightStick(Stick::NEUTRAL, Stick::MAX, Stick::MIN, Stick::MAX, 2000, Button::B); // Bボタンを連打しながら、左スティックを下に、右スティックは左下に、2秒間倒す 215 | ``` 216 | 217 | - `Stick` 定義一覧 218 | 219 | ``` 220 | Stick::MIN 221 | Stick::NEUTRAL 222 | Stick::MAX 223 | ``` 224 | 225 | ### スティックぐるぐる 226 | 227 | - 左スティックをぐるぐるするコマンド 228 | 229 | - `spinLeftStick(int spin_time, uint8_t speed = 5, bool direction = 1);` 230 | 231 | - spin_time: ぐるぐるさせる時間(1 回転に満たない端数の時間が生じた場合は切り捨てとなります) 232 | - speed: 1 秒あたりの回転数 233 | - direction: 方向(1: 時計回り, 0:反時計回り) 234 | 235 | - 使用例 236 | 237 | ``` 238 | spinLeftStick(10000); // 10秒間左スティックを時計回りで、1秒に5回ぐるぐるする 239 | spinLeftStick(30000, 1); // 30秒間左スティックを時計回りで、1秒に1回ぐるぐるする 240 | spinLeftStick(25000, 3, 0); // 25秒間左スティックを反時計回りで、1秒に3回ぐるぐるする 241 | ``` 242 | 243 | - 右スティックをぐるぐるするコマンド 244 | 245 | - `spinRightStick(int spin_time, uint8_t speed = 5, bool direction = 1);` 246 | 247 | - spin_time: ぐるぐるさせる時間(1 回転に満たない端数の時間が生じた場合は切り捨てとなります) 248 | - speed: 1 秒あたりの回転数 249 | - direction: 方向(1: 時計回り, 0:反時計回り) 250 | 251 | - 使用例 252 | 253 | ``` 254 | spinRightStick(5000); // 5秒間右スティックを時計回りで、1秒に5回ぐるぐるする 255 | spinRightStick(9000, 10, 0); // 9秒間右スティックを反時計回りで、1秒に10回ぐるぐるする 256 | spinRightStick(3000, 4, 1); // 3秒間右スティックを時計回りで、1秒に4回ぐるぐるする 257 | ``` 258 | 259 | ### SwitchControlLibrary を使ったその他のコマンド 260 | 261 | このライブラリは SwitchControlLibrary のコマンドも内蔵しているため、合わせて使用することもできます。(**v2 系を採用しています。v1 系とは互換性がないことに注意してください**) 262 | 263 | 上記のもので対応できないものがある場合には、活用してみるといいかもしれません。 264 | 265 | サンプルとして、ポケモン剣盾でバックアップデータの読み込みを行うコマンドを用意してみました。 266 | 267 | ``` 268 | SwitchControlLibrary().pressButton(Button::B); 269 | SwitchControlLibrary().pressButton(Button::X); 270 | SwitchControlLibrary().pressHatButton(Hat::UP); // ※SwitchControlLibraryと異なり、moveHatは使えません。 pressHatButtonに統合されています。 271 | SwitchControlLibrary().sendReport(); // B、X、↑ボタンが同時に送信される 272 | delay(100); 273 | SwitchControlLibrary().releaseButton(Button::B); 274 | SwitchControlLibrary().releaseButton(Button::X); 275 | SwitchControlLibrary().releaseHatButton(); // ※SwitchControlLibraryと異なり、引数は指定しません。(十字キーをニュートラルポジションに戻す処理となる) 276 | SwitchControlLibrary().sendReport(); // B、X、↑ボタンを同時に離す 277 | ``` 278 | 279 | ## 🎁 さいごに 280 | 281 | このライブラリは暫定的なものなので、要望や改善案、追加してほしい機能などありましたら、[Issues](https://github.com/lefmarna/NintendoSwitchControlLibrary/issues)から気軽に投げかけてくださいませ。 282 | 283 | 画像認識のような高度なものを作るのは難しいかもしれませんが、入力プログラムの応用の範囲でしたら対応できるかと思います。 284 | 285 | ## ©️ ライセンス 286 | 287 | [MIT](https://github.com/lefmarna/NintendoSwitchControlLibrary/blob/master/LICENSE) 288 | -------------------------------------------------------------------------------- /examples/Pokemon_BDSP/auto-hatch-eggs/auto-hatch-eggs.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 育て屋から卵を回収→孵化→ボックスに預けるを繰り返すスケッチ 3 | * ボックスに空きがある限り、ポケモンを孵化し続ける 4 | * 5 | * 初期条件は以下の通り 6 | * 1.ズイタウンにいること 7 | * 2.ショートカットに自転車のみが登録された状態であること(+ボタンで自転車に乗れること) 8 | * 3.自転車を4速にしておくこと 9 | * 4.手持ちが「ほのおのからだ」の特性持ちの1体のみのこと 10 | * 5.「まるいおまもり」を所持していること 11 | * 6.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること 12 | * 7.空のボックスが続いた状態であること 13 | * 8.無線のコントローラーが接続されていないこと 14 | * 9.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 15 | * 10. ズイタウン周辺のトレーナーを全員倒しておくこと 16 | */ 17 | 18 | // ライブラリを読み込むためのコード 19 | #include 20 | 21 | // 孵化サイクルを設定する 22 | const int EGG_CYCLE = 40; 23 | 24 | // 孵化するまでに自転車で走り回る時間を計算する(試行錯誤の末にこのような形となったが、まだ練りきれていないところがある) 25 | int calcTimeToHatchingSec() { 26 | // 孵化サイクル35では計算が合わなかったため、個別に指定している 27 | if (EGG_CYCLE == 35) return 345; 28 | 29 | return (EGG_CYCLE * 10) - 10; 30 | } 31 | 32 | // 孵化するまでに自転車で走り回る時間 33 | const int TIME_TO_HATCHING_SEC = calcTimeToHatchingSec(); 34 | 35 | // 空飛ぶでズイタウンに移動する関数 36 | void moveToInitialPlayerPosition() { 37 | pushButton(Button::A, 2000); 38 | pushButton(Button::A, 1000, 2); 39 | delay(7000); 40 | } 41 | 42 | // 初期位置から育て屋さんに移動しタマゴを受け取る関数 43 | void getEggFromBreeder() { 44 | // 初期位置(ズイタウンのポケモンセンター)から育て屋さんのところまで移動 45 | tiltLeftStick(Stick::MIN, Stick::NEUTRAL, 735); 46 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 1250); 47 | tiltLeftStick(Stick::MIN, Stick::NEUTRAL, 735); 48 | // 育て屋さんから卵をもらう 49 | pushButton(Button::A, 500); 50 | pushButton(Button::B, 500, 2); 51 | pushButton(Button::A, 500, 2); 52 | pushButton(Button::B, 500, 2); 53 | pushButton(Button::A, 500); 54 | pushButton(Button::B, 500, 10); 55 | } 56 | 57 | // 初期位置(ズイタウンのポケモンセンター)からタマゴが孵化するまで走り回る関数 58 | void runAround(int run_time_sec) { 59 | tiltLeftStick(Stick::MIN, Stick::NEUTRAL, 560); 60 | pushButton(Button::PLUS, 600); 61 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 5900); 62 | // 孵化サイクル分の走行(チェック周期を考慮して-1からスタート) 63 | for (int i = -1; i < run_time_sec / 21; i++) { 64 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, 10400); 65 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 10400); 66 | } 67 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, (run_time_sec % 21) * 1000); 68 | } 69 | 70 | // タマゴが孵化するのを待つ関数 71 | void waitEggHatching() { 72 | pushButton(Button::A, 500, 30); 73 | delay(4000); 74 | } 75 | 76 | // 孵化した手持ちのポケモンをボックスに預ける関数 77 | // box_line : 何列目にポケモンを預けるか 78 | void sendHatchedPokemonToBox(int box_line) { 79 | // ボックスを開く 80 | pushButton(Button::X, 500); 81 | pushHat(Hat::RIGHT, 50); 82 | pushButton(Button::A, 1250); 83 | pushButton(Button::R, 1500); 84 | // 手持ちの孵化したポケモンを範囲選択 85 | pushHat(Hat::LEFT, 50); 86 | pushHat(Hat::DOWN, 50); 87 | pushButton(Button::Y, 50); 88 | pushButton(Button::Y, 50); 89 | pushButton(Button::A, 50); 90 | holdHat(Hat::DOWN, 1200); 91 | pushButton(Button::A, 50); 92 | // ボックスに移動させる 93 | pushHat(Hat::RIGHT, 100, box_line + 1); 94 | pushHat(Hat::UP, 50); 95 | pushButton(Button::A, 50); 96 | // ボックスがいっぱいになったら、次のボックスに移動させる 97 | if (box_line == 5) { 98 | pushHat(Hat::UP, 50); 99 | pushHat(Hat::RIGHT, 500); 100 | } 101 | // ボックスを閉じる 102 | pushButton(Button::B, 50); // ボックスが空でなかった場合でも、ボックスを閉じてループを実行し続けさせるのに必要な記述 103 | pushButton(Button::B, 1500); 104 | pushButton(Button::B, 1250); 105 | // メニュー画面のカーソルをタウンマップに戻す 106 | pushHat(Hat::LEFT, 50); 107 | } 108 | 109 | // 実際にループ内で呼び出す関数 110 | void receiveAndHatchEggs(int box_line) { 111 | // 手持ちが1体の状態から、卵受け取り→孵化を繰り返していく 112 | for (int egg_num = 0; egg_num < 5; egg_num++) { 113 | moveToInitialPlayerPosition(); 114 | getEggFromBreeder(); 115 | pushButton(Button::X, 500); 116 | moveToInitialPlayerPosition(); 117 | runAround(TIME_TO_HATCHING_SEC); 118 | waitEggHatching(); 119 | // 「そらをとぶ」を使う前に、ズイタウンにいることを確定させる 120 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 10400); 121 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, 4800); 122 | // 手持ちがいっぱいになったときの処理 123 | if (egg_num == 4) { 124 | // ボックスに預ける処理を呼び出す 125 | sendHatchedPokemonToBox(box_line); 126 | // 手持ちがいっぱいでない場合は、メニューを開いてからループに戻る 127 | } else { 128 | pushButton(Button::X, 500); 129 | } 130 | } 131 | } 132 | 133 | // マイコンのセット時に1度だけ行われる処理 134 | void setup() { 135 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 136 | pushButton(Button::L, 500, 5); 137 | 138 | // マイコンを認識したら、メニューの左上にカーソルを持っていく 139 | pushButton(Button::X, 750); 140 | holdHat(Hat::UP_LEFT, 1500); 141 | 142 | // 「そらをとぶ」を使うことで、位置情報をリセットする 143 | moveToInitialPlayerPosition(); 144 | 145 | // 初めのタマゴが出現するまで走り回る 146 | tiltLeftStick(Stick::MIN, Stick::NEUTRAL, 560); 147 | pushButton(Button::PLUS, 600); 148 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 5900); 149 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, 10400); 150 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 10400); 151 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, 4800); 152 | 153 | // メニューを開く動作をループに含めてしまうと、毎回メニューを閉じないといけなくなってしまうため、ループから外すことにした 154 | pushButton(Button::X, 500); 155 | } 156 | 157 | // ここに記述した内容がループされ続ける 158 | void loop() { 159 | for (int box_line = 0; box_line < 6; box_line++) { 160 | receiveAndHatchEggs(box_line); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /examples/Pokemon_BDSP/auto-release-pokemons/auto-release-pokemons.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 指定された数のボックスに存在するポケモンをすべて逃がし、空の状態にするスケッチ 3 | * 4 | * 18行目の "const int BOX_COUNT = 2;" の箇所に、空にしたいボックス数を指定した状態(必ず半角数値で入力してください)で使用してください。 5 | * 【例:"const int BOX_COUNT = 5;" と指定すると、5ボックス分のポケモンを逃がすコードになる】 6 | * 7 | * 初期条件は以下の通り 8 | * 1.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること 9 | * 2.30匹フルにポケモンが預けられたボックスが続いた状態であること。(タマゴなど逃がせないポケモンが混じった状態はNG) 10 | * 3.無線のコントローラーが接続されていないこと 11 | * 4.「設定」から「話の速さ」を「速い」にしておくこと 12 | */ 13 | 14 | // ライブラリを読み込むためのコード 15 | #include 16 | 17 | // 何ボックス分逃がすかをここで指定する 18 | const int BOX_COUNT = 2; 19 | 20 | // ボタンを押した際の猶予時間 21 | const int PUSH_BUTTON_DELAY = 500; 22 | const int PUSH_HAT_DELAY = 50; 23 | 24 | // ポケモンを逃がす関数 25 | void releasePokemon() { 26 | // 「にがす」を選択 27 | pushButton(Button::A, PUSH_BUTTON_DELAY); 28 | pushHat(Hat::UP, PUSH_HAT_DELAY, 2); 29 | pushButton(Button::A, PUSH_BUTTON_DELAY); 30 | pushHat(Hat::UP, PUSH_HAT_DELAY); 31 | 32 | // 「本当に 逃がしますか?」 33 | pushButton(Button::A, 1000); 34 | pushButton(Button::A, PUSH_BUTTON_DELAY); 35 | } 36 | 37 | // 1ボックス分(30匹)ポケモンを逃がす関数 38 | void releaseBox() { 39 | // 現在のボックスの列(左に移動するか、右に移動するかの判別に使用する) 40 | int boxline = 1; 41 | 42 | for (int i = 1; i <= 30; i++) { 43 | // ポケモンを逃がす 44 | releasePokemon(); 45 | // 次のポケモンにカーソルを合わせる 46 | if (i % 6 == 0) { 47 | pushHat(Hat::DOWN, PUSH_HAT_DELAY); 48 | boxline++; 49 | } else if (boxline % 2 == 1) { 50 | pushHat(Hat::RIGHT, PUSH_HAT_DELAY); 51 | } else { 52 | pushHat(Hat::LEFT, PUSH_HAT_DELAY); 53 | } 54 | } 55 | 56 | // 次のボックスに移動する 57 | pushButton(Button::R, PUSH_BUTTON_DELAY); 58 | pushHat(Hat::DOWN, PUSH_HAT_DELAY, 2); 59 | pushHat(Hat::RIGHT, 500, 2); 60 | } 61 | 62 | void setup() { 63 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 64 | pushButton(Button::L, PUSH_BUTTON_DELAY, 5); 65 | 66 | // マイコンを認識したら、メニューの左上にカーソルを持っていく 67 | pushButton(Button::X, 750); 68 | holdHat(Hat::UP_LEFT, 1500); 69 | 70 | // ボックスを開く 71 | pushHat(Hat::RIGHT, PUSH_HAT_DELAY); 72 | pushButton(Button::A, 1250); 73 | pushButton(Button::R, 2500); 74 | } 75 | 76 | int loopCount = 0; 77 | void loop() { 78 | // 指定されたボックス分のポケモンを逃し終えたら処理を終了する 79 | if (loopCount == BOX_COUNT) exit(0); 80 | 81 | releaseBox(); 82 | loopCount++; 83 | } 84 | -------------------------------------------------------------------------------- /examples/Pokemon_Legends_Arceus/auto-level-up/auto-level-up.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 訓練場で警備隊のタキとの連戦を行い、レベル上げと早業・力業のタスクを埋めていくスケッチ 3 | * 4 | * ※2匹のポケモンが倒される or PP切れで技が使えなくなるとループが止まってしまうので注意! 5 | * 6 | * 7 | * 初期条件は以下の通り 8 | * 1.ストーリークリア済であること(クリア前でも環境が揃っていれば可能かと思いますが、動作は未検証です) 9 | * 2.コトブキムラ訓練場前のノボリの前にいること 10 | * 3.手持ちの1匹目に強力なポケモンを配置し、初手のポケモンは別のポケモンであること 11 | * 4.2匹のポケモンそれぞれの一番上の技に使用する技を配置しておくこと 12 | * 5.無線のコントローラーが接続されていないこと 13 | * 6.「設定」から「話の速さ」を「速い」にしておくこと 14 | */ 15 | 16 | // ライブラリを読み込むためのコード 17 | #include 18 | 19 | // 早業・力業のパターンを決める(0: ランダム, 1: 早業のみ, 2: 力業のみ) 20 | const int PATTERN = 0; 21 | 22 | // ボタン入力の間隔(個人で調整してOK。早すぎると早業・力業の切り替えができないことがある) 23 | const int INTERVAL = 400; 24 | 25 | // PATTERNの値を元に打ちこむコマンドを決める 26 | int hats[2]; 27 | void decideCommands() { 28 | switch (PATTERN) { 29 | // 早業のみ 30 | case 1: 31 | hats[0] = Hat::LEFT; 32 | hats[1] = Hat::LEFT; 33 | break; 34 | 35 | // 力業のみ 36 | case 2: 37 | hats[0] = Hat::RIGHT; 38 | hats[1] = Hat::LEFT; /* NOTE ポケモン交換時に右入力すると技を選択してしまうことがあるため、脱却するために力業のみの場合も左入力が必要 */ 39 | break; 40 | 41 | // ランダム 42 | default: 43 | hats[0] = Hat::LEFT; 44 | hats[1] = Hat::RIGHT; 45 | } 46 | } 47 | 48 | // マイコンのセット時に1度だけ行われる処理 49 | void setup() { 50 | // ループ内で打ち込むコマンドを反映する(Switchの操作に関わらないため、認識前でも問題なく動作する) 51 | decideCommands(); 52 | 53 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 54 | pushHat(Hat::LEFT, 500, 5); 55 | } 56 | 57 | // ここに記述した内容がループされ続ける 58 | void loop() { 59 | pushButton(Button::A, INTERVAL); 60 | pushHat(hats[0], INTERVAL); 61 | pushButton(Button::A, INTERVAL); 62 | pushHat(hats[1], INTERVAL); 63 | 64 | // 2番(力業のみ)を選択したときは、早業経由で力業を選択する 65 | if (PATTERN == 2) { 66 | pushHat(Hat::LEFT, INTERVAL); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/auto-gain-watt/auto-gain-watt.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 巣穴からワットを回収し続けるスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.願いのかたまりを投げ入れた巣穴の前にいること 6 | * 2.巣穴のワットは回収済みであること 7 | * 3.インターネットで時間をあわせるがOFFになっていること 8 | * 4.オフライン状態であること 9 | * 5.無線のコントローラーが接続されていないこと 10 | * 6.「設定」から「話の速さ」を「速い」にしておくこと 11 | * 7.モンスターボールを1つ以上所持していること 12 | * 8.ちょいらくモードが「しない」であること 13 | */ 14 | 15 | // ライブラリを読み込むためのコード 16 | #include 17 | 18 | // Nintendo Switchのシステムバージョンを設定する 19 | const int SWITCH_SYSTEM_VERSION = 13; 20 | 21 | // Nintendo Switch Liteの場合はtrueを設定する 22 | const bool IS_SWITCH_LITE = false; 23 | 24 | // ホーム画面にSwitchのVer11から登場した Nintendo Switch Onlineのメニューが存在するか 25 | bool hasNintendoSwitchOnlineMenu(int systemVersion) { 26 | return systemVersion >= 11; 27 | } 28 | 29 | // 設定 > 本体 に ドックの更新 メニューが存在するか 30 | bool hasDockUpdateMenu(int systemVersion, bool isSwitchLite) { 31 | if (isSwitchLite) { 32 | return false; 33 | } else { 34 | return systemVersion >= 13; 35 | } 36 | } 37 | 38 | // ワットを回収するシーケンス 39 | void execWattGainSequence() { 40 | // 募集開始 41 | pushButton(Button::A, 3000); 42 | // ホーム画面 > 設定 43 | pushButton(Button::HOME, 500); 44 | pushHat(Hat::DOWN, 25); 45 | if (hasNintendoSwitchOnlineMenu(SWITCH_SYSTEM_VERSION)) { 46 | pushHat(Hat::RIGHT, 25, 5); 47 | } else { 48 | pushHat(Hat::RIGHT, 25, 4); 49 | } 50 | pushButton(Button::A, 100); 51 | // 設定 > 本体 > 日付と時刻 52 | holdHat(Hat::DOWN, 2000); 53 | pushHat(Hat::RIGHT, 25); 54 | if (hasDockUpdateMenu(SWITCH_SYSTEM_VERSION, IS_SWITCH_LITE)) { 55 | pushHat(Hat::DOWN, 25, 9); 56 | } else { 57 | pushHat(Hat::DOWN, 25, 4); 58 | } 59 | pushButton(Button::A, 200); 60 | // 日付と時刻 > 現在の日付と時刻 61 | pushHat(Hat::DOWN, 25, 2); 62 | pushButton(Button::A, 500); 63 | pushHat(Hat::RIGHT, 25, 2); 64 | pushHat(Hat::UP, 25); 65 | pushHat(Hat::RIGHT, 25, 3); 66 | pushButton(Button::A, 50); 67 | // ホーム画面 > ゲーム画面 68 | pushButton(Button::HOME, 600); 69 | pushButton(Button::A, 600); 70 | // レイド募集中止 71 | pushButton(Button::B, 1000); 72 | pushButton(Button::A, 6000); 73 | // ワット回収 74 | pushButton(Button::A, 1000); 75 | pushButton(Button::B, 1000); // ここをBにすることで、月が変わった際にキャンセルできず詰んでしまう問題をスマートに解決できる 76 | pushButton(Button::A, 1000); 77 | } 78 | 79 | // マイコンのセット時に1度だけ行われる処理 80 | void setup() { 81 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 82 | pushButton(Button::B, 500, 5); 83 | // 巣穴をチェックする 84 | pushButton(Button::A, 1000); 85 | } 86 | 87 | // ここに記述した内容がループされ続ける 88 | void loop() { 89 | execWattGainSequence(); 90 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/auto-hatch-eggs/auto-hatch-eggs.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 育て屋から卵を回収→孵化→ボックスに預けるを繰り返すスケッチ 3 | * ボックスに空きがある限り、ポケモンを孵化し続ける 4 | * 5 | * 初期条件は以下の通り 6 | * 1.ハシノマはらっぱにいること 7 | * 2.自転車に乗っていること 8 | * 3.手持ちが1体のみのこと 9 | * 4.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること 10 | * 5.ボックスが空のこと 11 | * 6.オフライン状態であること 12 | * 7.無線のコントローラーが接続されていないこと 13 | * 8.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 14 | * 9.ちょいらくモードが「しない」であること 15 | * 10.まるいおまもりを所持していること 16 | */ 17 | 18 | // ライブラリを読み込むためのコード 19 | #include 20 | 21 | // 孵化するまでに自転車で走り回る時間 22 | const int TIME_TO_HATCHING_SEC = 70; // 完成された値 23 | 24 | // 空飛ぶタクシーでハシノマはらっぱに移動する関数 25 | void moveToInitialPlayerPosition() { 26 | pushButton(Button::A, 2000); 27 | pushButton(Button::A, 450, 2); 28 | delay(2200); // 天候によって読み込み時間がやや異なる(最も重かった砂嵐でも1900で安定していたが、柱の本数や服装などの環境による差異がある可能性も考慮して少し余裕を持たせた) 29 | } 30 | 31 | // 初期位置から育て屋さんに移動しタマゴを受け取る関数 32 | void getEggFromBreeder() { 33 | // 初期位置(ハシノマはらっぱ)から育て屋さんのところまで移動 34 | pushButton(Button::PLUS, 600); 35 | tiltRightStick(Stick::MAX, Stick::NEUTRAL, 2000); 36 | tiltLeftStick(166, Stick::MIN, 800); 37 | pushButton(Button::PLUS, 450); 38 | // 育て屋さんから卵をもらう 39 | pushButton(Button::A, 450, 3); 40 | delay(750); 41 | pushButton(Button::B, 450, 10); 42 | delay(50); 43 | } 44 | 45 | // 初期位置(ハシノマはらっぱ)からぐるぐる走り回る関数 46 | void runAround(int run_time_sec) { 47 | // delayの秒数がintの最大値を越えないように30秒ごとに実行する 48 | for (int i = 0; i < run_time_sec / 30; i++) { 49 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, 30000); 50 | } 51 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, (run_time_sec % 30) * 1000); 52 | } 53 | 54 | // タマゴが孵化するのを待つ関数 55 | void waitEggHatching() { 56 | pushButton(Button::B, 450, 38); // 余裕があるように思えるが、色違いのエフェクトを考慮するとこれ以上は厳しい 57 | } 58 | 59 | // 孵化した手持ちのポケモンをボックスに預ける関数 60 | // box_line : 何列目にポケモンを預けるか 61 | void sendHatchedPokemonToBox(int box_line) { 62 | // ボックスを開く 63 | pushButton(Button::X, 500); 64 | pushHat(Hat::RIGHT, 25); 65 | pushButton(Button::A, 1250); 66 | pushButton(Button::R, 1500); 67 | // 手持ちの孵化したポケモンを範囲選択 68 | pushHat(Hat::LEFT, 25); 69 | pushHat(Hat::DOWN, 25); 70 | pushButton(Button::Y, 25); 71 | pushButton(Button::Y, 25); 72 | pushButton(Button::A, 25); 73 | holdHat(Hat::DOWN, 600); 74 | pushButton(Button::A, 25); 75 | // ボックスに移動させる 76 | pushHat(Hat::RIGHT, 100, box_line + 1); 77 | pushHat(Hat::UP, 25); 78 | pushButton(Button::A, 25); 79 | // ボックスがいっぱいになったら、次のボックスに移動させる 80 | if (box_line == 5) { 81 | pushHat(Hat::UP, 25); 82 | pushHat(Hat::RIGHT, 25); 83 | } 84 | // ボックスを閉じる 85 | pushButton(Button::B, 25); // ボックスが空でなかった場合でも、ボックスを閉じてループを実行し続けさせるのに必要な記述 86 | pushButton(Button::B, 1500); 87 | pushButton(Button::B, 1250); 88 | // メニュー画面のカーソルをタウンマップに戻す 89 | pushHat(Hat::LEFT, 25); 90 | } 91 | 92 | // 実際にループ内で呼び出す関数 93 | void receiveAndHatchEggs(int box_line) { 94 | // 手持ちが1体の状態から、卵受け取り→孵化を繰り返していく 95 | for (int egg_num = 0; egg_num < 5; egg_num++) { 96 | moveToInitialPlayerPosition(); 97 | getEggFromBreeder(); 98 | pushButton(Button::X, 500); 99 | moveToInitialPlayerPosition(); 100 | // 野生ポケモンとのエンカウントを避けるため初期位置から少し移動する 101 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 102 | runAround(TIME_TO_HATCHING_SEC); 103 | waitEggHatching(); 104 | 105 | // 手持ちがいっぱいになったときの処理 106 | if (egg_num == 4) { 107 | // 孵化歩数の多いポケモンも孵化させてから預けるためのコード(下2行を無効にすると回転は上がるので、好みで削除すると良い) 108 | runAround(60); 109 | waitEggHatching(); 110 | // ボックスに預ける処理を呼び出す 111 | sendHatchedPokemonToBox(box_line); 112 | 113 | // 手持ちがいっぱいでない場合は、メニューを開いてからループに戻る 114 | } else { 115 | pushButton(Button::X, 500); 116 | } 117 | } 118 | } 119 | 120 | // マイコンのセット時に1度だけ行われる処理 121 | void setup() { 122 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 123 | pushButton(Button::B, 500, 5); 124 | 125 | // マイコンを認識したら、メニューの左上にカーソルを持っていく 126 | pushButton(Button::X, 600); 127 | holdHat(Hat::UP_LEFT, 750); 128 | 129 | // 空飛ぶを使うことで、位置情報をリセットする 130 | moveToInitialPlayerPosition(); 131 | 132 | // 初めのタマゴが出現するまで走り回る 133 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 134 | runAround(25); 135 | 136 | // メニューを開く動作をループに含めてしまうと、毎回メニューを閉じないといけなくなってしまうため、ループから外すことにした 137 | pushButton(Button::X, 500); 138 | } 139 | 140 | // ここに記述した内容がループされ続ける 141 | void loop() { 142 | for (int box_line = 0; box_line < 6; box_line++) { 143 | receiveAndHatchEggs(box_line); 144 | } 145 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/auto-hatch-eggs_shiny/auto-hatch-eggs_shiny.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 育て屋から卵を回収→孵化→ボックスに預けるを繰り返すスケッチ 3 | * ボックスに空きがある限り、ポケモンを孵化し続ける 4 | * 5 | * 初期条件は以下の通り 6 | * 1.ハシノマはらっぱにいること 7 | * 2.自転車に乗っていること 8 | * 3.手持ちが1体のみのこと 9 | * 4.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること 10 | * 5.ボックスが空のこと 11 | * 6.オフライン状態であること 12 | * 7.無線のコントローラーが接続されていないこと 13 | * 8.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 14 | * 9.ちょいらくモードが「しない」であること 15 | * 10.まるいおまもりを所持していること 16 | * 17 | * コード25行目の以下の箇所に孵化するポケモンの孵化サイクルを入れること 18 | * const int EGG_CYCLE = 25; 19 | */ 20 | 21 | // ライブラリを読み込むためのコード 22 | #include 23 | 24 | // 孵化サイクルを設定する 25 | const int EGG_CYCLE = 25; 26 | 27 | // 孵化するまでに自転車で走り回る時間 28 | const int TIME_TO_HATCHING_SEC = EGG_CYCLE * 32 / 10 + 5; 29 | 30 | // 空飛ぶタクシーでハシノマはらっぱに移動する関数 31 | void moveToInitialPlayerPosition() { 32 | pushButton(Button::A, 2000); 33 | pushButton(Button::A, 450, 2); 34 | delay(2200); // 天候によって読み込み時間がやや異なる(最も重かった砂嵐でも1900で安定していたが、柱の本数や服装などの環境による差異がある可能性も考慮して少し余裕を持たせた) 35 | } 36 | 37 | // 初期位置から育て屋さんに移動しタマゴを受け取る関数 38 | void getEggFromBreeder() { 39 | // 初期位置(ハシノマはらっぱ)から育て屋さんのところまで移動 40 | pushButton(Button::PLUS, 600); 41 | tiltRightStick(Stick::MAX, Stick::NEUTRAL, 2000); 42 | tiltLeftStick(166, Stick::MIN, 800); 43 | pushButton(Button::PLUS, 450); 44 | // 育て屋さんから卵をもらう 45 | pushButton(Button::A, 450, 3); 46 | delay(750); 47 | pushButton(Button::B, 450, 10); 48 | delay(50); 49 | } 50 | 51 | // 初期位置(ハシノマはらっぱ)からぐるぐる走り回る関数 52 | void runAround(int run_time_sec) { 53 | // delayの秒数がintの最大値を越えないように30秒ごとに実行する 54 | for (int i = 0; i < run_time_sec / 30; i++) { 55 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, 30000); 56 | } 57 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, (run_time_sec % 30) * 1000); 58 | } 59 | 60 | // タマゴが孵化するのを待つ関数 61 | void waitEggHatching() { 62 | pushButton(Button::B, 450, 38); // 余裕があるように思えるが、色違いのエフェクトを考慮するとこれ以上は厳しい 63 | } 64 | 65 | // 孵化した手持ちのポケモンをボックスに預ける関数 66 | // box_line : 何列目にポケモンを預けるか 67 | void sendHatchedPokemonToBox(int box_line) { 68 | // ボックスを開く 69 | pushButton(Button::X, 500); 70 | pushHat(Hat::RIGHT, 25); 71 | pushButton(Button::A, 1250); 72 | pushButton(Button::R, 1500); 73 | // 手持ちの孵化したポケモンを範囲選択 74 | pushHat(Hat::LEFT, 25); 75 | pushHat(Hat::DOWN, 25); 76 | pushButton(Button::Y, 25); 77 | pushButton(Button::Y, 25); 78 | pushButton(Button::A, 25); 79 | holdHat(Hat::DOWN, 600); 80 | pushButton(Button::A, 25); 81 | // ボックスに移動させる 82 | pushHat(Hat::RIGHT, 100, box_line + 1); 83 | pushHat(Hat::UP, 25); 84 | pushButton(Button::A, 25); 85 | // ボックスがいっぱいになったら、次のボックスに移動させる 86 | if (box_line == 5) { 87 | pushHat(Hat::UP, 25); 88 | pushHat(Hat::RIGHT, 25); 89 | } 90 | // ボックスを閉じる 91 | pushButton(Button::B, 25); // ボックスが空でなかった場合でも、ボックスを閉じてループを実行し続けさせるのに必要な記述 92 | pushButton(Button::B, 1500); 93 | pushButton(Button::B, 1250); 94 | // メニュー画面のカーソルをタウンマップに戻す 95 | pushHat(Hat::LEFT, 25); 96 | } 97 | 98 | // 実際にループ内で呼び出す関数 99 | void receiveAndHatchEggs(int box_line) { 100 | // 手持ちが1体の状態から、卵受け取り→孵化を繰り返していく 101 | for (int egg_num = 0; egg_num < 5; egg_num++) { 102 | moveToInitialPlayerPosition(); 103 | getEggFromBreeder(); 104 | pushButton(Button::X, 500); 105 | moveToInitialPlayerPosition(); 106 | // 野生ポケモンとのエンカウントを避けるため初期位置から少し移動する 107 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 108 | runAround(TIME_TO_HATCHING_SEC); 109 | waitEggHatching(); 110 | 111 | // 手持ちがいっぱいになったときの処理 112 | if (egg_num == 4) { 113 | // ボックスに預ける処理を呼び出す 114 | sendHatchedPokemonToBox(box_line); 115 | // 手持ちがいっぱいでない場合は、メニューを開いてからループに戻る 116 | } else { 117 | pushButton(Button::X, 500); 118 | } 119 | } 120 | } 121 | 122 | // マイコンのセット時に1度だけ行われる処理 123 | void setup() { 124 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 125 | pushButton(Button::B, 500, 5); 126 | 127 | // マイコンを認識したら、メニューの左上にカーソルを持っていく 128 | pushButton(Button::X, 600); 129 | holdHat(Hat::UP_LEFT, 750); 130 | 131 | // 空飛ぶを使うことで、位置情報をリセットする 132 | moveToInitialPlayerPosition(); 133 | 134 | // 初めのタマゴが出現するまで走り回る 135 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 136 | runAround(25); 137 | 138 | // メニューを開く動作をループに含めてしまうと、毎回メニューを閉じないといけなくなってしまうため、ループから外すことにした 139 | pushButton(Button::X, 500); 140 | } 141 | 142 | // ここに記述した内容がループされ続ける 143 | void loop() { 144 | for (int box_line = 0; box_line < 6; box_line++) { 145 | receiveAndHatchEggs(box_line); 146 | } 147 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/auto-receive-eggs/auto-receive-eggs.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * 孵化はせずにタマゴだけをひたすら受け取っていくスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.ハシノマはらっぱにいること 6 | * 2.自転車に乗っていること 7 | * 3.手持ち6匹全てがポケモンで埋まっていること 8 | * 4.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること 9 | * 5.オフライン状態であること 10 | * 6.無線のコントローラーが接続されていないこと 11 | * 7.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 12 | * 8.ちょいらくモードが「しない」であること 13 | * 9.まるいおまもりを所持していること 14 | */ 15 | 16 | // ライブラリを読み込むためのコード 17 | #include 18 | 19 | // タマゴを受け取るまでの間隔(数値が大きいほど間隔が長くなる) 20 | const int INTERVAL = 15; 21 | 22 | // 空飛ぶタクシーでハシノマはらっぱに移動する関数 23 | void moveToInitialPlayerPosition() { 24 | pushButton(Button::A, 2000); 25 | pushButton(Button::A, 450, 2); 26 | delay(2200); // 天候によって読み込み時間がやや異なる(最も重かった砂嵐でも1900で安定していたが、柱の本数や服装などの環境による差異がある可能性も考慮して少し余裕を持たせた) 27 | } 28 | 29 | // 初期位置から育て屋さんに移動しタマゴを受け取る関数 30 | void getEggFromBreeder() { 31 | // 初期位置(ハシノマはらっぱ)から育て屋さんのところまで移動 32 | pushButton(Button::PLUS, 600); 33 | tiltRightStick(Stick::MAX, Stick::NEUTRAL, 2000); 34 | tiltLeftStick(166, Stick::MIN, 800); 35 | pushButton(Button::PLUS, 450); 36 | // 育て屋さんから卵をもらう 37 | pushButton(Button::A, 450, 3); 38 | delay(750); 39 | pushButton(Button::B, 450, 10); 40 | delay(50); 41 | } 42 | 43 | // 初期位置(ハシノマはらっぱ)からぐるぐる走り回る関数 44 | void runAround(int run_time_sec) { 45 | // delayの秒数がintの最大値を越えないように30秒ごとに実行する 46 | for (int i = 0; i < run_time_sec / 30; i++) { 47 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, 30000); 48 | } 49 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, (run_time_sec % 30) * 1000); 50 | } 51 | 52 | // 実際にループ内で呼び出す関数 53 | void receiveEggs(int box_line) { 54 | // 手持ちが1体の状態から、卵受け取り→孵化を繰り返していく 55 | for (int egg_num = 0; egg_num < 5; egg_num++) { 56 | moveToInitialPlayerPosition(); 57 | getEggFromBreeder(); 58 | pushButton(Button::X, 500); 59 | moveToInitialPlayerPosition(); 60 | // 野生ポケモンとのエンカウントを避けるため初期位置から少し移動する 61 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 62 | runAround(INTERVAL); 63 | pushButton(Button::X, 500); 64 | } 65 | } 66 | 67 | // マイコンのセット時に1度だけ行われる処理 68 | void setup() { 69 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 70 | pushButton(Button::B, 500, 5); 71 | 72 | // マイコンを認識したら、メニューの左上にカーソルを持っていく 73 | pushButton(Button::X, 600); 74 | holdHat(Hat::UP_LEFT, 750); 75 | 76 | // 空飛ぶを使うことで、位置情報をリセットする 77 | moveToInitialPlayerPosition(); 78 | 79 | // 初めのタマゴが出現するまで走り回る 80 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 81 | runAround(INTERVAL); 82 | 83 | // メニューを開く動作をループに含めてしまうと、毎回メニューを閉じないといけなくなってしまうため、ループから外すことにした 84 | pushButton(Button::X, 500); 85 | } 86 | 87 | // ここに記述した内容がループされ続ける 88 | void loop() { 89 | for (int box_line = 0; box_line < 6; box_line++) { 90 | receiveEggs(box_line); 91 | } 92 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/battle-tower-automation/battle-tower-automation.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * バトルタワーでのBP稼ぎを自動化するスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.バトルタワーの受付の前で待機していること 6 | * 2.レンタルチームに 0000 0003 M4XW JG をレンタルしておくこと 7 | * 3.上記のチームがバトルチーム選択で最初に来るようにすること 8 | * 4.無線のコントローラーが接続されていないこと 9 | * 5.「設定」から「話の速さ」を「速い」に、「戦闘アニメ」を「みない」にしておくこと 10 | * 6.ちょいらくモードが「しない」であること 11 | */ 12 | 13 | // ライブラリを読み込むためのコード 14 | #include 15 | 16 | // マイコンのセット時に1度だけ行われる処理 17 | void setup() { 18 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 19 | pushButton(Button::B, 500, 5); 20 | } 21 | 22 | // ここに記述した内容がループされ続ける 23 | void loop() { 24 | pushButton(Button::ZL, 2800); 25 | pushButton(Button::A, 800); 26 | pushButton(Button::A, 800); 27 | pushButton(Button::B, 800); 28 | pushHat(Hat::UP); 29 | pushButton(Button::ZL, 2800); 30 | pushButton(Button::A, 1050); // ここは少し長めにとらないと、参加画面で詰んでしまう 31 | pushButton(Button::ZL, 2800); 32 | pushButton(Button::A, 800); 33 | pushHat(Hat::UP); 34 | pushButton(Button::ZL, 2800); 35 | pushButton(Button::A, 800); 36 | pushHat(Hat::UP); 37 | pushButton(Button::ZL, 3300); 38 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/collect-fossils/collect-fossils.ino: -------------------------------------------------------------------------------- 1 | // ライブラリを読み込むためのコード 2 | #include 3 | 4 | // マイコンのセット時に1度だけ行われる処理 5 | void setup() { 6 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 7 | pushButton(Button::B, 500, 5); 8 | } 9 | 10 | // ここに記述した内容がループされ続ける 11 | void loop() { 12 | pushButton(Button::A, 100); 13 | } 14 | -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/dynamax-adventure/dynamax-adventure.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ダイマックスアドベンチャーを自動周回するスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.エキスパンションパスを購入済みであること 6 | * 2.ダイマックスアドベンチャーの「エンドレスモード」を解放済みであること 7 | * 3.「マックスダイ巣穴」内の清掃員前で待機していること 8 | * 4.オフライン状態であること 9 | * 5.無線のコントローラーが接続されていないこと 10 | * 6.「設定」から「話の速さ」を「速い」に、「戦闘アニメ」を「みない」にしておくこと 11 | * 7.モンスターボールを大量に用意し、ボールの先頭に設定しておくこと 12 | * 8.ちょいらくモードが「しない」であること 13 | */ 14 | 15 | // ライブラリを読み込むためのコード 16 | #include 17 | 18 | // マイコンのセット時に1度だけ行われる処理 19 | void setup() { 20 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 21 | pushButton(Button::B, 500, 5); 22 | } 23 | 24 | // ここに記述した内容がループされ続ける 25 | void loop() { 26 | pushHat(Hat::DOWN, 2000); 27 | pushButton(Button::A, 2000); 28 | pushButton(Button::A, 2000); 29 | pushButton(Button::A, 2000); 30 | pushButton(Button::A, 2000); 31 | pushButton(Button::A, 2000); 32 | delay(1800); 33 | pushHat(Hat::DOWN, 2000); 34 | pushButton(Button::A, 800); 35 | pushHat(Hat::DOWN, 2000); 36 | pushButton(Button::A, 2000); 37 | pushButton(Button::A, 800); 38 | pushHat(Hat::DOWN); 39 | pushButton(Button::A, 1000); 40 | pushButton(Button::A, 1000); 41 | pushButton(Button::B, 2800); 42 | holdButton(Button::B, 1400); 43 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/fossil-pokemons/arctovish/arctovish.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ウオチルドンの受け取りを自動化するスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.無線のコントローラーが接続されていないこと 6 | * 2.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 7 | * 3.ちょいらくモードが「しない」であること 8 | */ 9 | 10 | // ライブラリを読み込むためのコード 11 | #include 12 | 13 | // マイコンのセット時に1度だけ行われる処理 14 | void setup() { 15 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 16 | pushButton(Button::B, 500, 5); 17 | } 18 | 19 | // ここに記述した内容がループされ続ける 20 | void loop() { 21 | pushButton(Button::A, 650, 2); 22 | pushHat(Hat::DOWN, 25); 23 | pushButton(Button::A, 800); 24 | pushHat(Hat::DOWN, 25); 25 | pushButton(Button::A, 800); 26 | pushButton(Button::A, 650, 2); 27 | delay(2350); 28 | pushButton(Button::B, 200, 35); 29 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/fossil-pokemons/arctozolt/arctozolt.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * パッチルドンの受け取りを自動化するスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.無線のコントローラーが接続されていないこと 6 | * 2.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 7 | * 3.ちょいらくモードが「しない」であること 8 | */ 9 | 10 | // ライブラリを読み込むためのコード 11 | #include 12 | 13 | // マイコンのセット時に1度だけ行われる処理 14 | void setup() { 15 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 16 | pushButton(Button::B, 500, 5); 17 | } 18 | 19 | // ここに記述した内容がループされ続ける 20 | void loop() { 21 | pushButton(Button::A, 650, 2); 22 | pushButton(Button::A, 800); 23 | pushHat(Hat::DOWN, 25); 24 | pushButton(Button::A, 800); 25 | pushButton(Button::A, 650, 2); 26 | delay(2350); 27 | pushButton(Button::B, 200, 35); 28 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/fossil-pokemons/dracovish/dracovish.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ウオノラゴンの受け取りを自動化するスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.無線のコントローラーが接続されていないこと 6 | * 2.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 7 | * 3.ちょいらくモードが「しない」であること 8 | */ 9 | 10 | // ライブラリを読み込むためのコード 11 | #include 12 | 13 | // マイコンのセット時に1度だけ行われる処理 14 | void setup() { 15 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 16 | pushButton(Button::B, 500, 5); 17 | } 18 | 19 | // ここに記述した内容がループされ続ける 20 | void loop() { 21 | pushButton(Button::A, 650, 2); 22 | pushHat(Hat::DOWN, 25); 23 | pushButton(Button::A, 800, 2); 24 | pushButton(Button::A, 650, 2); 25 | delay(2350); 26 | pushButton(Button::B, 200, 35); 27 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/fossil-pokemons/dracozolt/dracozolt.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * パッチラゴンの受け取りを自動化するスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.無線のコントローラーが接続されていないこと 6 | * 2.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 7 | * 3.ちょいらくモードが「しない」であること 8 | */ 9 | 10 | // ライブラリを読み込むためのコード 11 | #include 12 | 13 | // マイコンのセット時に1度だけ行われる処理 14 | void setup() { 15 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 16 | pushButton(Button::B, 500, 5); 17 | } 18 | 19 | // ここに記述した内容がループされ続ける 20 | void loop() { 21 | pushButton(Button::A, 100); 22 | } -------------------------------------------------------------------------------- /examples/Pokemon_SWSH/hatch-eggs-in-the-box/hatch-eggs-in-the-box.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ボックスに眠っているタマゴを順に孵化していくスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1.ハシノマはらっぱにいること 6 | * 2.自転車に乗っていること 7 | * 3.手持ちが1体のみのこと 8 | * 4.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること 9 | * 5.ボックスが空のこと 10 | * 6.オフライン状態であること 11 | * 7.無線のコントローラーが接続されていないこと 12 | * 8.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと 13 | * 9.ちょいらくモードが「しない」であること 14 | * 10.まるいおまもりを所持していること 15 | */ 16 | 17 | // ライブラリを読み込むためのコード 18 | #include 19 | 20 | // 孵化サイクル20のポケモンが、孵化するまでにかかる最大時間 21 | const int TIME_TO_HATCHING_SEC = 69; 22 | 23 | // 空飛ぶタクシーでハシノマはらっぱに移動する関数 24 | void moveToInitialPlayerPosition() { 25 | pushButton(Button::A, 2000); 26 | pushButton(Button::A, 450, 2); 27 | delay(2200); // 天候によって読み込み時間がやや異なる(最も重かった砂嵐でも1900で安定していたが、柱の本数や服装などの環境による差異がある可能性も考慮して少し余裕を持たせた) 28 | } 29 | 30 | // 初期位置(ハシノマはらっぱ)からぐるぐる走り回る関数 31 | void runAround() { 32 | for (int egg_num = 0; egg_num < 6; egg_num++) { 33 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 34 | // delayの秒数がintの最大値を越えないように30秒ごとに実行する 35 | for (int i = 0; i < TIME_TO_HATCHING_SEC / 30; i++) { 36 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, 30000); 37 | } 38 | tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, (TIME_TO_HATCHING_SEC % 30) * 1000); 39 | waitEggHatching(); 40 | pushButton(Button::X, 500); 41 | moveToInitialPlayerPosition(); 42 | } 43 | } 44 | 45 | // ボックスを開く関数 46 | void openBox() { 47 | pushButton(Button::X, 500); 48 | pushHat(Hat::RIGHT, 25); 49 | pushButton(Button::A, 1250); 50 | pushButton(Button::R, 1500); 51 | } 52 | 53 | // ボックスを閉じる関数 54 | void closeBox() { 55 | pushButton(Button::B, 25); // ボックスが空でなかった場合でも、ボックスを閉じてループを実行し続けさせるのに必要な記述 56 | pushButton(Button::B, 1500); 57 | pushButton(Button::B, 1250); 58 | pushHat(Hat::LEFT, 25); 59 | } 60 | 61 | // タマゴが孵化するのを待つ関数 62 | void waitEggHatching() { 63 | pushButton(Button::B, 450, 38); // 余裕があるように思えるが、色違いのエフェクトを考慮するとこれ以上は厳しい 64 | } 65 | 66 | // タマゴをボックスから引き取る関数 67 | void adoptedEggs(int box_line) { 68 | // 孵化させるタマゴを範囲選択 69 | pushButton(Button::A, 25); 70 | pushHat(Hat::DOWN, 50, 4); 71 | pushButton(Button::A, 25); 72 | // 手持ちに加える 73 | pushHat(Hat::LEFT, 100, box_line + 1); 74 | pushHat(Hat::DOWN, 25); 75 | pushButton(Button::A, 25); 76 | } 77 | 78 | // タマゴを孵化→ボックスのタマゴと入れ替えを繰り返す関数 79 | void withdrawEggs(int box_line) { 80 | // 空飛ぶタクシーでハシノマはらっぱに移動する 81 | moveToInitialPlayerPosition(); 82 | // 手持ちのタマゴを全て孵化させる 83 | runAround(); 84 | // ボックスを開く 85 | openBox(); 86 | // 手持ちの孵化したポケモンを範囲選択 87 | pushHat(Hat::LEFT, 25); 88 | pushHat(Hat::DOWN, 25); 89 | pushButton(Button::Y, 25); 90 | pushButton(Button::Y, 25); 91 | pushButton(Button::A, 25); 92 | pushHat(Hat::DOWN, 50, 4); 93 | pushButton(Button::A, 25); 94 | // ボックスに預ける 95 | pushHat(Hat::RIGHT, 100, box_line); 96 | pushHat(Hat::UP, 25); 97 | pushButton(Button::A, 25); 98 | // ボックスがいっぱいになったら、次のボックスに移動させる 99 | if (box_line == 6) { 100 | pushHat(Hat::UP, 25); 101 | pushHat(Hat::RIGHT, 25); 102 | // 新しいボックスの1列目のタマゴを引き取る 103 | pushHat(Hat::DOWN, 25); 104 | pushHat(Hat::RIGHT, 100, 2); 105 | adoptedEggs(0); 106 | } else { 107 | // タマゴをボックスから引き取る 108 | pushHat(Hat::RIGHT, 25); 109 | adoptedEggs(box_line); 110 | } 111 | // ボックスを閉じる 112 | closeBox(); 113 | } 114 | 115 | // マイコンのセット時に1度だけ行われる処理 116 | void setup() { 117 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 118 | pushButton(Button::B, 500, 5); 119 | 120 | // マイコンを認識したら、メニューの左上にカーソルを持っていく 121 | pushButton(Button::X, 600); 122 | holdHat(Hat::UP_LEFT, 750); 123 | 124 | // ボックスを開く 125 | pushHat(Hat::RIGHT, 25); 126 | pushButton(Button::A, 1250); 127 | pushButton(Button::R, 1500); 128 | 129 | // 孵化させるタマゴを手持ちに加える 130 | pushButton(Button::Y, 25); 131 | pushButton(Button::Y, 25); 132 | adoptedEggs(0); 133 | 134 | // ボックスを閉じる 135 | closeBox(); 136 | } 137 | 138 | // ここに記述した内容がループされ続ける 139 | void loop() { 140 | for (int box_line = 1; box_line < 7; box_line++) { 141 | withdrawEggs(box_line); 142 | } 143 | } -------------------------------------------------------------------------------- /examples/Splatoon3/get-ikura/get-ikura.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * スプラトゥーン3のヒーローモードでイクラ集めを自動化するスケッチ 3 | * 4 | * ※ 当プログラムはスプラトゥーン3のVer1.1.1で動作確認を行っております。アップデートにより正常に動作しなくなる可能性がありますのでご了承ください。 5 | * 6 | * 初期条件は以下の通り 7 | * 1. ヒーローモードで「宇宙の中心が、ここにある。」のヤカン上にいること 8 | * 2. Rスティックの操作感度が「0」であること 9 | * 3. Rスティックの上下操作が「ノーマル」であること 10 | * 3. ジャイロ操作が「OFF」であること 11 | */ 12 | 13 | // ヤカンに潜る際のロード時間 14 | const int START_LOADING_TIME_MS = 10000; 15 | 16 | // ミッションをクリアした後、自由行動できるようになるまでの時間 17 | const int CLEAR_LOADING_TIME_MS = 30000; 18 | 19 | // リッターを構えるまでの時間 20 | const int ADJUST_TIME_MS = 6000; 21 | 22 | // ライブラリを読み込むためのコード(詳細: https://github.com/lefmarna/NintendoSwitchControlLibrary) 23 | #include 24 | 25 | // 「使いたいコントローラーのL+Rを押してください」を閉じる 26 | void selectController() { 27 | pushButton(Button::L, 100); 28 | pushButton(Button::R, 100); 29 | pushButton(Button::A, 3000); 30 | } 31 | 32 | // ミッションを開始する 33 | void startMission() { 34 | holdButton(Button::ZL, START_LOADING_TIME_MS); 35 | pushButton(Button::A, 2000); 36 | tiltLeftStick(Stick::NEUTRAL, Stick::MIN, 2000); 37 | pushButton(Button::A, 3000); 38 | } 39 | 40 | // インクを発射する 41 | void shootInk() { 42 | tiltRightStick(Stick::NEUTRAL, Stick::MIN, 50); 43 | holdButton(Button::ZR, 2000); 44 | } 45 | 46 | // マイコンのセット時に1度だけ行われる処理 47 | void setup() { 48 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 49 | pushButton(Button::B, 500, 5); 50 | // 「使いたいコントローラーのL+Rを押してください」の画面が出るまで待機する 51 | delay(5000); 52 | // 「使いたいコントローラーのL+Rを押してください」を突破する 53 | selectController(); 54 | } 55 | 56 | // ここに記述した内容がループされ続ける 57 | void loop() { 58 | startMission(); 59 | delay(ADJUST_TIME_MS); 60 | shootInk(); 61 | delay(CLEAR_LOADING_TIME_MS); 62 | } 63 | -------------------------------------------------------------------------------- /examples/Xenoblade3/auto-get-nopon-coins/auto-get-nopon-coins.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ゼノブレイド3の熾天神獣セラティニア討伐を自動化し、ノポンコイン金・銀と金策を自動化するスケッチ 3 | * 4 | * 初期条件は以下の通り 5 | * 1. 熾天神獣セラティニアを討伐済であること 6 | * 2. 難易度設定が「イージー」であること 7 | * 3. インタリンク操作タイプを「パーティ」にしておくこと 8 | * 4. 大剣上層部のユニークモンスターをすべて討伐済であること(全3種) 9 | * 5. 操作キャラにマスタースキル「いつでもやれる」を設定していないこと 10 | * 6. 操作キャラ以外にバーストコンボを盛り込みつつ、かつ、全滅しない程度の回復アーツも積んだ編成であること(参考: https://www.youtube.com/watch?v=VsUHX7SLwsU) 11 | */ 12 | 13 | // ライブラリを読み込むためのコード(詳細: https://github.com/lefmarna/NintendoSwitchControlLibrary) 14 | #include 15 | 16 | // スキップトラベル → 名を冠する者の墓 にて 「熾天神獣セラティニア」が上から何番目にあるかを指定する 17 | const int SKIP_TRAVEL_INDEX = 2; 18 | 19 | // 1戦闘にかかる時間を指定する(分指定) 20 | const int BATTLE_TIME_MINUS = 29; 21 | 22 | // 何回ループさせるか?(銀コインが3セットで90枚近く取得できるため、3推奨) 23 | const int BATTLE_COUNT = 3; 24 | 25 | // パケ版・DL版の差やSwitch本体の個体差などにより、ボタン間隔が短いと動かない方は以下の数値を調節してください 26 | const int BUTTON_INTERVAL = 1000; // ボタンを押す間隔 27 | const int HAT_INTERVAL = 500; // カーソルキーを押す間隔 28 | 29 | // マップを開く 30 | void openMap() { 31 | SwitchControlLibrary().pressButton(Button::ZL); 32 | SwitchControlLibrary().sendReport(); 33 | delay(BUTTON_INTERVAL); 34 | SwitchControlLibrary().pressButton(Button::X); 35 | SwitchControlLibrary().sendReport(); 36 | delay(BUTTON_INTERVAL); 37 | SwitchControlLibrary().releaseButton(Button::ZL); 38 | SwitchControlLibrary().releaseButton(Button::X); 39 | SwitchControlLibrary().sendReport(); 40 | delay(5000); 41 | } 42 | 43 | // 位置をリセットする 44 | void resetPosition() { 45 | openMap(); 46 | // 「熾天神獣セラティニアの墓」へスキップトラベル 47 | pushButton(Button::PLUS, BUTTON_INTERVAL); 48 | pushHat(Hat::DOWN, HAT_INTERVAL, 2); 49 | pushButton(Button::A, BUTTON_INTERVAL); 50 | pushHat(Hat::DOWN, HAT_INTERVAL, SKIP_TRAVEL_INDEX - 1); 51 | pushButton(Button::A, BUTTON_INTERVAL, 2); 52 | // ロード時間 53 | delay(5000); 54 | } 55 | 56 | // 「使いたいコントローラーのL+Rを押してください」を閉じる 57 | void selectController() { 58 | pushButton(Button::L, 100); 59 | pushButton(Button::R, 100); 60 | pushButton(Button::A, 3000); 61 | } 62 | 63 | // バトル開始位置に移動 64 | void moveToGravePosition() { 65 | tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500); 66 | } 67 | 68 | // バトルを行う 69 | void startBattle() { 70 | pushButton(Button::A, 3000, 3); 71 | // 離れた場所に移動しておく 72 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, 7000); 73 | // 指定の時間(デフォルトは29分)待機する 74 | const unsigned long battle_time_ms = (1000UL * BATTLE_TIME_MINUS * 60) - 7000; 75 | delay(battle_time_ms); 76 | } 77 | 78 | // Switchをスリープさせる 79 | void sleepGame() { 80 | holdButton(Button::HOME, 1500); 81 | pushButton(Button::A, BUTTON_INTERVAL); 82 | } 83 | 84 | // マイコンのセット時に1度だけ行われる処理 85 | void setup() { 86 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 87 | pushButton(Button::B, 500, 5); 88 | // 「使いたいコントローラーのL+Rを押してください」の画面が出るまで待機する 89 | delay(3000); 90 | // 「使いたいコントローラーのL+Rを押してください」を突破する 91 | selectController(); 92 | } 93 | 94 | int loopCount = 0; 95 | 96 | // ここに記述した内容がループされ続ける 97 | void loop() { 98 | // 指定の回数(デフォルトでは3回)バトルを行った後、スリープ状態にして処理を終了する 99 | if (loopCount == BATTLE_COUNT) { 100 | sleepGame(); 101 | exit(0); 102 | } 103 | 104 | resetPosition(); 105 | moveToGravePosition(); 106 | startBattle(); 107 | loopCount++; 108 | } 109 | -------------------------------------------------------------------------------- /examples/Xenoblade3/auto-leveling/auto-leveling.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ゼノブレイド3の亜人煉獄でクラスのレベル上げを自動化するスケッチ 3 | * 4 | * いくつか定数を用意しています。 5 | * これらは動作させるために必要不可欠な値であり、必ず設定してもらう必要があります。 6 | * 28行目・39行目の値はご自身で設定いただくようお願いいたします。 7 | * 8 | * 9 | * 初期条件は以下の通り 10 | * 1. カデンシア地方にいること 11 | * 2. 近くに敵が存在しないこと 12 | * 3. 操作キャラがノアであること 13 | * 4. ノアのフラッシュフェンサーがLv20まで育っていること 14 | * 5. タレントアーツが「アンリミテッドソード」に設定してあること 15 | * 6. マスタースキル「いつでもやれる」を設定してあること 16 | * 7. 亜人煉獄をスキップトラベル開放済であること 17 | * 8. 戦闘に負けない編成であること 18 | */ 19 | 20 | // ライブラリを読み込むためのコード(詳細: https://github.com/lefmarna/NintendoSwitchControlLibrary) 21 | #include 22 | 23 | /** 24 | * スキップトラベル → ランドマーク にて 「亜人煉獄」が上から何番目にあるかを指定する 25 | * (上から10番目の場合は10となります) 26 | * 27 | * ランドマーク開放数で順番が変わるため人によって値が違います。 28 | * 要設定 29 | */ 30 | const int DEMI_HUMAN_PURGATORY_INDEX = 12; 31 | 32 | /** 33 | * 1戦闘にかかる時間を指定する(秒指定) 34 | * 35 | * ※ チェインアタックの有無で大きく時間が変わります。 36 | * 1チェインしても戦闘が終了することが期待できる時間が300でしたので初期値を300としていますが、必要に応じて変更してください。 37 | * 要設定 38 | */ 39 | const int BATTLE_TIME = 300; 40 | 41 | /** 42 | * パケ版・DL版の差やSwitch本体の個体差などにより、ボタン間隔が短いと動かない方は以下の数値を調節してください 43 | */ 44 | const int BUTTON_INTERVAL = 1000; // ボタンを押す間隔 45 | const int HAT_INTERVAL = 200; // カーソルキーを押す間隔 46 | 47 | // 位置をリセットする 48 | void resetPosition() { 49 | // メニュー → マップ 50 | pushButton(Button::X, BUTTON_INTERVAL); 51 | pushHat(Hat::DOWN, HAT_INTERVAL, 2); 52 | // 亜人煉獄へスキップトラベル 53 | pushButton(Button::A, BUTTON_INTERVAL, 2); 54 | pushButton(Button::PLUS, BUTTON_INTERVAL); 55 | pushButton(Button::A, BUTTON_INTERVAL); 56 | pushHat(Hat::DOWN, HAT_INTERVAL * 2, DEMI_HUMAN_PURGATORY_INDEX - 1); 57 | pushButton(Button::A, BUTTON_INTERVAL, 2); 58 | // ロード時間 59 | delay(5000); 60 | } 61 | 62 | // 「使いたいコントローラーのL+Rを押してください」を閉じる 63 | void selectController() { 64 | pushButton(Button::L, 100); 65 | pushButton(Button::R, 100); 66 | pushButton(Button::A, 3000); 67 | } 68 | 69 | // バトル開始位置に移動 70 | void moveBattlePosition() { 71 | tiltLeftStick(Stick::NEUTRAL, Stick::MAX, 4000); 72 | } 73 | 74 | // バトルを行う 75 | void startBattle() { 76 | // 抜刀 → アンリミテッドソード 77 | pushButton(Button::R, BUTTON_INTERVAL); 78 | pushButton(Button::A, 2000); 79 | pushButton(Button::A, 6000); 80 | // オートバトル 81 | pushButton(Button::MINUS, BUTTON_INTERVAL); 82 | for (int i = 0; i < BATTLE_TIME / 30; i++) { 83 | delay(30000); 84 | } 85 | delay((BATTLE_TIME % 30) * 1000); 86 | } 87 | 88 | // 敵をリポップさせる 89 | void repopMonsters() { 90 | pushButton(Button::R, BUTTON_INTERVAL); 91 | pushButton(Button::A, 2000); 92 | holdButton(Button::MINUS, 2000); 93 | pushHat(Hat::DOWN, HAT_INTERVAL); 94 | pushButton(Button::A, BUTTON_INTERVAL); 95 | pushHat(Hat::UP, HAT_INTERVAL); 96 | pushButton(Button::A, BUTTON_INTERVAL); 97 | delay(5000); 98 | } 99 | 100 | // マイコンのセット時に1度だけ行われる処理 101 | void setup() { 102 | // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく 103 | pushButton(Button::B, 500, 5); 104 | // 「使いたいコントローラーのL+Rを押してください」の画面が出るまで待機する 105 | delay(5000); 106 | // 「使いたいコントローラーのL+Rを押してください」を突破する 107 | selectController(); 108 | // メニューを開いていた場合は閉じる 109 | pushButton(Button::B, BUTTON_INTERVAL, 5); 110 | resetPosition(); 111 | } 112 | 113 | // ここに記述した内容がループされ続ける 114 | void loop() { 115 | moveBattlePosition(); 116 | startBattle(); 117 | resetPosition(); 118 | repopMonsters(); 119 | } 120 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=NintendoSwitchControlLibrary 2 | version=1.3.1 3 | author=lefmarna 4 | maintainer=lefmarna 5 | sentence=A library for microcontrollers that uses Arduino to automate Nintendo Switch games. 6 | paragraph=A library for microcontrollers that uses Arduino to automate Nintendo Switch games. 7 | category=Device Control 8 | url=https://github.com/lefmarna/NintendoSwitchControlLibrary 9 | architectures=* -------------------------------------------------------------------------------- /src/NintendoSwitchControlLibrary.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 lefmarna 3 | released under the MIT license 4 | https://opensource.org/licenses/mit-license.php 5 | */ 6 | 7 | #include "./NintendoSwitchControlLibrary.h" 8 | 9 | // ボタンを押してから離すまでの時間(ミリ秒) 10 | const uint16_t INPUT_TIME = 100; 11 | 12 | // ボタンを連打する際に、押して認識後、離して認識するまでの合計時間(ミリ秒) 13 | const uint16_t INPUT_TIME_TWICE = INPUT_TIME * 2; 14 | 15 | /** 16 | * ボタンを押す 17 | * 18 | * @param uint16_t button 押すボタン 19 | * @param unsigned long delay_time ボタンを押した後の待ち時間(1秒 = 1000) 20 | * @param unsigned int loop ボタンを押す回数(省略可、デフォルトは1) 21 | */ 22 | void pushButton(uint16_t button, unsigned long delay_time, unsigned int loop) { 23 | for (unsigned int i = 0; i < loop; i++) { 24 | SwitchControlLibrary().pressButton(button); 25 | SwitchControlLibrary().sendReport(); 26 | delay(INPUT_TIME); 27 | SwitchControlLibrary().releaseButton(button); 28 | SwitchControlLibrary().sendReport(); 29 | delay(delay_time); 30 | } 31 | delay(INPUT_TIME); 32 | } 33 | 34 | /** 35 | * ボタンを指定の時間押し続ける 36 | * 37 | * @param uint16_t button 押し続けるボタン 38 | * @param unsigned long hold_time ボタンを押す時間の長さ(1秒 = 1000) 39 | */ 40 | void holdButton(uint16_t button, unsigned long hold_time) { 41 | SwitchControlLibrary().pressButton(button); 42 | SwitchControlLibrary().sendReport(); 43 | delay(hold_time); 44 | SwitchControlLibrary().releaseButton(button); 45 | SwitchControlLibrary().sendReport(); 46 | delay(INPUT_TIME); 47 | } 48 | 49 | /** 50 | * 十字キーを押す 51 | * 52 | * @param uint8_t hat 押す十字キーのボタン 53 | * @param unsigned long delay_time ボタンを押した後の待ち時間(1秒 = 1000) 54 | * @param unsigned int loop ボタンを押す回数(省略可、デフォルトは1) 55 | */ 56 | void pushHat(uint8_t hat, unsigned long delay_time, unsigned int loop) { 57 | for (unsigned int i = 0; i < loop; i++) { 58 | SwitchControlLibrary().pressHatButton(hat); 59 | SwitchControlLibrary().sendReport(); 60 | delay(INPUT_TIME); 61 | SwitchControlLibrary().releaseHatButton(); 62 | SwitchControlLibrary().sendReport(); 63 | delay(delay_time); 64 | } 65 | delay(INPUT_TIME); 66 | } 67 | 68 | /** 69 | * 十字キーを指定の時間押し続ける 70 | * 71 | * @param uint8_t hat: 押し続ける十字キーのボタン 72 | * @param unsigned long hold_time: ボタンを押す時間の長さ(1秒 = 1000) 73 | */ 74 | void holdHat(uint8_t hat, unsigned long hold_time) { 75 | SwitchControlLibrary().pressHatButton(hat); 76 | SwitchControlLibrary().sendReport(); 77 | delay(hold_time); 78 | SwitchControlLibrary().releaseHatButton(); 79 | SwitchControlLibrary().sendReport(); 80 | delay(INPUT_TIME); 81 | } 82 | 83 | /** 84 | * 左スティックを指定の時間傾け続ける 85 | * 128を基準とし、0~255の値を指定する 86 | * 87 | * @param uint8_t lx: 左スティックのx軸 88 | * @param uint8_t ly: 左スティックのy軸 89 | * @param unsigned long tilt_time: スティックを傾ける時間の長さ 90 | * @param uint16_t button: 連打するボタン 91 | * 92 | * @see Stick::MIN 0 93 | * @see Stick::NEUTRAL 128 94 | * @see Stick::MAX 255 95 | */ 96 | void tiltLeftStick(uint8_t lx, uint8_t ly, unsigned long tilt_time, uint16_t button) { 97 | SwitchControlLibrary().moveLeftStick(lx, ly); 98 | SwitchControlLibrary().sendReport(); 99 | if (button) { 100 | while (INPUT_TIME_TWICE <= tilt_time) { 101 | SwitchControlLibrary().pressButton(button); 102 | SwitchControlLibrary().sendReport(); 103 | delay(INPUT_TIME); 104 | SwitchControlLibrary().releaseButton(button); 105 | SwitchControlLibrary().sendReport(); 106 | delay(INPUT_TIME); 107 | tilt_time -= INPUT_TIME_TWICE; 108 | } 109 | } 110 | delay(tilt_time); 111 | SwitchControlLibrary().moveLeftStick(Stick::NEUTRAL, Stick::NEUTRAL); 112 | SwitchControlLibrary().sendReport(); 113 | delay(INPUT_TIME); 114 | } 115 | 116 | /** 117 | * 右スティックを指定の時間傾け続ける 118 | * 128を基準とし、0~255の値を指定する 119 | * 120 | * @param uint8_t rx: 右スティックのx軸 121 | * @param uint8_t ry: 右スティックのy軸 122 | * @param unsigned long tilt_time: スティックを傾ける時間の長さ 123 | * @param uint16_t button: 連打するボタン 124 | * 125 | * @see Stick::MIN 0 126 | * @see Stick::NEUTRAL 128 127 | * @see Stick::MAX 255 128 | */ 129 | void tiltRightStick(uint8_t rx, uint8_t ry, unsigned long tilt_time, uint16_t button) { 130 | SwitchControlLibrary().moveRightStick(rx, ry); 131 | SwitchControlLibrary().sendReport(); 132 | if (button) { 133 | while (INPUT_TIME_TWICE <= tilt_time) { 134 | SwitchControlLibrary().pressButton(button); 135 | SwitchControlLibrary().sendReport(); 136 | delay(INPUT_TIME); 137 | SwitchControlLibrary().releaseButton(button); 138 | SwitchControlLibrary().sendReport(); 139 | delay(INPUT_TIME); 140 | tilt_time -= INPUT_TIME_TWICE; 141 | } 142 | } 143 | delay(tilt_time); 144 | SwitchControlLibrary().moveRightStick(Stick::NEUTRAL, Stick::NEUTRAL); 145 | SwitchControlLibrary().sendReport(); 146 | delay(INPUT_TIME); 147 | } 148 | 149 | /** 150 | * 左スティックと右スティックを同時に指定の時間傾け続ける 151 | * 128を基準とし、0~255の値を指定する 152 | * 153 | * @param uint8_t lx: 左スティックのx軸 154 | * @param uint8_t ly: 左スティックのy軸 155 | * @param uint8_t rx: 右スティックのx軸 156 | * @param uint8_t ry: 右スティックのy軸 157 | * @param unsigned long tilt_time: スティックを傾ける時間の長さ 158 | * @param uint16_t button: 連打するボタン 159 | * 160 | * @see Stick::MIN 0 161 | * @see Stick::NEUTRAL 128 162 | * @see Stick::MAX 255 163 | */ 164 | void tiltLeftAndRightStick(uint8_t lx, uint8_t ly, uint8_t rx, uint8_t ry, 165 | unsigned long tilt_time, uint16_t button) { 166 | SwitchControlLibrary().moveLeftStick(lx, ly); 167 | SwitchControlLibrary().moveRightStick(rx, ry); 168 | SwitchControlLibrary().sendReport(); 169 | if (button) { 170 | while (INPUT_TIME_TWICE <= tilt_time) { 171 | SwitchControlLibrary().pressButton(button); 172 | SwitchControlLibrary().sendReport(); 173 | delay(INPUT_TIME); 174 | SwitchControlLibrary().releaseButton(button); 175 | SwitchControlLibrary().sendReport(); 176 | delay(INPUT_TIME); 177 | tilt_time -= INPUT_TIME_TWICE; 178 | } 179 | } 180 | delay(tilt_time); 181 | SwitchControlLibrary().moveLeftStick(Stick::NEUTRAL, Stick::NEUTRAL); 182 | SwitchControlLibrary().moveRightStick(Stick::NEUTRAL, Stick::NEUTRAL); 183 | SwitchControlLibrary().sendReport(); 184 | delay(INPUT_TIME); 185 | } 186 | 187 | /** 188 | * 左スティックをぐるぐると回す 189 | * 190 | * @param unsigned long spin_time: ぐるぐるさせる時間(1回転に満たない端数の時間が生じた場合は切り捨てとなります) 191 | * @param uint8_t speed: 1秒あたりの回転数 192 | * @param bool direction: 方向(1: 時計回り, 0:反時計回り) 193 | */ 194 | void spinLeftStick(unsigned long spin_time, uint8_t speed, bool direction) { 195 | // 1秒あたりの回転数から1回転にかかる時間を求める 196 | float spin_count_per_second = 1000 / speed; 197 | 198 | // 1回転で8箇所のチェックポイントを回ることになるため、その通過タイムを求める 199 | float spin_delay = spin_count_per_second / 8; 200 | 201 | // 回転方向の制御を担う変数を用意する(スティックのx座標をdirectionの値によって左右逆転させる) 202 | int x_max; 203 | int x_min; 204 | if (direction) { 205 | x_max = Stick::MAX; 206 | x_min = Stick::MIN; 207 | } else { 208 | x_max = Stick::MIN; 209 | x_min = Stick::MAX; 210 | } 211 | 212 | // 指定された時間の間、左スティックをぐるぐると回す 213 | while (spin_time >= spin_count_per_second) { 214 | SwitchControlLibrary().moveLeftStick(Stick::NEUTRAL, Stick::MAX); 215 | SwitchControlLibrary().sendReport(); 216 | delay(spin_delay); 217 | SwitchControlLibrary().moveLeftStick(x_min, Stick::MAX); 218 | SwitchControlLibrary().sendReport(); 219 | delay(spin_delay); 220 | SwitchControlLibrary().moveLeftStick(x_min, Stick::NEUTRAL); 221 | SwitchControlLibrary().sendReport(); 222 | delay(spin_delay); 223 | SwitchControlLibrary().moveLeftStick(x_min, Stick::MIN); 224 | SwitchControlLibrary().sendReport(); 225 | delay(spin_delay); 226 | SwitchControlLibrary().moveLeftStick(Stick::NEUTRAL, Stick::MIN); 227 | SwitchControlLibrary().sendReport(); 228 | delay(spin_delay); 229 | SwitchControlLibrary().moveLeftStick(x_max, Stick::MIN); 230 | SwitchControlLibrary().sendReport(); 231 | delay(spin_delay); 232 | SwitchControlLibrary().moveLeftStick(x_max, Stick::NEUTRAL); 233 | SwitchControlLibrary().sendReport(); 234 | delay(spin_delay); 235 | SwitchControlLibrary().moveLeftStick(x_max, Stick::MAX); 236 | SwitchControlLibrary().sendReport(); 237 | delay(spin_delay); 238 | spin_time = spin_time - spin_count_per_second; 239 | } 240 | 241 | // 処理が終了したら、スティックを倒していない状態に戻す 242 | SwitchControlLibrary().moveLeftStick(Stick::NEUTRAL, Stick::NEUTRAL); 243 | SwitchControlLibrary().sendReport(); 244 | } 245 | 246 | /** 247 | * 右スティックをぐるぐると回す 248 | * 249 | * @param unsigned long spin_time: ぐるぐるさせる時間(1回転に満たない端数の時間が生じた場合は切り捨てとなります) 250 | * @param uint8_t speed: 1秒あたりの回転数 251 | * @param bool direction: 方向(1: 左, 0:右) 252 | */ 253 | void spinRightStick(unsigned long spin_time, uint8_t speed, bool direction) { 254 | // 1秒あたりの回転数から1回転にかかる時間を求める 255 | float spin_count_per_second = 1000 / speed; 256 | 257 | // 1回転で8箇所のチェックポイントを回ることになるため、その通過タイムを求める 258 | float spin_delay = spin_count_per_second / 8; 259 | 260 | // 回転方向の制御を担う変数を用意する(スティックのx座標をdirectionの値によって左右逆転させる) 261 | int x_max; 262 | int x_min; 263 | if (direction) { 264 | x_max = Stick::MAX; 265 | x_min = Stick::MIN; 266 | } else { 267 | x_max = Stick::MIN; 268 | x_min = Stick::MAX; 269 | } 270 | 271 | // 指定された時間の間、右スティックをぐるぐると回す 272 | while (spin_time >= spin_count_per_second) { 273 | SwitchControlLibrary().moveRightStick(Stick::NEUTRAL, Stick::MAX); 274 | SwitchControlLibrary().sendReport(); 275 | delay(spin_delay); 276 | SwitchControlLibrary().moveRightStick(x_min, Stick::MAX); 277 | SwitchControlLibrary().sendReport(); 278 | delay(spin_delay); 279 | SwitchControlLibrary().moveRightStick(x_min, Stick::NEUTRAL); 280 | SwitchControlLibrary().sendReport(); 281 | delay(spin_delay); 282 | SwitchControlLibrary().moveRightStick(x_min, Stick::MIN); 283 | SwitchControlLibrary().sendReport(); 284 | delay(spin_delay); 285 | SwitchControlLibrary().moveRightStick(Stick::NEUTRAL, Stick::MIN); 286 | SwitchControlLibrary().sendReport(); 287 | delay(spin_delay); 288 | SwitchControlLibrary().moveRightStick(x_max, Stick::MIN); 289 | SwitchControlLibrary().sendReport(); 290 | delay(spin_delay); 291 | SwitchControlLibrary().moveRightStick(x_max, Stick::NEUTRAL); 292 | SwitchControlLibrary().sendReport(); 293 | delay(spin_delay); 294 | SwitchControlLibrary().moveRightStick(x_max, Stick::MAX); 295 | SwitchControlLibrary().sendReport(); 296 | delay(spin_delay); 297 | spin_time = spin_time - spin_count_per_second; 298 | } 299 | 300 | // 処理が終了したら、スティックを倒していない状態に戻す 301 | SwitchControlLibrary().moveRightStick(Stick::NEUTRAL, Stick::NEUTRAL); 302 | SwitchControlLibrary().sendReport(); 303 | } -------------------------------------------------------------------------------- /src/NintendoSwitchControlLibrary.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 lefmarna 3 | released under the MIT license 4 | https://opensource.org/licenses/mit-license.php 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "./SwitchControlLibrary/SwitchControlLibrary.h" 10 | 11 | void pushButton(uint16_t button, unsigned long delay_time = 0, unsigned int loop = 1); 12 | void holdButton(uint16_t button, unsigned long hold_time); 13 | 14 | void pushHat(uint8_t hat, unsigned long delay_time = 0, unsigned int loop = 1); 15 | void holdHat(uint8_t hat, unsigned long hold_time); 16 | 17 | void tiltLeftStick(uint8_t lx, uint8_t ly, unsigned long tilt_time, uint16_t button = 0); 18 | void tiltRightStick(uint8_t rx, uint8_t ry, unsigned long tilt_time, uint16_t button = 0); 19 | void tiltLeftAndRightStick(uint8_t lx, uint8_t ly, uint8_t rx, uint8_t ry, unsigned long tilt_time, uint16_t button = 0); 20 | 21 | void spinLeftStick(unsigned long spin_time, uint8_t speed = 5, bool direction = 1); 22 | void spinRightStick(unsigned long spin_time, uint8_t speed = 5, bool direction = 1); -------------------------------------------------------------------------------- /src/SwitchControlLibrary/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveBitFields: false 9 | AlignConsecutiveDeclarations: false 10 | AlignEscapedNewlines: Left 11 | AlignOperands: Align 12 | AlignTrailingComments: true 13 | AllowAllArgumentsOnNextLine: true 14 | AllowAllConstructorInitializersOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortBlocksOnASingleLine: Never 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: All 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortIfStatementsOnASingleLine: WithoutElse 22 | AllowShortLoopsOnASingleLine: true 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: true 26 | AlwaysBreakTemplateDeclarations: Yes 27 | BinPackArguments: true 28 | BinPackParameters: true 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: false 32 | AfterControlStatement: Never 33 | AfterEnum: false 34 | AfterFunction: false 35 | AfterNamespace: false 36 | AfterObjCDeclaration: false 37 | AfterStruct: false 38 | AfterUnion: false 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakBeforeBinaryOperators: None 49 | BreakBeforeBraces: Attach 50 | BreakBeforeInheritanceComma: false 51 | BreakInheritanceList: BeforeColon 52 | BreakBeforeTernaryOperators: true 53 | BreakConstructorInitializersBeforeComma: false 54 | BreakConstructorInitializers: BeforeColon 55 | BreakAfterJavaFieldAnnotations: false 56 | BreakStringLiterals: true 57 | ColumnLimit: 80 58 | CommentPragmas: '^ IWYU pragma:' 59 | CompactNamespaces: false 60 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 61 | ConstructorInitializerIndentWidth: 4 62 | ContinuationIndentWidth: 4 63 | Cpp11BracedListStyle: true 64 | DeriveLineEnding: true 65 | DerivePointerAlignment: true 66 | DisableFormat: false 67 | ExperimentalAutoDetectBinPacking: false 68 | FixNamespaceComments: true 69 | ForEachMacros: 70 | - foreach 71 | - Q_FOREACH 72 | - BOOST_FOREACH 73 | IncludeBlocks: Regroup 74 | IncludeCategories: 75 | - Regex: '^' 76 | Priority: 2 77 | SortPriority: 0 78 | - Regex: '^<.*\.h>' 79 | Priority: 1 80 | SortPriority: 0 81 | - Regex: '^<.*' 82 | Priority: 2 83 | SortPriority: 0 84 | - Regex: '.*' 85 | Priority: 3 86 | SortPriority: 0 87 | IncludeIsMainRegex: '([-_](test|unittest))?$' 88 | IncludeIsMainSourceRegex: '' 89 | IndentCaseLabels: true 90 | IndentCaseBlocks: false 91 | IndentGotoLabels: true 92 | IndentPPDirectives: None 93 | IndentExternBlock: AfterExternBlock 94 | IndentWidth: 2 95 | IndentWrappedFunctionNames: false 96 | InsertTrailingCommas: None 97 | JavaScriptQuotes: Leave 98 | JavaScriptWrapImports: true 99 | KeepEmptyLinesAtTheStartOfBlocks: false 100 | MacroBlockBegin: '' 101 | MacroBlockEnd: '' 102 | MaxEmptyLinesToKeep: 1 103 | NamespaceIndentation: None 104 | ObjCBinPackProtocolList: Never 105 | ObjCBlockIndentWidth: 2 106 | ObjCBreakBeforeNestedBlockParam: true 107 | ObjCSpaceAfterProperty: false 108 | ObjCSpaceBeforeProtocolList: true 109 | PenaltyBreakAssignment: 2 110 | PenaltyBreakBeforeFirstCallParameter: 1 111 | PenaltyBreakComment: 300 112 | PenaltyBreakFirstLessLess: 120 113 | PenaltyBreakString: 1000 114 | PenaltyBreakTemplateDeclaration: 10 115 | PenaltyExcessCharacter: 1000000 116 | PenaltyReturnTypeOnItsOwnLine: 200 117 | PointerAlignment: Left 118 | RawStringFormats: 119 | - Language: Cpp 120 | Delimiters: 121 | - cc 122 | - CC 123 | - cpp 124 | - Cpp 125 | - CPP 126 | - 'c++' 127 | - 'C++' 128 | CanonicalDelimiter: '' 129 | BasedOnStyle: google 130 | - Language: TextProto 131 | Delimiters: 132 | - pb 133 | - PB 134 | - proto 135 | - PROTO 136 | EnclosingFunctions: 137 | - EqualsProto 138 | - EquivToProto 139 | - PARSE_PARTIAL_TEXT_PROTO 140 | - PARSE_TEST_PROTO 141 | - PARSE_TEXT_PROTO 142 | - ParseTextOrDie 143 | - ParseTextProtoOrDie 144 | - ParseTestProto 145 | - ParsePartialTestProto 146 | CanonicalDelimiter: '' 147 | BasedOnStyle: google 148 | ReflowComments: true 149 | SortIncludes: true 150 | SortUsingDeclarations: true 151 | SpaceAfterCStyleCast: false 152 | SpaceAfterLogicalNot: false 153 | SpaceAfterTemplateKeyword: true 154 | SpaceBeforeAssignmentOperators: true 155 | SpaceBeforeCpp11BracedList: false 156 | SpaceBeforeCtorInitializerColon: true 157 | SpaceBeforeInheritanceColon: true 158 | SpaceBeforeParens: ControlStatements 159 | SpaceBeforeRangeBasedForLoopColon: true 160 | SpaceInEmptyBlock: false 161 | SpaceInEmptyParentheses: false 162 | SpacesBeforeTrailingComments: 2 163 | SpacesInAngles: false 164 | SpacesInConditionalStatement: false 165 | SpacesInContainerLiterals: true 166 | SpacesInCStyleCastParentheses: false 167 | SpacesInParentheses: false 168 | SpacesInSquareBrackets: false 169 | SpaceBeforeSquareBrackets: false 170 | Standard: Auto 171 | StatementMacros: 172 | - Q_UNUSED 173 | - QT_REQUIRE_VERSION 174 | TabWidth: 8 175 | UseCRLF: false 176 | UseTab: Never 177 | WhitespaceSensitiveMacros: 178 | - STRINGIZE 179 | - PP_STRINGIZE 180 | - BOOST_PP_STRINGIZE 181 | ... 182 | 183 | -------------------------------------------------------------------------------- /src/SwitchControlLibrary/CustomHID.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 celclow 3 | released under the MIT license 4 | https://opensource.org/licenses/mit-license.php 5 | */ 6 | 7 | #include "./CustomHID.h" 8 | 9 | #if defined(USBCON) 10 | 11 | CustomHID_::CustomHID_() {} 12 | 13 | int CustomHID_::SendReport(const void *data, int len) { 14 | auto ret = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len); 15 | return ret; 16 | } 17 | 18 | CustomHID_ &CustomHID() { 19 | static CustomHID_ obj; 20 | return obj; 21 | } 22 | 23 | #endif /* if defined(USBCON) */ 24 | -------------------------------------------------------------------------------- /src/SwitchControlLibrary/CustomHID.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 celclow 3 | released under the MIT license 4 | https://opensource.org/licenses/mit-license.php 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #if defined(USBCON) 12 | 13 | class CustomHID_ : public HID_ { 14 | public: 15 | CustomHID_(); 16 | int SendReport(const void *data, int len); 17 | }; 18 | 19 | CustomHID_ &CustomHID(); 20 | 21 | #endif /* if defined(USBCON) */ 22 | -------------------------------------------------------------------------------- /src/SwitchControlLibrary/SwitchControlLibrary.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 celclow 3 | released under the MIT license 4 | https://opensource.org/licenses/mit-license.php 5 | */ 6 | 7 | #include "./SwitchControlLibrary.h" 8 | 9 | #if defined(_USING_HID) 10 | 11 | static const uint8_t _hidReportDescriptor[] PROGMEM = { 12 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 13 | 0x09, 0x05, // USAGE (Game Pad) 14 | 0xa1, 0x01, // COLLECTION (Application) 15 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 16 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 17 | 0x35, 0x00, // PHYSICAL_MINIMUM (0) 18 | 0x45, 0x01, // PHYSICAL_MAXIMUM (1) 19 | 0x75, 0x01, // REPORT_SIZE (1) 20 | 0x95, 0x10, // REPORT_COUNT (16) 21 | 0x05, 0x09, // USAGE_PAGE (Button) 22 | 0x19, 0x01, // USAGE_MINIMUM (1) 23 | 0x29, 0x10, // USAGE_MAXIMUM (16) 24 | 0x81, 0x02, // INPUT (Data,Var,Abs) 25 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 26 | 0x25, 0x07, // LOGICAL_MAXIMUM (7) 27 | 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) 28 | 0x75, 0x04, // REPORT_SIZE (4) 29 | 0x95, 0x01, // REPORT_COUNT (1) 30 | 0x65, 0x14, // UNIT (20) 31 | 0x09, 0x39, // USAGE (Hat Switch) 32 | 0x81, 0x42, // INPUT (Data,Var,Abs) 33 | 0x65, 0x00, // UNIT (0) 34 | 0x95, 0x01, // REPORT_COUNT (1) 35 | 0x81, 0x01, // INPUT (Cnst,Arr,Abs) 36 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 37 | 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) 38 | 0x09, 0x30, // USAGE (X) 39 | 0x09, 0x31, // USAGE (Y) 40 | 0x09, 0x32, // USAGE (Z) 41 | 0x09, 0x35, // USAGE (Rz) 42 | 0x75, 0x08, // REPORT_SIZE (8) 43 | 0x95, 0x04, // REPORT_COUNT (4) 44 | 0x81, 0x02, // INPUT (Data,Var,Abs) 45 | 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined 65280) 46 | 0x09, 0x20, // USAGE (32) 47 | 0x95, 0x01, // REPORT_COUNT (1) 48 | 0x81, 0x02, // INPUT (Data,Var,Abs) 49 | 0x0a, 0x21, 0x26, // USAGE (9761) 50 | 0x95, 0x08, // REPORT_COUNT (8) 51 | 0x91, 0x02, // OUTPUT (Data,Var,Abs) 52 | 0xc0 // END_COLLECTION 53 | }; 54 | 55 | SwitchControlLibrary_::SwitchControlLibrary_() { 56 | static HIDSubDescriptor node(_hidReportDescriptor, 57 | sizeof(_hidReportDescriptor)); 58 | CustomHID().AppendDescriptor(&node); 59 | 60 | memset(&_joystickInputData, 0, sizeof(USB_JoystickReport_Input_t)); 61 | _joystickInputData.LX = Stick::NEUTRAL; 62 | _joystickInputData.LY = Stick::NEUTRAL; 63 | _joystickInputData.RX = Stick::NEUTRAL; 64 | _joystickInputData.RY = Stick::NEUTRAL; 65 | _joystickInputData.Hat = Hat::NEUTRAL; 66 | } 67 | 68 | void SwitchControlLibrary_::sendReport() { 69 | CustomHID().SendReport(&_joystickInputData, 70 | sizeof(USB_JoystickReport_Input_t)); 71 | } 72 | 73 | void SwitchControlLibrary_::pressButton(uint16_t button) { 74 | _joystickInputData.Button |= button; 75 | } 76 | 77 | void SwitchControlLibrary_::releaseButton(uint16_t button) { 78 | _joystickInputData.Button &= (button ^ 0xffff); 79 | } 80 | 81 | void SwitchControlLibrary_::pressHatButton(uint8_t hat) { 82 | _joystickInputData.Hat = hat; 83 | } 84 | 85 | void SwitchControlLibrary_::releaseHatButton() { 86 | _joystickInputData.Hat = Hat::NEUTRAL; 87 | } 88 | 89 | void SwitchControlLibrary_::moveLeftStick(uint8_t lx, uint8_t ly) { 90 | _joystickInputData.LX = lx; 91 | _joystickInputData.LY = ly; 92 | } 93 | 94 | void SwitchControlLibrary_::moveRightStick(uint8_t rx, uint8_t ry) { 95 | _joystickInputData.RX = rx; 96 | _joystickInputData.RY = ry; 97 | } 98 | 99 | SwitchControlLibrary_ &SwitchControlLibrary() { 100 | static SwitchControlLibrary_ obj; 101 | return obj; 102 | } 103 | 104 | #endif -------------------------------------------------------------------------------- /src/SwitchControlLibrary/SwitchControlLibrary.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 celclow 3 | released under the MIT license 4 | https://opensource.org/licenses/mit-license.php 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "./CustomHID.h" 10 | 11 | struct Button { 12 | static const uint16_t Y = 0x0001; 13 | static const uint16_t B = 0x0002; 14 | static const uint16_t A = 0x0004; 15 | static const uint16_t X = 0x0008; 16 | static const uint16_t L = 0x0010; 17 | static const uint16_t R = 0x0020; 18 | static const uint16_t ZL = 0x0040; 19 | static const uint16_t ZR = 0x0080; 20 | static const uint16_t MINUS = 0x0100; 21 | static const uint16_t PLUS = 0x0200; 22 | static const uint16_t LCLICK = 0x0400; 23 | static const uint16_t RCLICK = 0x0800; 24 | static const uint16_t HOME = 0x1000; 25 | static const uint16_t CAPTURE = 0x2000; 26 | }; 27 | 28 | struct Hat { 29 | static const uint8_t UP = 0x00; 30 | static const uint8_t UP_RIGHT = 0x01; 31 | static const uint8_t RIGHT = 0x02; 32 | static const uint8_t DOWN_RIGHT = 0x03; 33 | static const uint8_t DOWN = 0x04; 34 | static const uint8_t DOWN_LEFT = 0x05; 35 | static const uint8_t LEFT = 0x06; 36 | static const uint8_t UP_LEFT = 0x07; 37 | static const uint8_t NEUTRAL = 0x08; 38 | }; 39 | 40 | struct Stick { 41 | static const uint8_t MIN = 0; 42 | static const uint8_t NEUTRAL = 128; 43 | static const uint8_t MAX = 255; 44 | }; 45 | 46 | typedef struct { 47 | uint16_t Button; 48 | uint8_t Hat; 49 | uint8_t LX; 50 | uint8_t LY; 51 | uint8_t RX; 52 | uint8_t RY; 53 | uint8_t VendorSpec; 54 | } USB_JoystickReport_Input_t; 55 | 56 | class SwitchControlLibrary_ { 57 | private: 58 | USB_JoystickReport_Input_t _joystickInputData; 59 | 60 | public: 61 | SwitchControlLibrary_(); 62 | 63 | void sendReport(); 64 | 65 | void pressButton(uint16_t button); 66 | void releaseButton(uint16_t button); 67 | 68 | void pressHatButton(uint8_t hat); 69 | void releaseHatButton(); 70 | 71 | void moveLeftStick(uint8_t lx, uint8_t ly); 72 | void moveRightStick(uint8_t rx, uint8_t ry); 73 | }; 74 | 75 | SwitchControlLibrary_ &SwitchControlLibrary(); 76 | --------------------------------------------------------------------------------