各言語のプログラム雛形の作成条件
- 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文字
Cargo.toml
[package]
name = "file_name"
version = "0.1.0"
edition = "2021"
[dependencies]
windows = { version = "0.51.1", features=["Win32_UI_Input_KeyboardAndMouse"] }
↓15行・約406文字
main.rs
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