procedure TForm1.chkPWClick(Sender: TObject);
begin
if chkPW.Checked then
begin
EditPW.PasswordChar := #0;
end else begin
EditPW.PasswordChar := '*';
end;
end;
procedure TForm1.chkZahyoClick(Sender: TObject);
begin
if chkZahyo.Checked then
begin
//Enabled
Timer1.Enabled:=True;
end else begin
//Enabled
Timer1.Enabled:=False;
LabelXY.Caption:='[X座標, Y座標]';
end;
end;
この本「徹底活用ブック」と銘打つだけあって、ThinkPad220に関するありとあらゆる情報が掲載されている感があり、どこから読んでも面白い本だった。新幹線の車内で電源を確保する方法など「こんなことやって、ほんとに大丈夫なのか?」と思っちゃったりもしたけど、そのゲーム機としての利用案内で知ったのが「Microsoft Flight Simulator Version 4」
(こんなん、あるんだー!)
それが「Flight Simulator」なるモノと、僕の出会いだった。
FS2020
FS98、FS2004どちらも楽しく遊べた。FS2004はWindowsXP時代のソフトで、インストールディスクなしで動かすには fs9.exe そのものを入れ替えるという裏技も必要だったりしたけど、ヤフオクで「Microsoft Force FeedBack2」なるジョイスティックも入手。現実世界では絶対に実現できない「火酒」を片手に操縦桿を握るという楽しみも、僕はこのFS2004で覚えた・・・。
procedure TForm1.chkSettingClick(Sender: TObject);
begin
if chkSetting.Checked then
begin
LabelID.Visible:=True;
btnCopy.Visible:=True;
btnCopy.Enabled:=True;
Edit1.Visible:=True;
LabelX.Visible:=True;
EditX.Visible:=True;
LabelY.Visible:=True;
EditY.Visible:=True;
btnSave.Visible:=True;
chkZahyo.Visible:=True;
LabelXY.Visible:=True;
LabelWaitTime.Visible:=True;
cmbWaitTime.Visible:=True;
end else begin
LabelID.Visible:=False;
btnCopy.Visible:=False;
Edit1.Visible:=False;
LabelX.Visible:=False;
EditX.Visible:=False;
LabelY.Visible:=False;
EditY.Visible:=False;
btnSave.Visible:=False;
chkZahyo.Visible:=False;
LabelXY.Visible:=False;
LabelWaitTime.Visible:=False;
cmbWaitTime.Visible:=False;
end;
end;
(3)入力値の保存/読み込みと暗号化
各VCLコントロールに入力された値は、必要な個所は暗号化してiniファイルに保存する。
uses
System.IniFiles;
procedure TForm1.btnSaveClick(Sender: TObject);
var
strID:string;
Ini:TIniFile;
begin
//入力の有無をCheck
if Edit1.Text='' then
begin
MessageDlg('IDとして利用するメールアドレスを入力してください', mtInformation, [mbOk] , 0);
Edit1.SetFocus;
Exit;
end;
if (EditX.Text='') or (EditY.Text='') then
begin
if EditX.Text='' then
begin
MessageDlg('自動クリックするX座標を入力してください', mtInformation, [mbOk] , 0);
EditX.SetFocus;
end;
if EditY.Text='' then
begin
MessageDlg('自動クリックするY座標を入力してください', mtInformation, [mbOk] , 0);
EditY.SetFocus;
end;
Exit;
end;
if cmbWaitTime.Text='' then
begin
MessageDlg('カーソル移動の待機時間をミリ秒単位で入力してください', mtInformation, [mbOk] , 0);
cmbWaitTime.SetFocus;
Exit;
end;
//暗号化
strID:=EDText(Edit1.Text, IntToStr(HashOf('XXXXXXXX')), True);
//iniファイルに保存
Ini := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
//保存
Ini.WriteString('Section', 'ID', strID);
Ini.WriteString('Section', 'IchiX', EditX.Text);
Ini.WriteString('Section', 'IchiY', EditY.Text);
Ini.WriteString('Section', 'WaitTime', cmbWaitTime.Text);
//Userに通知
MessageDlg('現在の設定を保存しました!', mtInformation, [mbOk] , 0);
if not btnCopy.Enabled then btnCopy.Enabled:=True;
finally
Ini.Free;
end;
end;
コードの中で使用しているEDText関数はテキスト暗号化の関数。
private
{ Private 宣言 }
//HashNameMBCS(Create hashed values from a Unicode string)
//MBCS:Multibyte Character Set=マルチバイト文字セット
function HashOf(const key: string): cardinal;
//テキスト暗号化/復号化
Function EDText(KeyStr,PassW:string; EncOrDec:Boolean):string;
//KeyStr:平文 or 暗号化文のいずれかを指定
//PassW:パスワード
//EncOrDec:True -> Encode / False -> Decode
public
{ Public 宣言 }
end;
function TForm1.HashOf(const key: string): cardinal;
var
I: integer;
begin
Result := 0;
for I := 1 to length(key) do
begin
Result := (Result shl 5) or (Result shr 27);
Result := Result xor Cardinal(key[I]);
end;
end;
function TForm1.EDText(KeyStr, PassW: string; EncOrDec: Boolean): string;
var
{暗号化用変数}
Source, Dest, Password:TStringBuilder;
lpSource, lpPass:Integer;
PassValue, SourceValue, EDValue:Word;
{共用変数}
//乱数の種
Seed1,Seed2,Seed3:integer;
//実数の一様乱数
RandNum:Double;
//秘密鍵Seed
Seed:string;
{復号化用変数}
DecSource:string;
begin
//1.シード値を準備
// (1)Passwordを整数へ変換→シード値1へ代入
Password := TStringBuilder.Create;
//Seed1を初期化
//Seed1:=0;
try
Password.Append(PassW);
PassValue := 0;
for lpPass := 0 to Password.Length - 1 do
begin
//パスワード→整数
PassValue := PassValue + Word(Password.Chars[lpPass]);
end;
Seed1:=PassValue;
finally
Password.Free;
end;
// (2)パスワード文字列の長さを取得→シード値2へ代入
Seed2:= ElementToCharLen(PassW,Length(PassW));
// (3)シード値1とシード値2の排他的論理和を計算して、シード値3へ代入
Seed3 := Seed1 xor Seed2;
//2.実数の一様乱数を計算
//---------------------------------------------------------------------------
// 0より大きく1より小さい実数の一様乱数を発生する関数
// B.A.Wichmann and I.D.Hill, Applied Statistics, 31, 1982, p.188 に基づく
// Seed1-3に入れる初期値(整数)は16bit長(maxint=32767)で十分
// Seed1-3には1から30000までの任意の整数値を準備する(0ではいけない)
//---------------------------------------------------------------------------
//Seed1:=171*Seed1 mod 30269 と同値
Seed1:=(Seed1 mod 177)*171-(Seed1 div 177)* 2;
if Seed1<0 then Seed1:=Seed1+30269;
//Seed2:=172*Seed1 mod 30307 と同値
Seed2:=(Seed2 mod 176)*172-(Seed2 div 176)* 35;
if Seed2<0 then Seed2:=Seed2+30307;
//Seed1:=170*Seed1 mod 30323 と同値
Seed3:=(Seed3 mod 178)*170-(Seed3 div 178)* 63;
if Seed3<0 then Seed3:=Seed3+30323;
//See1-3それぞれの乱数を0<RandNum<1となるように
//計算結果が0より大きく、1未満の実数に直し、和の小数部分をとる
RandNum:=(Seed1/30269.0) + (Seed2/30307.0) + (Seed3/30323.0);
while RandNum>=1 do RandNum:=RandNum-1;
//3.秘密鍵を生成
//整数の一様乱数の上限値を決めて、整数の一様乱数を生成し、
//これに上で計算した実数の一様乱数を加えて秘密鍵を生成する
//Seedが秘密鍵(文字列として利用)となる
Seed:= FloatToStr(RandNum + trunc((Seed1+Seed2+Seed3)*RandNum));
//4.暗号化 / 復号化
if (EncOrDec) then
begin
//暗号化(Encode)
Source := TStringBuilder.Create;
Dest := TStringBuilder.Create;
Password := TStringBuilder.Create;
try
Source.Append(KeyStr);
//秘密鍵をセット
Password.Append(Seed);
lpPass := 0;
//テキストのエンコード
for lpSource := 0 to Source.Length - 1 do
begin
//パスワード→整数
if Password.Length = 0 then
PassValue := 0
else begin
PassValue := Word(Password.Chars[lpPass]);
Inc(lpPass);
if lpPass >= Password.Length then lpPass := 0;
end;
//テキスト→整数
SourceValue := Word(Source.Chars[lpSource]);
//XOR演算
EDValue := PassValue xor SourceValue;
//16進数文字列に変換
Dest.Append(IntToHex(EDValue, 4));
//処理結果を返り値にセット
Result:=Dest.ToString;
end;
finally
Password.Free;
Dest.Free;
Source.Free;
end;
end else begin
//復号化(Decode)
DecSource:=keyStr;
Dest := TStringBuilder.Create;
Password := TStringBuilder.Create;
try
//暗号化テキストのデコード
Dest.Clear;
Password.Clear;
//秘密鍵をセット
Password.Append(Seed);
lpPass := 0;
for lpSource := 1 to Length(DecSource) div 4 do
begin
SourceValue := StrToInt('$' + Copy(DecSource, (lpSource - 1) * 4 + 1, 4));
if Password.Length = 0 then
PassValue := 0
else
begin
PassValue := Word(Password.Chars[lpPass]);
Inc(lpPass);
if lpPass >= Password.Length then lpPass := 0;
end;
EDValue := SourceValue xor PassValue;
Dest.Append(Char(EDValue));
end;
//処理結果を返り値にセット
Result:=Dest.ToString;
finally
Password.Free;
Dest.Free;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Ini: TIniFile;
strID, strX, strY, strWaitTime: String;
i:integer;
begin
//Formを最大化して表示
Form1.WindowState:=wsMaximized;
//待ち時間の選択肢(100~3000ミリ秒を100ミリ秒単位で用意)
for i := 1 to 30 do
begin
cmbWaitTime.Items.Add(IntToStr(i*100));
end;
//iniファイルの存在を確認
if FileExists(ChangeFileExt(Application.ExeName, '.ini')) then
begin
//iniファイルからデータを読込み
Ini := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
strID:=Ini.ReadString('Section', 'ID', '');
strX:=Ini.ReadString('Section', 'IchiX', '580');
strY:=Ini.ReadString('Section', 'IchiY', '420');
strWaitTime:=Ini.ReadString('Section', 'WaitTime', '500');
finally
Ini.Free;
end;
//復号して表示
Edit1.Text:=EDText(strID, IntToStr(HashOf('XXXXXXXX')), False);
EditX.Text:=strX;
EditY.Text:=strY;
cmbWaitTime.Text:=strWaitTime;
end;
//Navigate
EdgeBrowser1.Navigate('https://onedrive.live.com/about/ja-jp/signin/');
end;
(4)カーソル位置の座標を取得
マウスのカーソルが現在置かれている位置のスクリーン座標を取得してLabelに表示。
procedure TForm1.chkZahyoClick(Sender: TObject);
begin
if chkZahyo.Checked then
begin
//Enabled
Timer1.Enabled:=True;
end else begin
//Enabled
Timer1.Enabled:=False;
LabelXY.Caption:='[X座標, Y座標]';
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Ini: TIniFile;
strID, strX, strY, strWaitTime: String;
i:integer;
dllFileName:string;
begin
//リソースからDLLを(なければ)生成
//rijnファイルの位置を指定
dllFileName:=ExtractFilePath(Application.ExeName)+'WebView2Loader.dll';
//rijnファイルの存在を確認
if not FileExists(dllFilename) then
begin
//リソースを再生
with TResourceStream.Create(hInstance, 'Resource_1', RT_RCDATA) do
begin
try
SaveToFile(dllFileName);
finally
Free;
end;
end;
end;
・・・
end;
(8)操作方法の案内
この他に、画面最下部に設置したStatusBarに次のような案内を表示できるようにした。
操作方法の案内の表示/非表示の切り替え。
procedure TForm1.chkInfoClick(Sender: TObject);
var
strInfo:string;
strWidth:integer;
begin
if chkInfo.Checked then
begin
//表示する文字列
strInfo:='ID(メールアドレス)が自動入力されないときは、Ctrl+V で入力できます!';
strWidth:=StatusBar1.Canvas.TextWidth(strInfo);
btnOK.Visible:=True;
with btnOK do
begin
Parent:=StatusBar1;
Left:=strWidth-20;
Top:=1;
end;
//StatusBar1の設定(重要:このプロパティがFalseだとStatusBarにテキストが表示されない)
StatusBar1.SimplePanel:=True;
//Info
StatusBar1.SimpleText:=strInfo;
end else begin
StatusBar1.SimpleText:='';
btnOK.Visible:=False;
end;
end;
案内を「表示する」が選ばれていた場合はFormCreate時に案内表示を出すよう設定。
procedure TForm1.FormCreate(Sender: TObject);
var
Ini: TIniFile;
strID, strX, strY, strWaitTime: String;
i:integer;
dllFileName:string;
strWidth:Integer;
strInfo:string;
boolInfo:boolean;
begin
if chkInfo.Checked then
begin
//表示する文字列
strInfo:='ID(メールアドレス)が自動入力されないときは、Ctrl+V で入力できます!';
strWidth:=StatusBar1.Canvas.TextWidth(strInfo);
with btnOK do
begin
Parent:=StatusBar1;
Left:=strWidth-20;
Top:=1;
end;
//StatusBar1の設定(重要:このプロパティがFalseだとStatusBarにテキストが表示されない)
StatusBar1.SimplePanel:=True;
//Info
StatusBar1.SimpleText:=strInfo;
end;
・・・
//iniファイルの存在を確認
if FileExists(ChangeFileExt(Application.ExeName, '.ini')) then
begin
//iniファイルからデータを読込み
Ini := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
strID:=Ini.ReadString('Section', 'ID', '');
strX:=Ini.ReadString('Section', 'IchiX', '580');
strY:=Ini.ReadString('Section', 'IchiY', '420');
strWaitTime:=Ini.ReadString('Section', 'WaitTime', '500');
boolInfo:=Ini.ReadBool('Section','Info',True);
finally
Ini.Free;
end;
//復号して表示
Edit1.Text:=EDText(strID, IntToStr(HashOf('adminy')), False);
EditX.Text:=strX;
EditY.Text:=strY;
cmbWaitTime.Text:=strWaitTime;
chkInfo.Checked:=boolInfo;
end;
・・・
end;
案内そのものを表示したくない場合は、ユーザーの自由意思でその設定も可能に。
procedure TForm1.btnSaveClick(Sender: TObject);
var
strID:string;
Ini:TIniFile;
begin
//入力の有無をCheck
・・・
//暗号化
strID:=EDText(Edit1.Text, IntToStr(HashOf('adminy')), True);
//iniファイルに保存
Ini := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
//保存
Ini.WriteString('Section', 'ID', strID);
Ini.WriteString('Section', 'IchiX', EditX.Text);
Ini.WriteString('Section', 'IchiY', EditY.Text);
Ini.WriteString('Section', 'WaitTime', cmbWaitTime.Text);
Ini.WriteBool('Section','Info',chkInfo.Checked);
//Userに通知
MessageDlg('現在の設定を保存しました!', mtInformation, [mbOk] , 0);
if not btnCopy.Enabled then btnCopy.Enabled:=True;
finally
Ini.Free;
end;
end;