各言語のプログラム雛形の作成条件
-
- Visual studio codeや秀丸でプログラミング。
-
- コンパイルはVisual studioとかは使わずにコマンドで手動。
-
- 200ミリ秒ごとにループ(繰り返し)する。
-
- ループを一周する毎に、変数「t」の値を「1」増やす。
-
- 「←」の矢印ボタンを押した時、反応する。
-
- GetAsyncKeyStateからの出力は、変数「key37」に格納する。
-
- 絵文字を使いたいのでファイルはutf-8で保存する。
- (C++は日本語や絵文字が文字化けした!)
パソコン環境
-
- Windows10 : 22H2
-
- WindowsTerminal(プレビュー版) : 1.19.2831.0
-
- c++のコンパイラ g++ : 10.3.0
-
- C#のコンパイラ csc : 4.8.9037.0
-
- Go : 1.21.3
- Rust : 1. 72.0
プログラミング結果
C++
↓13行・249文字
#include <iostream>
#include <windows.h>
int main(){
long t = 0;
while(1){
int key37 = GetAsyncKeyState(37);
std::cout << "C++ Left-button " << t << " " << key37 << std::endl;
Sleep(200);
t++;
}
return 0;
}
C++出力結果
C#
↓15行・515文字
using System;
using System.Threading;
class hello_GetAsyncKeyState {
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern short GetAsyncKeyState(int vKey);
public static void Main() {
Console.OutputEncoding = System.Text.Encoding.GetEncoding("utf-8");//?の文字化け対策
int t = 0;
while(true){
short key37 = GetAsyncKeyState(37);
Console.WriteLine("C#「← 」キーを押したか?? {0} {1} {2}",t,key37,key37&0x1);
Thread.Sleep(200);
t++;
}
}
}
C#出力結果
Go言語
↓22行・421文字
package main
import (
"fmt"
"time"
"golang.org/x/sys/windows"
)
var (
moduser32 = windows.NewLazyDLL("user32.dll")
procGetAsyncKeyState = moduser32.NewProc("GetAsyncKeyState")
)
func main() {
t := 0
for {
key37, _, _ := procGetAsyncKeyState.Call(uintptr(37))
fmt.Println("Go「← 」キーを押したか?? ", t, key37, key37&0x1)
time.Sleep(200 * time.Millisecond)
t++
}
}
Rust
↓7行・164文字
[package]
name = "file_name"
version = "0.1.0"
edition = "2021"
[dependencies]
windows = { version = "0.51.1", features=["Win32_UI_Input_KeyboardAndMouse"] }
↓15行・約406文字
use std::thread;
use std::time::Duration;
use windows::Win32::UI::Input::KeyboardAndMouse::GetAsyncKeyState;
fn main() {
let mut t =0;
unsafe {
loop{
let key37 = GetAsyncKeyState(37);
println!("Rust 「← 」キーが押したか?? {} {} {}",t,key37,key37&0x1);
thread::sleep(Duration::from_millis(200));
t =t+1
}
}
}
Rust出力結果
感想
三つ並べるとロゼッタストーンみたい。
以下は「C」「JavaScript」「VBA」「Go」で趣味で遊んだ経験を踏まえての感想(愚痴ばっかり)です。
「C++」
-
- 最もシンプルに書ける。
-
- 「Sleep(200);」と書くだけで0.2秒待ってくれるのは、すごくない?
-
- 「while(1)」の「1」や「return 0;」の「0」の意味がわからん。
-
- 「std::cout」もなんだこれ?という感想。
-
- 最もシンプルに書けるので、C++を使いたいが以下より私には無理だった。
utf-8や絵文字が絶望的に出力できない。
メモリの扱いにプロ技術が必要。
「C#」
-
- C#の内部はutf-16なので、utf-8が直接使えなく、絵文字を表現できないのが致命傷。
-
- utf-8を使う為には以下の一文が必要になる
-
- 「Console.OutputEncoding = System.Text.Encoding.GetEncoding(“utf-8”);」
-
- C#ってなんで「class」から始めんとあかんのだ。
-
- 「private」「pubclic」「static」「void」も非常に鬱陶しい。プログラムが横に長くなる。
-
- とボヤキつつ、C#の最大最強の魅力はコンパイラ「csc」が標準でWindowsにインストールされている事。
- 機械系エンジニアには2023年の昨今、もはや管理者権限ない。 会社のパソコンは、2020年頃から管理者権限は剥奪され、ソフトを自由にインストールできない。出来ても限定されたソフトとなる。追加でインストールしたい時には、管理者権限の一時申請やら上司の許可が必要になる。 私は会社内で中堅になったので、今は比較的、会社内の手続きや説明も楽になったけど、理解のない会社や上司だったら無理だろうなと思う。「Visual Studio」とかも「何それ?」となって、インストールなんで夢のまた夢。なので、Visual Studioを使わない素の「csc」と「メモ帳」での野良プログラムは今後も静かな需要があると思う。
「Go」
-
- いつもはシンプルなGo言語なのに、今回はシンプルにあらず。
-
- 今回の方法をWebから探し出すのが苦労した。
-
- 「NewLazyDLL」や「NewProc」ってなんやねん。一見さんお断り的な。
予備知識として「DLLファイル=Dynamic Load Library」の存在を知らなきゃならない。
「DLLファイル」内部に「GetAsyncKeyState」が入っていることはVBA作成した際に知っているが、なかなか知らんな。
DLLファイルは「C言語」で書かれている。
「Call」もしっくりこない。
「uintptr」も難しい。やめてよって感じ。出てこないで欲しい。ポインター恐怖症。
要するに普段使わない用語を使うという事で。
「Rust」
-
- Webで「Rust GetAsyncKeyState」で検索すると「GetAsyncKeyState」を使う方法は複数あり(winapiとかのライブラリもある)迷った。
-
- 迷った結果、マイクロソフトの「win32metadata」プロジェクトでの「Windowsのwin32クレート」を使ってます。
-
- マイクロソフトがRustでwin32を使えるようにする「win32metadata」プロジェクトはネットニュースで知っていたが、「Rust GetAsyncKeyState」でgoogle検索しても一番上に検索候補が挙がってこなかった。
-
- -「Cargo.toml」の[dependencies] (=依存関係) の記述も注意しなくちゃならない。事前準備が必要。
-
- Rust本文は短めだが、tomlと合計すると記述量はやや多めとなる。
- toml内の「Win32_UI_Input_KeyboardAndMouse」で、途中にアンダーバー「_」で繋ぐのは正直、反則だと思う。「::」や「.」で良いだろう。
補足説明
「Win32」って何?
↓ウィキペディアの説明ページ
-
- Microsoft社のWindowsは、C言語やC++言語で制作されている。
-
- 結果的にCやC++をコンパイルすれば、そのままOSと同一の機械語に変換できる。
- Win32の「32」は、32ビットパソコン時代に作られた為。64ビットCPUの昨今は「Win64」となるが、慣習的にWin32と言えばWin64も含んでいる。
参考にしたサイト
simple windows keylogger using GetAsyncKeyState
windows::Win32::UI::Input::KeyboardAndMouse::GetAsyncKeyState