要約
キャンペーンサイトへPCからスマホサイズでアクセスし、WebブラウザのコンソールからJavaScriptでフリック入力を再現した。
ソースコード: https://github.com/r-yanyo/flick-challenge/blob/master/newfuga.js
キャンペーンサイト: https://cp.zone-energy.jp/challenge/kuma/
キャンペーンサイトのconsoleにソースコードを貼り付けると(途中まで)フリック入力が自動的に入力されます(途中までの理由は最後の方に書いてます)。
PCでスマートフォン専用サイトにアクセスする
PCでキャンペーンページを普通に開くと、スマートフォン専用サイトである旨が表示されます。
このままではPCでフリック入力ゲームで遊ぶことが出来ません。
同じWebサイトでも、PCでアクセスした時とスマートフォンでアクセスした時にWebページのデザインが違う経験があるのではないでしょうか?これは、デバイスに依存してWebサイトの表示を変更する場合に、一般的にメディアクエリ が基準として使用されるからです。
メディアクエリはユーザが使用しているデバイスのViewport
(ウィンドウのサイズ)を基準として、Webサイトの表示を変更する方法です。つまり、実際にPCやスマートフォンのどちらを使用しているかは検証しておらず、ウィンドウのサイズだけで判断しています。よって、何らかの方法でウィンドウサイズを変更すれば、PCでもスマートフォン専用ページにアクセスすることが出来ます。
Google Chromeでは、デベロッパーツールを開き、Device Toolbarを使用することでウィンドウのサイズをスマートフォンサイズに変更できます。
フリック入力をプログラミングで再現する
大きく分けて工程は3つあります。
1. ひらがなボタンのElementを取得
2. 取得したElementに対してフリック入力を再現
3. 答えを機械が認識できる形で入力&変換
1. ひらがなボタンのElementを取得
デベロッパーツールで見てみると、どうやら.css-xx1yz5-buttonStyle
というクラスが各「あかさたなはまやらわ」ボタンに付与されているようです。
さらに、そのボタンをタップすると出現するフリック入力部分("あ"をタップした場合は「あいうえお」)には.css-2rzvda-wingStyle
というクラスが付与されています。
このことから、例えばキーボードの「さ」を取得したいときは、
[0]: "あ", [1]: "か", [2]: "さ"
なので
document.getElementsByClassName("css-xx1yz5-buttonStyle")[2]
フリック入力の「す」を取得したいときは、「す」は上から13番目なので
document.getElementsByClassName("css-2rzvda-wingStyle")[12]
とします。
ひらがな以外の文字に関しては、デベロッパーツールでその要素が上から何個目にあるかを見れば分かります。
2. 取得したElementに対してフリック入力を再現
初めはClickイベントでフリック入力が再現されると思ったのですが、
document.getElementsByClassName("css-xx1yz5-buttonStyle")[2].click()
のようにしても何も起こりませんでした。
そこで次に、TouchEvent を試したところ、キーボードのボタンがタッチされるイベントが発生しました。よって、このTouchEventを使うことにしました。
//elmはフリックの起点となるelement。「す」を入力するときは「さ」
//moveElmはフリック先のelement。「す」を入力するときは「す」
touchMove = function (elm, moveElm) {
if (!moveElm) return;
rect = moveElm.getBoundingClientRect();
X = rect.x + rect.width / 2;
Y = rect.y + rect.height / 2;
let touch = new Touch({
identifier: Date.now(),
target: elm,
clientX: X,
clientY: Y,
force: 1,
pageX: X,
pageY: Y,
radiusX: 41.66666793823242,
radiusY: 41.66666793823242,
rotationAngle: 0,
});
touchMoveEvent = new TouchEvent("touchmove", {
bubbles: true,
touches: [touch],
});
elm.dispatchEvent(touchMoveEvent);
};
TouchEventに関してはあまり詳しくなかったため、実際にイベントを発生させて必要な部分だけを変更する戦略を取りました。
結果的には clientX
,clietnY
,pageX
,pageY
の数値をフリック先のelementの座標に変えることで、フリック入力を再現することが出来ました。
フリック入力をするときにTouchEventで発生するイベントは、touchstart
-> touchmove
-> touchend
の順で発生します。また、それぞれのイベントの発生元は全てフリックの起点となるelementで発火します。1
//elmはフリックの起点となるelement。「す」を入力するときは「さ」
//moveElmはフリック先のelement。「す」を入力するときは「す」
function touchEmulate(startElement, moveElm) {
touchStart(elm);
touchMove(elm, moveElm); //イベント発火元はelm
touchEnd(elm);
}
3. 答えを機械が認識できる形で入力&変換
「ひらがな」から数字への変換は愚直に一つ一つ入力しました。
"あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもや(ゆ)よらりるれろわをんー 、。?!".split("")
例えば「す」をフリック入力したい場合は、
//「さ」ボタン
const button = document.getElementsByClassName("css-xx1yz5-buttonStyle")[2];
//「す」フリック
const flick = document.getElementsByClassName("css-xx1yz5-buttonStyle")[12];
このように「あ」〜「ん」や「!?」の記号などは入力できるようになりました。
ここで問題となるのが、濁音や半濁音、促音(「が」、「ぱ」、「っ」など)の入力です。これらはフリック入力を2回行う必要があります。例えば、「が」であれば、「か」をフリックした後に「゛」をフリックする必要があります。
これを解決する方法は色々あるのですが、今回は全部条件分岐で書きました(具体的にはソースコード参照)。2
「これで晴れてフリック入力がエミュレート出来た・・・」と思ったのですが、もう1つ問題があります。
フリック入力では同じボタンを2回押すと次の文字が表れるという特性上、連続で同じ文字を入力しようとすると正しい文字が入力されません。
例えば、「けたたましく」を入力しようとすると「けちましく」になってしまいます。
この問題はキーボードにある「→」ボタンを入力すれば解決できますが、当時の私は気付かなかったため手動で入力を分けて解決しました(ダサい・・・)。
おわりに
以上でフリック入力をエミュレートすることが出来ました。便宜上「ハックした」と書いていますが、JavaScriptでフリック入力をエミュレートしただけです。
キャンペーンは終了してしまいましたが、まだゲームで遊ぶことはできるようなので、是非実際に試してみてください。