WindowsTerminal上で「C++,C#,Go言語,Rust」の「Win32のGetAsyncKeyState」機能を使って、入力したKeyを取得する雛形文の比較

# 各言語のプログラム雛形の作成条件
- 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文字
```C++
#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++出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157498/e527b9e8-a8b4-1002-6294-aeb94c98eaa5.png)

## C#

↓15行・515文字
```C#
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#出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157498/1570e0fb-3ad1-7621-5e2e-c1ebbb6250a2.png)

## Go言語
↓22行・421文字

```Go
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++
	}
}

```
Go出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157498/f2780d77-c87d-021d-7605-be6ac5f60576.png)


## Rust
↓7行・164文字
```toml: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文字
```Rust: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出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157498/9a990eb9-6ff8-7b35-1ce9-94467b92f6b4.png)


# 感想
　三つ並べるとロゼッタストーンみたい。
　以下は「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年の昨今、もはや管理者権限ない。<br>　会社のパソコンは、2020年頃から管理者権限は剥奪され、ソフトを自由にインストールできない。出来ても限定されたソフトとなる。追加でインストールしたい時には、管理者権限の一時申請やら上司の許可が必要になる。<br>　私は会社内で中堅になったので、今は比較的、会社内の手続きや説明も楽になったけど、理解のない会社や上司だったら無理だろうなと思う。「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」って何？
↓ウィキペディアの説明ページ

https://ja.wikipedia.org/wiki/Windows_API

- Microsoft社のWindowsは、C言語やC++言語で制作されている。
- 結果的にCやC++をコンパイルすれば、そのままOSと同一の機械語に変換できる。
- Win32の「32」は、32ビットパソコン時代に作られた為。64ビットCPUの昨今は「Win64」となるが、慣習的にWin32と言えばWin64も含んでいる。



# 参考にしたサイト
https://qiita.com/pseuxide/items/fc445f5dd8f431b12b82

https://qiita.com/sawasaka/items/b3d5285b4198c0e46628

[simple windows keylogger using GetAsyncKeyState](https://gist.github.com/obonyojimmy/61abcbc6022cb7399813db8ac4d1de4d)


[windows::Win32::UI::Input::KeyboardAndMouse::GetAsyncKeyState](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/Input/KeyboardAndMouse/fn.GetAsyncKeyState.html)