3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

身の回りの困りごとを楽しく解決! by Works Human IntelligenceAdvent Calendar 2024

Day 15

"Xのだるま"を「↑↑↓↓←→←→BA」せずに1クリックで回すChrome拡張を作ってみた #コナミコマンド

Last updated at Posted at 2024-12-25

メリークリスマス :) Xでダルマが回せる のが話題ですね。 (なぜダルマなのか。。。)

X(旧Twitter)で、コナミコマンド(上上下下左右左右BA)を入力すると、サイト上部のロゴが回転する機能が(この冬限定かな?)実装されています。これを自動的に実行できるChrome拡張機能を作ってみました。 12/25に知って12/25に作ってるのでかなり勢い ですね。

先に作ったものを載せておきます。

"身の回りの困りごとを楽しく解決アドベントカレンダー"の記事です。

コナミコマンドでダルマとXロゴを回せる

まず基本ですが、"上上下下左右左右BA(↑↑↓↓←→←→BA)"をXの画面上で入力するとダルマが回転します。

こんな感じで、コナミコマンドをうまく入力できるとダルマが...!

コナミコマンド?

ギネスにも載ってるらしい有名な裏技コマンドです。

色々なサイトにギミックとして実装されてるっぽいです。PHP.netで試したら実装されてましたね。

"クレヨンしんちゃん 雲黒斎の野望"のラストのロボットバトルで似たようなギミックありましたね(世代)

コナミコマンド難しいので半自動化

さて本題。

コナミコマンド結構難しいなと思ってまして、 ゆっくり入力すぎるとコマンドとして認識されない です。あと 上上下下だっけ下下上上だっけ、、、?と間違えることも多々 あります。

困りごと解決アドベントカレンダーの記事ということで解決を試みます。


テストバージョン、ボタンを押すと回る。ここまで行くのもちょっとハマりました。

作ってみたログ

Chrome拡張機能でおそらくキー入力のエミュレートいけるだろうと思い作ってみました。

感情コードは記事の最後の方にGitHubに挙げておきます。

1. まずはキー入力をエミュレート

最初は単純なキーボードイベントのエミュレートからスタート

document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }));

しかし、これだけでは動作せず。

2. コナミコマンドのシーケンスを実装

次に、全てのキー入力を順番に実行するように改良:

['ArrowUp','ArrowUp','ArrowDown','ArrowDown','ArrowLeft','ArrowRight','ArrowLeft','ArrowRight','b','a'].forEach((key, i) => setTimeout(() => document.dispatchEvent(new KeyboardEvent('keydown', {key})), i * 100));

この段階でも、まだうまく動作しません。

3. イベントの種類を増やす

割と全然うごかんなーと悩んでましたけど、キーボードイベントには keydown、keypress、keyup の3種類があることに気づき、全てのイベントを送信するように修正してみました。

割と諦めかけ(そこまで時間かけたわけではないけどこのネタにどこまで時間かけるのか問題)

document.documentElement.dispatchEvent(createKeyEvent('keydown', key));
document.documentElement.dispatchEvent(createKeyEvent('keypress', key));
document.documentElement.dispatchEvent(createKeyEvent('keyup', key));

この段階で一旦動きました。

4. 複数回の回転に挑戦

1回の回転には成功したので、次は連続して3回回転させることに挑戦。しかし、ここでも問題が発生

  • 2周目の途中でリセットされる
  • アニメーションが重なって不自然
  • 回転が途中で止まる

2周目いくのときの挙動が割と不安定だった感じです。

5. タイミングの最適化

だるまの要素を見たら回転しているときにclassが付与されてアニメーション指定がありました。

スクリーンショット 2024-12-25 19.44.59.png

CSSを確認すると、transform 1sでアニメーション時間が1秒(1000ms)に設定されていることが判明。試行錯誤の結果、1024msのインターバルを設けることで滑らかな連続回転を実現できました。

ということで一旦の完成コード

動かんな、、、原因なんだろう、、、という試行錯誤はありましたが結果コード自体は95%くらいClaudeに書いてもらいました。

document.addEventListener('DOMContentLoaded', () => {
  document.getElementById('konami').addEventListener('click', async () => {
    const rotations = parseInt(document.getElementById('rotations').value) || 3;
    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      args: [rotations],
      func: (totalRotations) => {
        const sequence = [
          'ArrowUp', 'ArrowUp',
          'ArrowDown', 'ArrowDown',
          'ArrowLeft', 'ArrowRight',
          'ArrowLeft', 'ArrowRight',
          'b', 'a'
        ];
        
        function createKeyEvent(type, key) {
          return new KeyboardEvent(type, {
            key: key,
            code: key.startsWith('Arrow') ? key : `Key${key.toUpperCase()}`,
            keyCode: key === 'a' ? 65 : key === 'b' ? 66 : 
                    key === 'ArrowUp' ? 38 : key === 'ArrowDown' ? 40 : 
                    key === 'ArrowLeft' ? 37 : key === 'ArrowRight' ? 39 : 0,
            bubbles: true,
            cancelable: true,
            view: window
          });
        }

        function runSequence(round) {
          if (round >= totalRotations) return;
          
          let currentKey = 0;
          function emitKey() {
            if (currentKey >= sequence.length) {
              console.log(`シーケンス ${round + 1}/${totalRotations} 完了`);
              setTimeout(() => runSequence(round + 1), 1024);
              return;
            }

            const key = sequence[currentKey];
            console.log(`ラウンド ${round + 1}/${totalRotations}: キー入力: ${key} (${currentKey + 1}/${sequence.length})`);

            document.documentElement.dispatchEvent(createKeyEvent('keydown', key));
            document.documentElement.dispatchEvent(createKeyEvent('keypress', key));
            document.documentElement.dispatchEvent(createKeyEvent('keyup', key));

            currentKey++;
            setTimeout(emitKey, 1);
          }

          emitKey();
        }

        runSequence(0);
      }
    });
  });
});

ログにも出しつつデバッグしてました。

まとめ

コナミコマンドをエミュレートすることで誰でもXのダルマを回せる拡張機能を作りました。

ストアにも申請してみたので公開されたらリンク貼ります。リジェクトされないといいな。

個人的な身近な困りごと(コナミコマンド難しい)、解決できました★

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?