File:  [Isaki's NoNo m68k/m88k emulator] / nono / wx / wxmainview.cpp
Revision 1.1.1.20 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:57 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// メイン画面パネル
//

#include "wxmainview.h"
#include "wxmainframe.h"
#include "wxuimessage.h"
#include "config.h"
#include "keyboard.h"
#include "renderer.h"
#include <wx/event.h>

//#define KEYDEBUG 1
//#define MOUSEDEBUG 1

#if defined(KEYDEBUG)
#define DKPRINTF(...)	printf(__VA_ARGS__)
#else
#define DKPRINTF(...) /**/
#endif

#if defined(MOUSEDEBUG)
#define DMPRINTF(...)	printf(__VA_ARGS__)
#else
#define DMPRINTF(...) /**/
#endif

// 再描画矩形の指定方法について。
// DoRefresh() にて、VM スレッドが自発的に画面を更新する際は、
// パフォーマンスの観点からも更新矩形だけを再描画すべき。
// これを wxWidgets に指示するのが wxWindow::Refresh{,Rect}() であるが
// 一部のプラットフォームではこれを呼び出すと、アプリケーションウィンドウ
// 全体がささってしまい、MainView だけでなくメニューバーも含めたすべてが
// 再描画できなくなってしまう。仕方がないので、これらのプラットフォームでは
// Refresh{,Rect}() を呼ばず、再描画矩形を画面全体として運用する。
// ちょっと無駄なだけなので (動かないことに比べれば) 気にしない。
//
// 今のところ NetBSD (5.0 以降) と OpenBSD(/amd64)(-6.7)
// (と Linux (CentOS 6.3/x86_64)) が該当する。
#if defined(__NetBSD__) || defined(__OpenBSD__)
#define DONT_USE_REFRESH 1
#endif

wxDEFINE_EVENT(NONO_EVT_MOUSEMODE, wxCommandEvent);

wxBEGIN_EVENT_TABLE(WXMainView, inherited)
	EVT_PAINT(WXMainView::OnPaint)
	EVT_KEY_DOWN(WXMainView::OnKeyDown)
	EVT_KEY_UP(WXMainView::OnKeyUp)
	EVT_CHAR(WXMainView::OnChar)
	EVT_MOUSE_EVENTS(WXMainView::OnMouse)
	EVT_MOUSE_CAPTURE_LOST(WXMainView::OnMouseCaptureLost)
wxEND_EVENT_TABLE()

WXMainView::WXMainView(wxWindow *parent)
	: inherited(parent)
{
	SetName("WXMainView");

	// デバイスを取得。
	renderer = GetVideoRenderer();

	// rich		dumb
	// -------- -------
	// NULL		NULL	キー入力機能なし
	// NULL		avail	シリアル入力機能のみ
	// avail	avail	キー入力機能あり (2つは同じポインタ)
	dumbkbd = gMainApp.FindObject<DumbKeyboard>(OBJ_KEYBOARD);
	if (dumbkbd) {
		richkbd = dynamic_cast<Keyboard *>(dumbkbd);
	}

	// マウスモード変更イベント
	Bind(NONO_EVT_MOUSEMODE, &WXMainView::OnMouseMode, this);

	// VM からの通知を受け取る
	WXUIMessage::Connect(UIMessage::RENDER, this,
		wxCommandEventHandler(WXMainView::OnRender));

	// 実画面 (ウィンドウの大きさ)
	DoResize(screen_scale);

	// 更新間隔 [msec]
	renderer->SetRefreshInterval(33);

	// 最初に一度描画
	Refresh();
}

WXMainView::~WXMainView()
{
	// マウスをリリースしないと Assert される
	if (HasCapture()) {
		ReleaseMouse();
	}
	WXUIMessage::Disconnect(UIMessage::RENDER, this,
		wxCommandEventHandler(WXMainView::OnRender));
}

// (設定反映などの) 初期化
bool
WXMainView::Init()
{
	if (richkbd) {
		// キーボードの入力モードの初期値設定
		const ConfigItem& item_input = gConfig->Find("hostkbd-input");
		const std::string input_mode = item_input.AsString();
		if (input_mode == "char") {
			SetCharInputMode(true);
		} else if (input_mode == "jp") {
			// 今は二択しかないのでちょっと噛み合ってないが
			SetCharInputMode(false);
		} else {
			item_input.Err();
			return false;
		}
	} else if (dumbkbd) {
		// シリアルキーボードのみなら常に文字入力。
		SetCharInputMode(true);
	}

	return true;
}

// 終了用に描画を停止する
void
WXMainView::Close()
{
	// これで OnPaint() が何もせず帰るようになる。
	viewwidth = 0;
	viewheight = 0;
}

// リフレッシュ要求イベント
void
WXMainView::OnRender(wxCommandEvent& event)
{
#if defined(DONT_USE_REFRESH)
	// Refresh{,Rect}() が使えないので、再描画範囲は常に全体とする
#else
	// 再描画範囲を更新矩形に限定
	// XXX のはずだが、今の所全体
	RefreshRect(wxRect(0, 0, viewwidth, viewheight), false);
#endif
	// 実際に再描画する
	Refresh();
	// TODO: ビデオモニタにも通知する
}

// 描画イベント
void
WXMainView::OnPaint(wxPaintEvent& event)
{
	if (__predict_false(viewwidth == 0 || viewheight == 0)) {
		return;
	}

	BitmapRGB *bitmap24 = renderer->GetBitmap();
	if (__predict_false(bitmap24 == NULL)) {
		return;
	}

	wxImage image(viewwidth, viewheight, bitmap24->GetBuf(), true);
	wxBitmap bmp(image);

	// 実画面 DC にコピー
	wxPaintDC dstDC(this);
	dstDC.DrawBitmap(bmp, 0, 0);
}

// リサイズ (UI スレッドから呼ぶこと)
void
WXMainView::DoResize(double scale)
{
	screen_scale = scale;
	int width  = (double)renderer->GetWidth()  * scale;
	int height = (double)renderer->GetHeight() * scale;
	if (viewwidth != width || viewheight != height) {
		viewwidth  = width;
		viewheight = height;

		// レンダラにリサイズ指示。
		renderer->ResizeView(viewwidth, viewheight);

		// ウィンドウサイズ変更
		SetSize(viewwidth, viewheight);
		SetMinSize(wxSize(viewwidth, viewheight));
	}
}

// 現在のスケールを返す。
// screen_scale は public static なので見えるんだけど一応お行儀で。
double
WXMainView::GetScale() const
{
	return screen_scale;
}

// 現在のスケール
/*static*/ double WXMainView::screen_scale;


//
// マウス入力
//

// マウスモード変更要求イベント
void
WXMainView::OnMouseMode(wxCommandEvent& event)
{
	SetMouseMode(event.GetInt());
}

// マウスモード設定
void
WXMainView::SetMouseMode(bool mode)
{
	// XXX マウスモード ON にした時の座標を記憶してそこに戻るのはどうか

	mousemode = mode;
	if (mousemode) {
		// マウスモードを ON にする
		DMPRINTF("SetMouseMode ON\n");

		// マウスカーソル OFF
		::wxSetCursor(wxCursor(wxCURSOR_BLANK));

		if (!HasCapture()) {
			CaptureMouse();
		}

		// このウィンドウから外れないように移動を検出し続けるため、
		// マウスカーソルをウィンドウ中央に移す。
		// ウィンドウとメニューバーが分離してる wxOSX のために必要。
		MyWarpPointer(GetSize() / 2);
	} else {
		// マウスモードを OFF にする
		DMPRINTF("SetMouseMode OFF\n");

		if (HasCapture()) {
			ReleaseMouse();
		}

		// 分かりやすさのため、マウスカーソルを中央へ戻してから復帰
		wxSize pt = GetSize() / 2;
		WarpPointer(pt.x, pt.y);

		// マウスカーソル ON
		::wxSetCursor(wxNullCursor);
	}

	// マウスモードなら、タイトルにマウスモードの抜け方を表示したい。
	auto frame = dynamic_cast<WXMainFrame *>(GetParent());
	frame->SetMyTitle(mousemode);
}

// マウスカーソルをクライアント座標 (x, y) に移動
void
WXMainView::MyWarpPointer(wxSize pos)
{
	DMPRINTF("MyWarpPointer %d,%d\n", pos.x, pos.y);

	// この後の MDWarpPointer() でもう一度 EVT_MOTION が飛ぶので
	// それを判別するためのフラグ。
	motion_by_warp_pointer = true;

	WarpPointer(pos.x, pos.y);
}

// マウスイベント
void
WXMainView::OnMouse(wxMouseEvent& event)
{
	// マウスモードの時だけ処理。
	// XXX 本当はイベントごと Disconnect したい
	if (mousemode) {
		bool leaving = event.Leaving();
		bool moving  = event.Moving();
		bool dragging = event.Dragging();
		// LeftDown() 等は押された時、LeftIsDown() 等は押されてる間 true。
		bool rb = event.RightIsDown();
		bool lb = event.LeftIsDown();
		bool mb = event.MiddleIsDown();
		const wxPoint& pos = event.GetPosition();
		int dx = 0;
		int dy = 0;

#if defined(MOUSEDEBUG)
		std::string dstr = "OnMouse";
		if (moving || dragging || motion_by_warp_pointer) {
			dstr += string_format(" (%d,%d)", pos.x, pos.y);
		}
		if (moving)
			dstr += " Moving";
		if (dragging)
			dstr += " Dragging";
		if (motion_by_warp_pointer)
			dstr += " MotionByWarp";
		if (lb || mb || rb) {
			dstr += string_format(" Button(%c%c%c)",
				(lb ? 'L' : '-'),
				(mb ? 'M' : '-'),
				(rb ? 'R' : '-'));
		}
		if (leaving)
			dstr += " Leaving";
		printf("%s\n", dstr.c_str());
#endif

		if (leaving) {
			// タスクスイッチした時とかのための自動リリース。
			// メインウィンドウの上にサブウィンドウが乗っているときも
			// leaving が発生するので、メインウィンドウの外に出た場合のみ
			// リリースする。
			auto sz = GetSize();
			if (pos.x < 0 || pos.x > sz.x || pos.y < 0 || pos.y > sz.y) {
				SetMouseMode(false);
			}
		}

		if (moving || dragging) {
			// (My)WarpPointer() で自発的にマウスカーソルを移動させたことで
			// 来る EVT_MOTION は無視する。
			if (motion_by_warp_pointer) {
				motion_by_warp_pointer = false;
				// ここを基準点にする
				prevpos = pos;
			} else {
				// 前回からの差を求める
				dx = pos.x - prevpos.x;
				dy = pos.y - prevpos.y;
				prevpos = pos;

				// マウスカーソルを中心に戻す
				if (dx != 0 || dy != 0) {
					MyWarpPointer(GetSize() / 2);
				}
			}
		}

		// VM に入力
		if (dx != 0 ||
		    dy != 0 ||
		    lb != prevlb ||
		    mb != prevmb ||
		    rb != prevrb   )
		{
			DMPRINTF("        Input dx=%d dy=%d %c%c%c\n",
				dx, dy,
				(lb ? 'L' : '-'),
				(mb ? 'M' : '-'),
				(rb ? 'R' : '-'));

			if (richkbd) {
				richkbd->MouseInput(dx, dy, rb, lb, mb);
			}
		}

		prevlb = lb;
		prevmb = mb;
		prevrb = rb;
	}

	// EVT_LEFT_DOWN をデフォルト処理するため
	event.Skip();
}

// マウスキャプチャロスト
void
WXMainView::OnMouseCaptureLost(wxMouseCaptureLostEvent& event)
{
	// 外部要因でマウスキャプチャをロストしたので、マウスモードを抜ける。
	SetMouseMode(false);
}

// アクティベートイベント。
// この(トップレベル)ウィンドウにフォーカスが当たるか外れるかで飛んでくる。
// 実際には WXMainFrame 宛てに飛んできたイベントをこちらに転送してある。
// マウスモード中にこのウィンドウからフォーカスが外れたら (例えば ALT+TAB の
// ようなウィンドウを切り替える操作)、マウスモードを解除するため。
void
WXMainView::OnActivate(wxActivateEvent& event)
{
	// フォーカスが外れる際にマウスモード中ならマウスモードを解除
	if (event.GetActive() == false) {
		DMPRINTF("OnActivate FocusOut\n");
		if (mousemode) {
			SetMouseMode(false);
		}
	} else {
		DMPRINTF("OnActivate FocusIn\n");
	}
}


//
// キー入力
//

// wxKeyEvent でキーコードを得るためのメソッドは
// GetKeyCode()、GetRawKeyCode()、GetRawKeyFlags() の3つが用意されていて
// wxWidgets の port (wxGTK、wxOSX とか) によってそれぞれ内容の定義が違う。
//
// wxGTK の場合
//  GetKeyCode() が論理キーコードなのでこれをメインに使う。ただし左右 [SHIFT]
//  のように論理キーコードだけでは区別の付かないものについては物理キー番号で
//  ある GetRawKeyFlags() を併用する。
//
//  以下詳細。
//  GetKeyCode() は wxWidgets の WXK_* (/usr/pkg/include/wx-3.0/wx/defs.h)。
//  これは概ね論理キーコードであり、xorg.conf の swapcaps 設定や Xmodmap の
//  影響をうける。
//   o 基本的に [SHIFT] キーの影響を受けないが、一部例外がある。
//     - [^] (0x5e) と [SHIFT]+[^] (0x30)
//     - [,] (0x2c) と [SHIFT]+[,] (0x3c)
//   o [\] と [_] は同じ 0x5c になる ([SHIFT] 押しながらでも同様)。
//   o [SHIFT], [CTRL], [ALT] の各左右キーは同じコードになる。
//
//  GetRawKeyFlags() は物理キー番号ようだ。GDK の hardware keycode らしいが、
//  それ以上の詳細は不明。
//   o 環境 (OS か X かライブラリ?) によって異なるようだ。
//     少なくとも NetBSD9 と Ubuntu20.04 では一部の値が異なる。
//   o [SHIFT] キーの影響を受けない。
//     GetKeyCode() では影響を受けた例外キーもここでは影響を受けない。
//   o [SHIFT], [CTRL], [ALT] の各左右キーは違うコードになる。
//
//  GetRawKeyCode() は GDK の keycode っぽい?
//   (/usr/pkg/include/gtk-2.0/gdk/gdkkeysyms.h)。
//   X11 の keysym から来てる? (/usr/X11R7/include/X11/keysymdef.h)。
//   ただし [A] と [SHIFT]+[A] が違うコードを返すというか、文字コードで表現
//   出来る時は文字コード、みたいな感じになっているのでここでは使いづらい。
//   左右の SHIFT は区別可能。
//
// wxOSX の場合
//  GetKeyCode()
//   英字キー [A] と [SHIFT]+[A] は同じコードになるが、
//   記号キー [1] と [SHIFT]+[1] は別になる体系のようだ。
//   左右の [SHIFT] は区別できない。
//
//  GetRawKeyCode()
//   これがたぶん物理キー番号。
//   [1] と [SHIFT]+[1] は同じコードを返す。
//   左右の [SHIFT] は区別可能。
//
//  GetRawKeyFlags() は状態フラグか何かのようだ。
//

// 入力モード変更
void
WXMainView::SetCharInputMode(bool enable)
{
	is_charinput = enable;
}

// キーを押した
void
WXMainView::OnKeyDown(wxKeyEvent& event)
{
	// メニューのアクセラレータのために必要
	event.Skip();

	if (is_charinput) {
		return;
	}

	DKPRINTF("KeyDown ");
	int keycode = GetKeyCode(event);
	if (richkbd) {
		richkbd->MakeKey(keycode);
	}
}

// キーを離した
void
WXMainView::OnKeyUp(wxKeyEvent& event)
{
	if (is_charinput) {
		return;
	}

	DKPRINTF("KeyUp   ");
	int keycode = GetKeyCode(event);
	if (richkbd) {
		richkbd->BreakKey(keycode);
	}
}

// 文字による入力モード
void
WXMainView::OnChar(wxKeyEvent& event)
{
	// メニューのアクセラレータのために必要
	event.Skip();

	if (!is_charinput) {
		return;
	}

	uint ukey = event.GetUnicodeKey();
	uint ukey_orig = ukey;
	DKPRINTF("Char    uni=0x%02x", ukey);
	if (0x20 <= ukey && ukey < 0x7f) {
		DKPRINTF(" '%c'", ukey);
	}

	bool ctrl = event.ControlDown();
	if (ctrl) {
		DKPRINTF(" CTRL");

		// Ctrl + A .. Ctrl + Z までは 0x01(^A) .. 0x1a(^Z) の文字が来るが、
		// Ctrl + 記号は記号の文字コードだけが送られてくるようだ。
		// Ctrl + [ は 0x1b('^[') ではなく 0x5b('[') のような感じ。
		// そこでこの場合は Ctrl キーが押されているかどうかを別途判定する。
		if (0x40 <= ukey && ukey <= 0x5f) {
			ukey -= 0x40;
			// Ctrl+@ ('\0') はそのまま通せないので、別文字にエスケープ。
			if (ukey == 0) {
				ukey = CC_NUL;
			}
		}
	}
	// 文字コードが拾えなければキーコードから
	if (ukey == WXK_NONE) {
		uint wxkey = event.GetKeyCode();
		DKPRINTF(" key=%3u(0x%03x)", wxkey, wxkey);
		// 一部の特殊キーをここで対応。
		// キーボード国籍による違いはないだろう。
		switch (wxkey) {
		 case WXK_LEFT:		ukey = CC_left;		break;
		 case WXK_UP:		ukey = CC_up;		break;
		 case WXK_RIGHT:	ukey = CC_right;	break;
		 case WXK_DOWN:		ukey = CC_down;		break;
		 case WXK_F1:		ukey = CC_F1;		break;
		 case WXK_F2:		ukey = CC_F2;		break;
		 case WXK_F3:		ukey = CC_F3;		break;
		 case WXK_F4:		ukey = CC_F4;		break;
		 case WXK_F5:		ukey = CC_F5;		break;
		 case WXK_F6:		ukey = CC_F6;		break;
		 case WXK_F7:		ukey = CC_F7;		break;
		 case WXK_F8:		ukey = CC_F8;		break;
		 case WXK_F9:		ukey = CC_F9;		break;
		 case WXK_F10:		ukey = CC_F10;		break;
		 case WXK_F11:		ukey = CC_F10;		break;
		 default:
			ukey = 0;
			break;
		}
	}
	if (ukey != ukey_orig) {
		DKPRINTF(" -> 0x%02x", ukey);
	}
	DKPRINTF("\n");
	if (ukey == 0) {
		return;
	}
	ukey &= 0xff;

	if (dumbkbd) {
		dumbkbd->CharInput(ukey);
	}
}

// 共通キーコードを取得する。
// 対応するキーがない場合は -1 を返す。
int
WXMainView::GetKeyCode(wxKeyEvent& event)
{
	uint32 wxcode   __unused = event.GetKeyCode();
	uint32 rawcode  __unused = event.GetRawKeyCode();
	uint32 rawflags __unused = event.GetRawKeyFlags();
	uint32 raw;
	int keycode;

	// wx キーコードは10進、16進併記しないと読みづらい
	DKPRINTF("key=%3d(0x%03x) ", wxcode, wxcode);
#if defined(__WXOSX__)
	// wxOSX では raw が物理キー、flags はフラグっぽいものなので不要
	DKPRINTF("raw=0x%02x (flags=0x%06x) ", rawcode, rawflags);
	raw = rawcode;
#else
	// wxGTK では flags が物理キー、raw は文字コードっぽいものなので不要
	DKPRINTF("flags=0x%02x (raw=0x%04x) ", rawflags, rawcode);
	raw = rawflags;
#endif

	// まず wx キーコードでテーブルを引く
	if (wxcode < countof(keycode_table)) {
		keycode = keycode_table[wxcode];
	} else {
		keycode = KC_none;
	}

	// wx キーコードは論理キーコードなので [SHIFT] キーの左右を区別できないが
	// ここでは左右を区別したいので、物理キー番号を見て区別する。
	if (keycode == KC_SHIFT) {
#if defined(__WXOSX__)
		if (raw == 0x3c)
#else
		if (raw == 0x3e)
#endif
		{
			keycode = KC_SHIFT_R;
		} else {
			keycode = KC_SHIFT_L;
		}
	}

#if defined(__WXGTK__)
	// wxGTK では日本語キーボードの一部のキーが論理キーコードだけでは
	// 判定できないようだ
	// その上 raw キーコードも OS (か何か) によってところどころ体系が
	// 異なるようだ。orz
	//
	// OS				[^]		[0]		[_]		[\]
	// ---------------	-----	-----	-----	-----
	// NetBSD9			0x15	0x13	0xd3	0x85
	// OpenBSD7.1		0x15	0x13	0xd3	0x85
	// Ubuntu20.04		0x15	0x13	0x61	0x84

	// [0] と [SHIFT]+[^] が同じキーコードになるようだ
	if (keycode == KC_0) {
		if (raw == 0x15) {
			keycode = KC_circum;
		} else {
			keycode = KC_0;
		}
	}
	// [\] と [_] が同じキーコードになるようだ。
	// その時の raw は OS によって(?)異なるようだ。
	if (keycode == KC_backslash) {
		switch (raw) {
		 case 0xd3:		// NetBSD9
		 case 0x61:		// Ubuntu20.04
			keycode = KC_underscore;
			break;
		 default:
			keycode = KC_backslash;
			break;
		}
	}
#endif

	DKPRINTF("keycode=%d %s\n", keycode, Keyboard::GetKeyName(keycode).c_str());
	return keycode;
}

// wx キーコード(WXK_*)を共通キーコードに変換するテーブル。
// 一部このテーブルだけでは判定できないものがある。すぐ上の GetKeyCode() 参照。
// 値 0 は本当は KC_none と書くべきだが、こっちのほうが読みやすいので。
//
// XXX: OSX の [CAPS] は押す離すで一回分の Down しか来ないのでちょっと放置。
// XXX: OSX の [英数] と [かな] もちょっと放置。
/*static*/ const int
WXMainView::keycode_table[0x190] = {
	0,				// 0x00
	0,				// 0x01
	0,				// 0x02
	0,				// 0x03
	0,				// 0x04
	0,				// 0x05
	0,				// 0x06
	0,				// 0x07
	KC_BS,			// 0x08 WXK_BACK
	KC_TAB,			// 0x09 WXK_TAB
	0,				// 0x0a
	0,				// 0x0b
	0,				// 0x0c
	KC_enter,		// 0x0d WXK_RETURN
	0,				// 0x0e
	0,				// 0x0f

	0,				// 0x10
	0,				// 0x11
	0,				// 0x12
	0,				// 0x13
	0,				// 0x14
	0,				// 0x15
	0,				// 0x16
	0,				// 0x17
	0,				// 0x18
	0,				// 0x19
	0,				// 0x1a
	KC_ESC,			// 0x1b WXK_ESCAPE
	0,				// 0x1c
	0,				// 0x1d
	0,				// 0x1e
	0,				// 0x1f

	KC_space,		// 0x20 WXK_SPACE
	KC_1,			// 0x21		(OSX: [SHIFT]+[1])
	KC_2,			// 0x22		(OSX: [SHIFT]+[2])
	KC_3,			// 0x23		(OSX: [SHIFT]+[3])
	KC_4,			// 0x24		(OSX: [SHIFT]+[4])
	KC_5,			// 0x25		(OSX: [SHIFT]+[5])
	KC_6,			// 0x26		(OSX: [SHIFT]+[6])
	KC_7,			// 0x27		(OSX: [SHIFT]+[7])
	KC_8,			// 0x28		(OSX: [SHIFT]+[8])
	KC_9,			// 0x29		(OSX: [SHIFT]+[9])
	KC_colon,		// 0x2a		(OSX: [SHIFT]+[:])
	KC_semicolon,	// 0x2b		(OSX: [SHIFT]+[;])
	KC_comma,		// 0x2c
	KC_minus,		// 0x2d
	KC_period,		// 0x2e
	KC_slash,		// 0x2f

	KC_0,			// 0x30		(GTK: [0] と [SHIFT]+[^])
	KC_1,			// 0x31
	KC_2,			// 0x32
	KC_3,			// 0x33
	KC_4,			// 0x34
	KC_5,			// 0x35
	KC_6,			// 0x36
	KC_7,			// 0x37
	KC_8,			// 0x38
	KC_9,			// 0x39
	KC_colon,		// 0x3a
	KC_semicolon,	// 0x3b
	KC_comma,		// 0x3c		(GTK: [,]は0x2c だが [SHIFT]+[,]は0x3c)
	KC_minus,		// 0x3d		(OSX: [SHIFT]+[-])
	KC_period,		// 0x3e		(OSX: [SHIFT]+[.])
	KC_slash,		// 0x3f		(OSX: [SHIFT]+[/])

	KC_at,			// 0x40
	KC_A,			// 0x41
	KC_B,			// 0x42
	KC_C,			// 0x43
	KC_D,			// 0x44
	KC_E,			// 0x45
	KC_F,			// 0x46
	KC_G,			// 0x47
	KC_H,			// 0x48
	KC_I,			// 0x49
	KC_J,			// 0x4a
	KC_K,			// 0x4b
	KC_L,			// 0x4c
	KC_M,			// 0x4d
	KC_N,			// 0x4e
	KC_O,			// 0x4f

	KC_P,			// 0x50
	KC_Q,			// 0x51
	KC_R,			// 0x52
	KC_S,			// 0x53
	KC_T,			// 0x54
	KC_U,			// 0x55
	KC_V,			// 0x56
	KC_W,			// 0x57
	KC_X,			// 0x58
	KC_Y,			// 0x59
	KC_Z,			// 0x5a
	KC_bracketleft,	// 0x5b
	KC_backslash,	// 0x5c		(GTK: [\] と [_])
	KC_bracketright,// 0x5d
	KC_circum,		// 0x5e
	KC_underscore,	// 0x5f		(OSX: [_])

	KC_at,			// 0x60		(OSX: [SHIFT]+[@])
	0,				// 0x61
	0,				// 0x62
	0,				// 0x63
	0,				// 0x64
	0,				// 0x65
	0,				// 0x66
	0,				// 0x67
	0,				// 0x68
	0,				// 0x69
	0,				// 0x6a
	0,				// 0x6b
	0,				// 0x6c
	0,				// 0x6d
	0,				// 0x6e
	0,				// 0x6f

	0,				// 0x70
	0,				// 0x71
	0,				// 0x72
	0,				// 0x73
	0,				// 0x74
	0,				// 0x75
	0,				// 0x76
	0,				// 0x77
	0,				// 0x78
	0,				// 0x79
	0,				// 0x7a
	KC_bracketleft,	// 0x7b		(OSX: [SHIFT]+[[])
	KC_backslash,	// 0x7c		(OSX: [SHIFT]+[\])
	KC_bracketright,// 0x7d		(OSX: [SHIFT]+[]])
	KC_circum,		// 0x7e		(OSX: [SHIFT]+[^])
	KC_DEL,			// 0x7f

	0,0,0,0, 0,0,0,0,	// 0x80
	0,0,0,0, 0,0,0,0,	// 0x88
	0,0,0,0, 0,0,0,0,	// 0x90
	0,0,0,0, 0,0,0,0,	// 0x98

	0,				// 0xa0
	0,				// 0xa1
	0,				// 0xa2
	0,				// 0xa3
	0,				// 0xa4
	KC_backslash,	// 0xa5		(OSX: [\])
	0,				// 0xa6
	0,				// 0xa7
	0,				// 0xa8
	0,				// 0xa9
	0,				// 0xaa
	0,				// 0xab
	0,				// 0xac
	0,				// 0xad
	0,				// 0xae
	0,				// 0xaf

	0,0,0,0, 0,0,0,0,	// 0xb0
	0,0,0,0, 0,0,0,0,	// 0xb8

	0,				// 0xc0=192
	0,				// 193 WXK_SPECIAL1
	0,				// 194 WXK_SPECIAL2
	0,				// 195 WXK_SPECIAL3
	0,				// 196 WXK_SPECIAL4
	0,				// 197 WXK_SPECIAL5
	0,				// 198 WXK_SPECIAL6
	0,				// 199 WXK_SPECIAL7

	0,				// 200 WXK_SPECIAL8
	0,				// 201 WXK_SPECIAL9
	0,				// 202 WXK_SPECIAL10
	0,				// 203 WXK_SPECIAL11
	0,				// 204 WXK_SPECIAL12
	0,				// 205 WXK_SPECIAL13
	0,				// 206 WXK_SPECIAL14
	0,				// 207 WXK_SPECIAL15
	0,				// 208 WXK_SPECIAL16
	0,				// 209 WXK_SPECIAL17

	0,				// 210 WXK_SPECIAL18
	0,				// 211 WXK_SPECIAL19
	0,				// 212 WXK_SPECIAL20
	0,				// 0xd5
	0,				// 0xd6
	0,				// 0xd7

	0,0,0,0, 0,0,0,0,	// 0xd8
	0,0,0,0, 0,0,0,0,	// 0xe0
	0,0,0,0, 0,0,0,0,	// 0xe8
	0,0,0,0, 0,0,0,0,	// 0xf0
	0,0,0,0, 0,0,0,0,	// 0xf8
	0,0,0,0, 0,0,0,0,	// 0x100
	0,0,0,0, 0,0,0,0,	// 0x108
	0,0,0,0, 0,0,0,0,	// 0x110
	0,0,0,0, 0,0,0,0,	// 0x118
	0,0,0,0, 0,0,0,0,	// 0x120

	0,				// 0x128
	0,				// 0x129
	0,				// 0x12a
	0,				// 0x12b
	//
	// WXK_* は10進数で定義されていて、特殊キーは 300 (=0x12c) から。
	//
	0,				// 300 WXK_START
	0,				// 301 WXK_LBUTTON
	0,				// 302 WXK_RBUTTON
	0,				// 303 WXK_CANCEL
	0,				// 304 WXK_MBUTTON
	0,				// 305 WXK_CLEAR
	KC_SHIFT,		// 306 WXK_SHIFT	(左右[SHIFT])
	0,				// 307 WXK_ALT
	KC_CTRL,		// 308 WXK_CONTROL	(ゲストに右[CTRL]はないので区別不要)
	0,				// 309 WXK_MENU

	0,				// 310 WXK_PAUSE
	0,				// 311 WXK_CAPITAL
	KC_UNDO,		// 312 WXK_END
	KC_HOME,		// 313 WXK_HOME
	KC_left,		// 314 WXK_LEFT
	KC_up,			// 315 WXK_UP
	KC_right,		// 316 WXK_RIGHT
	KC_down,		// 317 WXK_DOWN
	0,				// 318 WXK_SELECT
	0,				// 319 WXK_PRINT

	0,				// 320 WXK_EXECUTE
	0,				// 321 WXK_SNAPSHOT
	KC_INS,			// 322 WXK_INSERT
	0,				// 323 WXK_HELP
	KC_PAD_0,		// 324 WXK_NUMPAD0
	KC_PAD_1,		// 325 WXK_NUMPAD1
	KC_PAD_2,		// 326 WXK_NUMPAD2
	KC_PAD_3,		// 327 WXK_NUMPAD3
	KC_PAD_4,		// 328 WXK_NUMPAD4
	KC_PAD_5,		// 329 WXK_NUMPAD5

	KC_PAD_6,		// 330 WXK_NUMPAD6
	KC_PAD_7,		// 331 WXK_NUMPAD7
	KC_PAD_8,		// 332 WXK_NUMPAD8
	KC_PAD_9,		// 333 WXK_NUMPAD9
	0,				// 334 WXK_MULTIPLY
	0,				// 335 WXK_ADD
	0,				// 336 WXK_SEPARATOR
	0,				// 337 WXK_SUBTRACT
	0,				// 338 WXK_DECIMAL
	0,				// 339 WXK_DIVIDE

	KC_F1,			// 340 WXK_F1
	KC_F2,			// 341 WXK_F2
	KC_F3,			// 342 WXK_F3
	KC_F4,			// 343 WXK_F4
	KC_F5,			// 344 WXK_F5
	KC_F6,			// 345 WXK_F6
	KC_F7,			// 346 WXK_F7
	KC_F8,			// 347 WXK_F8
	KC_F9,			// 348 WXK_F9
	KC_F10,			// 349 WXK_F10

	KC_F10,			// 350 WXK_F11
	0,				// 351 WXK_F12
	0,				// 352 WXK_F13
	0,				// 353 WXK_F14
	0,				// 354 WXK_F15
	0,				// 355 WXK_F16
	0,				// 356 WXK_F17
	0,				// 357 WXK_F18
	0,				// 358 WXK_F19
	0,				// 359 WXK_F20

	0,				// 360 WXK_F21
	0,				// 361 WXK_F22
	0,				// 362 WXK_F23
	0,				// 363 WXK_F24
	0,				// 364 WXK_NUMLOCK
	0,				// 365 WXK_SCROLL
	KC_ROLLUP,		// 366 WXK_PAGEUP
	KC_ROLLDOWN,	// 367 WXK_PAGEDOWN
	0,				// 368 WXK_NUMPAD_SPACE
	0,				// 369 WXK_NUMPAD_TAB

	KC_PAD_enter,	// 370 WXK_NUMPAD_ENTER
	0,				// 371 WXK_NUMPAD_F1
	0,				// 372 WXK_NUMPAD_F2
	0,				// 373 WXK_NUMPAD_F3
	0,				// 374 WXK_NUMPAD_F4
	0,				// 375 WXK_NUMPAD_HOME
	0,				// 376 WXK_NUMPAD_LEFT
	0,				// 377 WXK_NUMPAD_UP
	0,				// 378 WXK_NUMPAD_RIGHT
	0,				// 379 WXK_NUMPAD_DOWN

	0,				// 380 WXK_NUMPAD_PAGEUP
	0,				// 381 WXK_NUMPAD_PAGEDOWN
	0,				// 382 WXK_NUMPAD_END
	0,				// 383 WXK_NUMPAD_BEGIN
	0,				// 384 WXK_NUMPAD_INSERT
	0,				// 385 WXK_NUMPAD_DELETE
	KC_PAD_equal,	// 386 WXK_NUMPAD_EQUAL
	KC_PAD_multiply,// 387 WXK_NUMPAD_MULTIPLY
	KC_PAD_plus,	// 388 WXK_NUMPAD_ADD
	0,				// 389 WXK_NUMPAD_SEPARATOR

	KC_PAD_minus,	// 390 WXK_NUMPAD_SUBTRACT
	KC_PAD_decimal,	// 391 WXK_NUMPAD_DECIMAL
	KC_PAD_divide,	// 392 WXK_NUMPAD_DIVIDE
	0,				// 393 WXK_WINDOWS_LEFT
	0,				// 394 WXK_WINDOWS_RIGHT
	0,				// 395 WXK_WINDOWS_MENU
	// WXK_RAW_CONTROL は wxOSX でのみ定義してあり (wxOSX 以外では別名)、
	// wxOSX とそれ以外とで定義済みキーの最大値が違う。そこが可変だとこの
	// テーブルが困るので、wxOSX 以外でも常に WXK_RAW_CONTROL 分の枠は用意
	// することにする。wxOSX 以外だと飛んでこないというだけで害はない。
	KC_CTRL,		// 396 WXK_RAW_CONTROL	(OSX)

	0,				// 397
	0,				// 398
	0,				// 399=0x18f
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.