c++ builder XE4, 10.2 Tokyo > 半自動 > タブ表示した複数のPDFファイルをアニメーション表示 > Chromeを操作して実施

```txt:動作確認
C++ Builder XE4
  Chrome バージョン 54.0.2840.71 m
  Windows7

RAD Studio 10.2 Tokyo Update 2 (追記: 2017/12/28)
  v0.6の動作確認済
```

たくさんのPDF出力のチェックを半自動化したい。

http://qiita.com/7of9/items/b116bef47f8210bbb3c9#chrome%E4%BD%BF%E7%94%A8

マニュアル動作は単調作業だと誤操作してしまう。
半自動でできないだろうか。

### v0.1 > タブ送りだけ

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Sleep(1000);

	for(int loop=0; loop<10; loop++) {
        Sleep(300);
		keybd_event(VK_CONTROL, 0, 0, 0);
		keybd_event(VK_TAB, 0, 0, 0);
		keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
	}

	keybd_event(VK_RETURN, 0, 0, 0);
}
//---------------------------------------------------------------------------
```

使い方

0. Chromeに複数タブを立ち上げた状態にする
  - 例: PDFファイルをタブで開いた状態
1. Button1をクリック
2. 1秒以内にChromeを選択
3. 後はじっと見る

Chromeのウィンドウを自動フォーカスする機能があれば便利だが、とりあえず上の方法で間に合わせる。

### 注意点

処理が終わる前にC++ Builderに移ると、そこでタブ移動が処理されるので、気持ち悪くなる。

処理終了まで待つのがよいかと。

## v0.2 ページ送り追加

Chromeではスペースでページ送りができるので、それを追加した。

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Sleep(1000);

	static const int kNum_tabs = 7;
	static const int kLoop_inner = 5;
	static const int kLoop_page = 3;


	for(int loop_page=0; loop_page < kLoop_page; loop_page++) {
		for(int loop_inner=0; loop_inner < kLoop_inner; loop_inner++) {
			for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
				Sleep(300);
				keybd_event(VK_CONTROL, 0, 0, 0);
				keybd_event(VK_TAB, 0, 0, 0);
				keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
			}
		}
		for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
			keybd_event(VK_SPACE, 0, 0, 0);
			Sleep(300);
			keybd_event(VK_CONTROL, 0, 0, 0);
			keybd_event(VK_TAB, 0, 0, 0);
			keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
		}
	}

	keybd_event(VK_RETURN, 0, 0, 0);
}
//---------------------------------------------------------------------------
```

## v0.3 ページ巻き戻し機能追加 (rewind)

Shift+Spaceでページ巻き戻しできるので。

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// Chromeにフォーカスを移すまで1秒とする
	Sleep(1000);

	static const int kNum_tabs = 7;
	static const int kLoop_inner = 5;
	static const int kLoop_page = 3;

	// 1. ページrewind
	for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
		Sleep(300);
		for(int loop_page=0; loop_page < kLoop_page; loop_page++) {
			// ページrewind
			keybd_event(VK_SHIFT, 0, 0, 0);
			keybd_event(VK_SPACE, 0, 0, 0);
			//
			keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); // これがないとShiftを押したままになる
		}
		keybd_event(VK_CONTROL, 0, 0, 0);
		keybd_event(VK_TAB, 0, 0, 0);
		keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
	}

	// 2. タブ切り替え + ページ送り
	for(int loop_page=0; loop_page < kLoop_page; loop_page++) {
		for(int loop_inner=0; loop_inner < kLoop_inner; loop_inner++) {
			for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
				Sleep(300);
				keybd_event(VK_CONTROL, 0, 0, 0);
				keybd_event(VK_TAB, 0, 0, 0);
				keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
			}
		}
		for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
			keybd_event(VK_SPACE, 0, 0, 0); // ページ送り
			Sleep(300);
			keybd_event(VK_CONTROL, 0, 0, 0);
			keybd_event(VK_TAB, 0, 0, 0);
			keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
		}
	}

	keybd_event(VK_RETURN, 0, 0, 0);
}
//---------------------------------------------------------------------------
```


## v0.4 ページ縮尺調整追加 (一応完成)

Ctrl+"-"(ページ縮小)"とCtrl+"+"(ページ拡大)を追加。
こちらの環境では50%の縮尺になるようになった。

一応希望機能は実装完了。
あとはstatic const宣言のパラメータを変更して、自分の使いたい環境に合わせる。

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// Chromeにフォーカスを移すまで1秒とする
	Sleep(1000);

	static const int kNum_tabs = 6; // 表示したいタブ(PDFファイル)の数
	static const int kLoop_inner = 5; // 1つのタブを何週見たいか
	static const int kLoop_page = 3; // タブ(PDFファイル)のページ数
	static const int kNum_shrink = 10; // 縮小コマンド送信回数 (最小になる回数にする)
	static const int kNum_enlarge = 3; // 拡大コマンド送信回数 (3で50%の表示になった)

	// 1. ページ調整
	for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
		Sleep(300);
		for(int loop_shrink=0; loop_shrink < kNum_shrink; loop_shrink++) {
			Sleep(100);
			// ページrewind
			keybd_event(VK_CONTROL, 0, 0, 0);
			keybd_event(VK_SUBTRACT, 0, 0, 0);
			//
			keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
		}
		for(int loop_enlarge=0; loop_enlarge < kNum_enlarge; loop_enlarge++) {
			Sleep(100);
			// ページrewind
			keybd_event(VK_CONTROL, 0, 0, 0);
			keybd_event(VK_ADD, 0, 0, 0);
			//
			keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
		}
		// Tab送り
		keybd_event(VK_CONTROL, 0, 0, 0);
		keybd_event(VK_TAB, 0, 0, 0);
		keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
	}

	// 2. ページrewind
	for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
		Sleep(300);
		for(int loop_page=0; loop_page < kLoop_page; loop_page++) {
			// ページrewind
			keybd_event(VK_SHIFT, 0, 0, 0);
			keybd_event(VK_SPACE, 0, 0, 0);
			//
			keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); // これがないとShiftを押したままになる
		}
		keybd_event(VK_CONTROL, 0, 0, 0);
		keybd_event(VK_TAB, 0, 0, 0);
		keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
	}

	// 3. タブ切り替え + ページ送り
	for(int loop_page=0; loop_page < kLoop_page; loop_page++) {
		for(int loop_inner=0; loop_inner < kLoop_inner; loop_inner++) {
			for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
				Sleep(300);
				keybd_event(VK_CONTROL, 0, 0, 0);
				keybd_event(VK_TAB, 0, 0, 0);
				keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
			}
		}
		for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
			keybd_event(VK_SPACE, 0, 0, 0); // ページ送り
			Sleep(300);
			keybd_event(VK_CONTROL, 0, 0, 0);
			keybd_event(VK_TAB, 0, 0, 0);
			keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
		}
	}

	keybd_event(VK_RETURN, 0, 0, 0);
}
//---------------------------------------------------------------------------
```

