【SeleniumVBA】SendKeysとJavaScriptの文字入力について考える

# はじめに
テキストボックスに文字入力する方法は標準の**SendKeys**のほか、**JavaScript**による文字入力を行う方法もある。それぞれの方法にメリット/デメリットはないのか、実際に検証することとした。

# 検証方法
検証用サイトとして、[PHP & JavaScript Room](https://phpjavascriptroom.com/?t=js&p=event#a_onkeyup)の「onKeyDownの使用例」をお借りして、以下の画像の入力フォームを利用した。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3972727/8b17289d-7255-62d2-196d-d8ca398f3e01.png)

:::note
上の入力欄に文字入力してEnterキーを押すと、イベントが発火して下の欄に入力した文字を表示するようになっている。
:::

# 検証コード
標準モジュールに記述した下記コードにより【事例１】から【事例４】の方法を用いて、**「あ」を1000回連続させた文字**をテキストボックスに入力した。**下記コードをコピーして、新規の標準モジュールに貼り付けると動作確認が可能**。

:::note
もし、SeleniumVBAがまったく初めての方は、[こちら](https://note.com/sele_chan/n/n61a67c4379de)の記事を参考に**新規の標準モジュール作成**まで行う。
:::

<table>
 <thead>
    <tr>
      <th>事例</th><th>方法</th><th>説明</th>
    </tr>
  </thead>
  <tr>
    <td>1</td><td>JavaScript</td><td>JavaScriptでの文字代入</td>
  </tr>
  <tr>
    <td>2</td><td>JavaScript<br>(dispatchEvent付)</td><td>JavaScriptでの文字代入に加え、dispatchEventによるイベント強制発火</td>
  </tr>
   <tr>
    <td>3</td><td>SendKeys(クリップボード経由)</td><td>SendKeysでのクリップボード経由による文字代入</td>
  </tr>
  <tr>
    <td>4</td><td>SendKeys</td><td>SendKeysでの直接文字代入</td> 
</table>

```vb:VBA
Option Explicit
Sub A_Sendkeys()
    Dim driver As SeleniumVBA.WebDriver
    Set driver = SeleniumVBA.New_WebDriver

With driver
    .StartChrome
    .OpenBrowser
    .ImplicitMaxWait = 2000
    .NavigateTo "https://phpjavascriptroom.com/?t=js&p=event#a_onkeyup"
       
    Dim elmfound As WebElement
    Dim startTime As Double
    Dim endTime As Double
   '入力文字を変数に格納
    Dim str As String
    str = String(1000, "あ") '「あ」を1000回繰り返す
    'テキストボックス
    If .IsPresent(By.XPath, "//input[@onkeydown='fCopy(this.form)']", 2000, , elmfound) = False Then Stop
    
    '【事例１】JavaScriptの場合
    startTime = Timer
    .ExecuteScript "arguments[0].value= arguments[1];", elmfound, str
    endTime = Timer
    Debug.Print "事例１の処理時間は" & endTime - startTime & "秒"
    
    
    '【事例２】JavaScriptの場合(dispatchEvent)
    startTime = Timer
    Dim strScript As String
    strScript = "arguments[0].value= arguments[1];"
    strScript = strScript & "arguments[0].dispatchEvent(new Event('keydown'));"
    .ExecuteScript strScript, elmfound, str
    endTime = Timer
    Debug.Print "事例２の処理時間は" & endTime - startTime & "秒"
       
    '【事例３】SendKeys クリップボード経由の場合（最も安全なテキストボックス使用）
    startTime = Timer
    Dim keys As SeleniumVBA.WebKeyboard: Set keys = SeleniumVBA.New_WebKeyboard
    Dim objForm As Object: Set objForm = CreateObject("Forms.TextBox.1")
    objForm.MultiLine = True: objForm.text = str
    objForm.SelStart = 0: objForm.SelLength = objForm.textLength
    objForm.Copy: Set objForm = Nothing  'クリップボードにコピー
    elmfound.SendKeys keys.CtrlKey & "v", True '「Ctrl+V」で貼り付け
    endTime = Timer
    Debug.Print "事例３の処理時間は" & endTime - startTime & "秒"
    
    '【事例４】SendKeys 引数に直接文字を指定した場合
    startTime = Timer
    elmfound.SendKeys str, True
    endTime = Timer
    Debug.Print "事例４の処理時間は" & endTime - startTime & "秒"
    
    .CloseBrowser
    .Shutdown
    
End With
End Sub
```
:::note
処理時間計測結果はイミディエイトウインドウに表示される
:::

# 検証結果
結果は以下のとおりとなった。

## １ 速度
・　速い【事例１】【事例２】【事例３】
・　遅い【事例４】

## ２ イベント発現の有無
・　発現なし【事例１】
・　発現あり【事例２】【事例３】【事例４】

## ３ コード量（メンテナンス性）
・　最も少ない【事例４】
・　少ない【事例１】
・　多い【事例２】
・　かなり多い【事例３】

# まとめ
まずは、**手動動作の再現性が保証されるSendKeysの利用を考える**が、処理速度を優先したい場合はJavaScriptの選択もありうる。
<table>
 <thead>
    <tr>
      <th>順位</th><th>方法</th><th>説明</th>
    </tr>
  </thead>
  <tr>
    <td>2</td><td>JavaScript</td><td>処理速度を最優先し、その後の動作に支障がない場合に選択</td>
  </tr>
  <tr>
    <td>3</td><td>JavaScript<br>(dispatchEvent付)</td><td>イベント発火を必要とする場合で、dispatchEventが記述できる場合に選択可能であるが、複雑になる</td>
  </tr>
   <tr>
    <td>3</td><td>SendKeys(クリップボード経由)</td><td>処理速度は向上するが、複雑になるうえクリップボードの使用自体に不安感は残る</td>
  </tr>
  <tr>
    <td>1</td><td>SendKeys</td><td>手動動作の再現性が保証されるため、第１順位となる</td> 
</table>

:::note
ちなみに、私の環境ではイベント発生を必要とせず、処理速度向上が必須であっため、JavaScript使用を選択しています。
:::


# おわりに
この記事における動作確認は2025年1月17日時点です。
最後に、最適な検証材料を公開していただいた[PHP & JavaScript Room](https://phpjavascriptroom.com/)様、どうもありがとうございました。