* a23_useSelfMade #9
-(by [[K]], 2023.05.01)
--親ページ: [[a23_useSelfMade]]
** 2023.05.01 Mon #1 [easy-C]
-[1]みなさんは、RPAって聞いたことがあるでしょうか。
-Robotic Process Automation の略のことで、つまりキーやマウスの動作をプログラムで動かすことで、PC作業を自動でやらせようみたいな話です。
-easy-Cでこれができたら小学生は喜ぶのではないかと思いました。
-[2]そもそもプログラミングって、車の運転みたいなものだと思うのです。この機械を自由に操作したい、と。PCの操作で一番普通なのは、マウスやキーの操作でしょう。
-・・・変数に値を入れるとか、ウィンドウを開くとか、ウィンドウ上に線を引くとかは、小学生にとっては自然な「PCの操作」ではありません。それらはプログラミングでしかできないことかもしれませんが、でももっと普通のことだってやりたいと思うかもしれません。
-コンソールでコマンドを打っていた時代は、リダイレクトとかパイプが使えれば、他人が作ったアプリを好きなように利用できましたが、今はGUIの時代です。だからマウスやキーの操作を自動でやれるようにしてやれば、原理的にはかなり多くのアプリケーションがコントロールできるはずです。
-[3]とりあえず以下のようなことができるところまで作りました。
ARpa rpa[1]; ARpa_init(rpa);
ARpa_Win rpawin = ARpa_srchWinNam(rpa, "Chrome", 0); // Chromeをウィンドウ名に含むウィンドウを検索.
if (rpawin == 0) exit(1); // 見つからなければエラー終了.
ARpa_setWinPos(rpa, rpawin, 0, 0); // ウィンドウの左上の端に移動.
ARpa_activeWin(rpa, rpawin); // ウィンドウを入力アクティブにする.
-これで狙ったウィンドウを好きな位置に移動できるので、自動運転がしやすくなります。
-また自動運転をしないとしても、「このウィンドウがいつもこの位置にいてほしい」みたいなお気に入りの配置パターンがあるのなら、こんな感じのプログラムを書くことで、いつでも整列させられます。
-今はウィンドウが見つからない場合は終了していますが、system関数で見つからないアプリを起動するようにすれば、起動直後の何もない状態から必要なものを全部起動して、いい感じに並べるというプログラムもできます。
-ARpa_setWinSiz()もあるので、ウィンドウのサイズ調整もできます。
-[4]こんなのもできます。ワンライナーで、
HL9>!ARpa w;for(;;){ARpa_getMosPos(&w);printf(" (%04d,%04d) #%06x \r", w.x, w.y, ARpa_getPix(&w, w.x, w.y, 0));aWait(100);}
-ってやれば、マウスの座標とその場所の色をリアルタイムで確認できます。
-[5]ウィンドウ名だけで単純に区別できないときは、
ARpa rpa[1]; ARpa_init(rpa);
ARpa_Win win[1000];
int n = ARpa_getWin(rpa, win, 1000, 0);
-とするだけで画面上のすべてのウィンドウハンドルがwin[]に入ります。nは個数です。
-だからこのウィンドウハンドルを使って、
ARpa_getWinNam()
ARpa_getWinPos()
ARpa_getWinSiz()
-ができるので、それでどれが自分の探しているウィンドウかを判別します。
** 2023.05.02 Tue #1 [easy-C]
-[[a23_usm006]]の 2023.03.16 Thu #1 で、HL-9での演算子の優先順位を変えたらどうかということを考えていましたが、これはやっぱりよくないと思いなおしました。C言語との互換性が保てなくなる改造は良くないです。
-優先順位を変えるのではなく、新しい演算子を適当な優先順位で追加すればいいのです。・・・うん、よし、この方向で考えよう!
-問題になっているのは、代入演算子の優先順位が(比較演算子と比べて)低いことと、ビット演算の演算子の優先順位が(比較演算子と比べて)低いことです。この2点がなんとかなれば、かっこは減らせるはずです。
** 2023.05.02 Tue #2 [easy-C]
-拡大鏡のプログラムです。マウス周辺を拡大して表示します。
-(こういうのができるようになりました。)
-loupe.c[11行]
ARpa rpa; ARpa_init(&rpa);
AWin *win = aOpenWin(256, 256, "loupe");
while (!AWin_isClose(win)) {
ARpa_getMosPos(&rpa);
int *p = ARpa_capture(&rpa, 64, 64, rpa.x - 32, rpa.y - 32, 0);
[j = 0:<64] { [i = 0:<64] {
aFillRect(win, 4, 4, i * 4, j * 4, *p++ & 0xffffff);
} }
ARpa_captureFree(&rpa);
aWait(100);
}
** 2023.05.08 Mon #1 [easy-C]
-prsで全角文字を表示しようとして、今のHL-9が全角文字を含む文字列のことを全く考えていないことを思い出しました。
-これは不便だと思ったので直しました!
** 2023.05.09 Tue #1 [easy-C]
-引き続き、RPA機能の追加をやっているのですが、なんかうまくいかなくて「なんでかなー」と悩んでいたら、
#define _WIN32_WINNT 0x0500
を書いたつもりになっていて、でも実際は書いていなかったせいだと分かりました。
-なるほどなあ、書き忘れるとこうなるのかー。
** 2023.05.10 Wed #1 [easy-C]
-今日は自動のキー入力とマウス入力をやりました。ちゃんと動いているようです。
** 2023.05.11 Thu #1 [easy-C]
-自分でライブラリ関数の一覧が欲しくなったのでまとめてみます。
|AWin *win = aOpenWin(xsz, ysz, nam)|グラフィックウィンドウのオープン|
|aSetMode(win, m)|描画モード指定(AWinMode_Set, AWinMode_Or, AWinMode_And, AWinMode_Xor)|
|aSetPix(win, x, y, c)|ピクセル描画|
|aSetPix0(win, x, y, c)|ピクセル描画(簡易高速版)(aSetModeの設定を無視)|
|aGetPix(win, x, y)|指定した場所の色を返す|
|aFillRect(win, xsz, ysz, x, y, c)||
|aDrawRect(win, xsz, ysz, x, y, c)||
|aDrawLine(win, x0, y0, x1, y1, c)||
|aFillOval(win, xsz, ysz, x, y, c)||
|aDrawOval(win, xsz, ysz, x, y, c)||
|aFillOvalCent(win, x, y, a, b, c)||
|aDrawOvalCent(win, x, y, a, b, c)||
|AWin_flushAll(win)|描画内容を実画面に反映(aWaitを使うならこの操作は不要)|
|key = aInkey(win, flg)|flg=1:読み取ったキーコードをバッファから取り除く(これが普通)、flg=0:バッファに残る|
|key = aInkeyWait(win, flg)|何らかのキー入力があるまで待ってからaInkeyする|
|aClrKeybuf(win)|キー入力バッファをクリアする|
|bool = AWin_isClose(win)|ウィンドウはユーザによって閉じられたか?|
|AWin_close(win)|ウィンドウを閉じる|
|||
|retCod = ACA_EasyC_exec(aCA, s, fnam)|文字列sをeasy-Cとしてgcc実行。fnam.cとfnam.exeを生成する。|
|||
|AClass(className) { ... };|これで宣言すると自動でtypedefもされるのでstructを付けずに型名として使える|
|||
|AAutoPlay(aCA, ch, mml)|もしAPlayオブジェクトがなければ適当に初期化して、APlay_mml(play, ch, mml)を実行|
|APlay_init16(play, sz)|playオブジェクトを最大16ch、バッファサイズszで初期化|
|APlay_mml(play, ch, mml)|MMLをコンパイルしてバッファにためる|
|APlay_run(play)|演奏開始|
|||
|APcg_initCa(aCA, pcg)|pcgオブジェクトを初期化|
|APcg_set0pi(pcg, 0, win, bc)|ウィンドウと背景色を指定|
|APcg_set0(pcg, 1, pos1, 0)|pos1値を指定(pos1:パレット番号)|
|APcg_set0(pcg, 2, pos2c, pos2y)|pos2cとpos2y値を指定|
|APcg_set0(pcg, 3, pos3x, pos3y)|pos3xとpos3y値を指定|
|APcg_set0(pcg, 4, xsz, ysz)|キャラクタの大きさ(ピクセル単位)|
|APcg_set0(pcg, 5, xsc, ysc)|キャラクタを描画するときの拡大倍率|
|APcg_set1(pcg, s)|パレット設定(pos1番から)|
|APcg_set2(pcg, s)|キャラクタ設定(pos2c番のpos2y行目から)|
|APcg_set3(pcg, s)|キャラクタの並べ方の設定(pos3x, pos3y)から|
|||
|ARat r = ARat_new(a, b)|a:/bの値を持つARatオブジェクトを返す|
|ARat_print(r)|分数の表示|
|ARat_irreducible(r)|分数の約分|
|ARat_add(r, s)||
|ARat_sub(r, s)||
|ARat_mul(r, s)||
|ARat_div(r, s)||
|ARat_equ(r, s)|等しければ非零を返す|
|ARat_next(r)|分数で雑に総当たりしたいときに、次の分数を返す関数|
|||
|ARpa_init(rpa)||
|ARpa_getMosPos(rpa)||
|ARpa_setMosPos(rpa, x, y)||
|ARpa_getWin(rpa, aryWin, n, parent)||
|ARpa_getWinPos(rpa, win)||
|ARpa_getWinSiz(rpa, win)||
|ARpa_getWinNam(rpa, win, s, n)||
|ARpa_setWinPos(rpa, win, x, y)||
|ARpa_setWinSiz(rpa, win, x, y)||
|ARpa_activeWin(rpa, win)||
|win = ARpa_srchWinNam(rpa, s, parent)||
** 2023.05.15 Mon #1 [easy-C]
-最近は、OSC名古屋のために、小学生向けのeasy-Cの入門テキストを書いています。
** 2023.05.22 Mon #1 [easy-C]
-OSC名古屋ようの配布物ができましたー。
--https://essen.osask.jp/files/intro-ec-01.pdf
** 2023.05.23 Tue #1 [easy-C]
-追加したRPA用の関数は結構役に立ちそうなのですが、クリップボードへのアクセスができるともっとよさそうだと思いました。
-ということでクリップボードのAPIを勉強中です。
~
-[追記] webの資料を見ながら何度かワンライナーで実験したら、テキストデータをクリップボードから取得したり、クリップボードにテキストデータをセットしたりできるようになりました。やった!あとはこれをライブラリから使えるように整備します。
~
-[追記] ARpa_getClipboardTxt()とARpa_setClipboardTxt()でクリップボードを読み書きできるようになりました!
** 2023.06.05 Mon #1 [easy-C]
-webの情報をクロールして、そのデータを別のwebサイトに入力したり、その内容でメールを書かせようとか思っています(というかもうやっています)。
-でもやっぱり完全自動化はちょっと怖いのです。だからなんというか[送信]ボタンを押す直前で止まってほしいわけです。でもそこで止まると、続きができません。
-そこで考えた方法は、まずクローラとアクション系の処理を完全分離することでした。クローラはクロール結果をローカルファイルにしまうだけにします。それでアクションプログラムは、やりたいアクションごとに分けてしまって、それぞれローカルファイルから情報を取得して、それぞれのアクションをやればいいわけです。これなら[送信]を押す手前で止まってもよくて、確認して送信した後は、次のアクションのプログラムをrunすればいいわけです。
** 2023.06.05 Mon #2 [easy-C]
-gccの関数内関数宣言を確認したくて以下のようなプログラムを書いてrunしました。
pr 1;
int f0() { prs "f0"; return 0; }
pr 2;
int f1() { prs "f1"; return 1;}
f0(); f1();
// 実行結果
1 2 f0 f1
-なるほどこうなるのかー。
** 2023.06.08 Thu #1 [easy-C]
-以下の記述が実行できずに落ちてしまう。でも悪いのはプログラムじゃなくてメモリ不足のせいかもしれない。とりあえず今は時間がないので、メモだけを残しておく。
HL9>!SimpleDB db[1]; SimpleDB_init(db, "db01.txt", 31, 255, 10000); SimpleDB_load(db); SimpleDB_set(db, "nextRecordNo", "63");
** 2023.06.21 Wed #1 [easy-C]
-適当に作った SimpleDB は排他制御もないような本当にシンプルすぎるデータベースだけど、でもこれがあると変数を保存できるので、できることはかなり増えました。
** 2023.06.22 Thr #1 [easy-C]
-リファクタリングして行数が減って見やすくなると嬉しい!
** 2023.07.12 Wed #1 [easy-C]
-0以上1未満の値を返す乱数が欲しい。仮数部のすべてのビットが乱数で決まってほしい。・・・後で作ろう。double版もあったら便利かもしれない。
** 2023.07.20 Thu #1 [easy-C]
-なんとなく感じたRPAによる作業自動化の必勝パターン
-[1]すべてを自動化する必要は全くない、自動化しやすいところだけ自動化すればいい。
--手動の部分が残っていていい。こう思うことで気負わなくなる。できるところから着手するようになる。
-[2]RPA専用機を用意する。
--RPA実行中はできるだけ触らないほうがいいけど、その間何もできなくなるのは不便なので、専用マシンを用意するといい。
-[3]途中で中断されることを想定。つまり処理開始時は何よりも前に現状がどういう状況なのかを確認する処理になる。
--なんかうまくいってないときに、人間がCtrl-Cで処理を中断することは十分にあり得る。その前提で作っておくと、トラブル時にすぐに復旧できるので、すごく使いやすくなる。
-[4]画面遷移を少なくする。
--アプリAの表示内容をアプリBに入力するとき、人間が手動でやるなら一項目ごとにCtrl-C、Ctrl-Vをするけど、それはRPAには向いてない。先にアプリAに対してCtrl-Cをたくさんして必要な項目をすべて読み取ってしまったほうがいい。そしてアプリBに画面遷移して、そこで一気に入力する。
-[5]中断されても途中から再開できるために、中断しても消えない変数が欲しくなる。それは簡易的なデータベースを用意すると便利。
-[6]送信ボタンとか保存ボタンなど、なんかこう決定的なボタンは自動では押さない。
--そこに差し掛かったらプログラムを終了して、人間に押させる。この仕様だと、気楽にRPAプログラムを書ける。細心の注意を払わなくてよくなる。
** 2023.08.07 Mon #1 [easy-C]
-小学生向けの、easy-Cの入門書を書いています。→ [[a23_intro00]]
-easy-Cを一度もやったことがないという人ではなく、2~3回くらいはPLAY命令で遊んだことがあるくらいの人を想定しています。
-タイピング練習をちょっとやって、テキストファイルを入力したり保存したりできるようになったら(もしくはそこを大人がフォローできるなら)、たぶんはじめられます。
** 2023.08.21 Mon #1 [easy-C]
-HL-9のPICTURE命令が、BMPファイルにしか対応してなくて不便だったので、JPEGにも対応させました。これで画像ファイルを小さくできる!
** 2023.08.28 Mon #1 [easy-C]
-まず、MinGWで作ったexeファイルは、トロイの木馬型のマルウェアと言われて、問答無用で消されたり、(消されないまでも)実行を妨害されたりすることが多くなってきました。
-自分一人でMinGWを使っている分には、それでも設定を調整して使い続けることはできるのですが、自分が作ったものを誰かに使てもらおうとすると、マルウェア認定されるのは不安だろうと思うので、やっぱりなんとかしたいです。
-ということで、Visual StudioのCommunity 2022版は「オープン ソース、個人の開発者向けの無料」らしいのでこの条件で、Visual Studioを使うことにしました。
-しかしそれでも思うのは、本当に悪いのはWindowsのDefenderのマルウェア判定基準が雑で、本当は全く悪くないものを悪いと決めつけることだと思うのです。MinGWは別に何も悪いことなんかしてなくて、今も昔も同じようにオープンソースの開発ツールだと思うのです。私もずっとお世話になってきました。・・・ということで、なんだかすごく負けた気分なのですが、今回は我慢します。
-それでVisual Studioは、IDEなし版でも6GBくらいあって、
-それでVisual Studioは、IDEなし版でも6GBくらいあって、300MB未満だったMinGWと比べるとかなり大きいです。・・・でもコンパイル速度や生成されるバイナリは悪くないです(サイズ優先で最適化したら、MinGW版よりもかなり小さくなりました)。
// sjisconv的なものを入れる.
// :&や:|など. ビット演算
// utf8でウィンドウ名は正しく出せるのか?
//[lv1] 導入と「1 2 3 4 ...」と「3 6 9 12 15 ...」
//[lv2] IF文と「10 9 8 ... 1」
//[lv3] 復習と以上、以下と「10 9 8 ... 2 1 0」
//
//[lv4] 繰り返しの繰り返し、九九の表
//[lv5] printfで整形、for文で整形
//[lv6] 郵便料金、ゆうパック料金
//[lv7] 乱数を10個表示、狙った乱数を作れるようになる
//[lv8] 数当てゲームを作る
//
//[lv9]手本無しで、「10 9 8 ... 0」ができるか?
//[lv10]手本無しで、九九の表ができるか?
//[lv11]手本無しで数当てゲームができるか。
* こめんと欄
-掲示板をご利用ください。→[[a23_bbs]]