## v0.6 リファクタリング

v0.5において、チェックボックスを押した時点で処理を抜けるようにした。
v0.6にてリファクタリングした。

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

/*
v0.6 2016/10/26
	- リファクタリング
v0.5 2016/10/26
	- 停止用チェックボックス処理追加
	- Application->ProcessMessages();追加
v0.4 2016/10/26
	- ページ縮尺調整機能実装
v0.3 2016/10/26
	- ページ巻き戻し機能実装
v0.2 2016/10/26
	- ページ送り機能実装
v0.1 2016/10/26
	- タブ送り機能実装

*/

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::moveTab()
{
	keybd_event(VK_CONTROL, 0, 0, 0);
	keybd_event(VK_TAB, 0, 0, 0);
	keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
}

void __fastcall TForm1::shrinkPage()
{
	keybd_event(VK_CONTROL, 0, 0, 0);
	keybd_event(VK_SUBTRACT, 0, 0, 0);
	keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
}

void __fastcall TForm1::enlargePage()
{
	keybd_event(VK_CONTROL, 0, 0, 0);
	keybd_event(VK_ADD, 0, 0, 0);
	keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // これがないとControlを押したままになる
}

void __fastcall TForm1::rewindPage()
{
	keybd_event(VK_SHIFT, 0, 0, 0);
	keybd_event(VK_SPACE, 0, 0, 0);
	keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); // これがないとShiftを押したままになる
}

void __fastcall TForm1::delay(int msec)
{
	Sleep(msec);
	Application->ProcessMessages();
}


void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// Chromeにフォーカスを移すまで1秒とする
	delay(1000);

	static const int kNum_tabs = 10; // 表示したいタブ(PDFファイル)の数
	static const int kLoop_inner = 5; // 1つのタブを何週見たいか
	static const int kLoop_page = 7; // タブ(PDFファイル)のページ数
	static const int kNum_shrink = 10; // 縮小コマンド送信回数 (最小になる回数にする)
	static const int kNum_enlarge = 3; // 拡大コマンド送信回数 (3で50%の表示になった)

	// 1. ページ縮尺の調整
	for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
		delay(300);
		for(int loop=0; loop < kNum_shrink; loop++) {
			delay(100);
			if (CHK_stop->Checked) {
				return;
			}
			shrinkPage();
		}
		for(int loop=0; loop < kNum_enlarge; loop++) {
			delay(100);
			if (CHK_stop->Checked) {
				return;
			}
			enlargePage();
		}
		moveTab();
	}

	// 2. ページrewind
	for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
		delay(300);
		for(int loop=0; loop < kLoop_page; loop++) {
			if (CHK_stop->Checked) {
				return;
			}
			rewindPage();
		}
		moveTab();
	}

	// 3. タブ切り替え + ページ送り
	for(int loop_page=0; loop_page < kLoop_page; loop_page++) {
		for(int loop_inner=0; loop_inner < kLoop_inner; loop_inner++) {
			for(int loop=0; loop < kNum_tabs; loop++) {
				if (CHK_stop->Checked) {
					return;
				}
				delay(300);
				moveTab();
			}
		}
		for(int loop_tab=0; loop_tab < kNum_tabs; loop_tab++) {
			keybd_event(VK_SPACE, 0, 0, 0); // ページ送り
			delay(300);
			if (CHK_stop->Checked) {
				return;
			}
			Application->ProcessMessages();
			moveTab();
		}
	}

	keybd_event(VK_RETURN, 0, 0, 0);
}
//---------------------------------------------------------------------------
```

## 使い方 (再掲)

### 使い方

0. Chromeに複数タブを立ち上げた状態にする
  - 例: PDFファイルをタブで開いた状態
  - タブの数はkNum_tabsと合わせること
1. Button1をクリック
2. 1秒以内にChromeを選択
3. 後はじっと見るだけ

Chromeのウィンドウを自動フォーカスする機能があれば便利だが、とりあえず上の方法で間に合わせる。

### 注意点

処理が終わる前にC++ Builderに移ると、そこでタブ移動が処理されるので、気持ち悪くなる。

処理終了まで待つのがよいかと。

ページ切り替え時は見ていて疲れる。人間工学的にはまだまだ。