|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.4 root 7: #include "wxmainview.h"
1.1 root 8: #include "keyboard.h"
9: #include "renderer.h"
10: #include "scheduler.h"
11: #include <wx/region.h>
12: #include <wx/event.h>
13:
14: //#define KEYDEBUG 1
1.1.1.2 root 15: //#define MOUSEDEBUG 1
1.1 root 16:
17: #if defined(KEYDEBUG)
1.1.1.2 root 18: #define DKPRINTF(...) printf(__VA_ARGS__)
1.1 root 19: #else
1.1.1.2 root 20: #define DKPRINTF(...) /**/
21: #endif
22:
23: #if defined(MOUSEDEBUG)
24: #define DMPRINTF(...) printf(__VA_ARGS__)
25: #else
26: #define DMPRINTF(...) /**/
1.1 root 27: #endif
28:
29: // 再描画矩形の指定方法について。
30: // DoRefresh() にて、VM スレッドが自発的に画面を更新する際は、
31: // パフォーマンスの観点からも更新矩形だけを再描画すべき。
32: // これを wxWidgets に指示するのが wxWindow::Refresh{,Rect}() であるが
33: // 一部のプラットフォームではこれを呼び出すと、アプリケーションウィンドウ
34: // 全体がささってしまい、MainView だけでなくメニューバーも含めたすべてが
35: // 再描画できなくなってしまう。仕方がないので、これらのプラットフォームでは
36: // Refresh{,Rect}() を呼ばず、再描画矩形を画面全体として運用する。
37: // ちょっと無駄なだけなので (動かないことに比べれば) 気にしない。
38: //
1.1.1.4 root 39: // 今のところ NetBSD (5.0 以降) と OpenBSD(/amd64)(-6.7)
40: // (と Linux (CentOS 6.3/x86_64)) が該当する。
41: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.1 root 42: #define DONT_USE_REFRESH 1
43: #endif
44:
45: static void wxmainview_refresh();
46:
47: WXMainView *gMainView;
48:
49: wxBEGIN_EVENT_TABLE(WXMainView, inherited)
50: EVT_PAINT(WXMainView::OnPaint)
51: EVT_KEY_DOWN(WXMainView::OnKeyDown)
52: EVT_KEY_UP(WXMainView::OnKeyUp)
1.1.1.2 root 53: EVT_MOUSE_EVENTS(WXMainView::OnMouse)
1.1.1.5 root 54: EVT_TIMER(wxID_ANY, WXMainView::OnTimer)
1.1 root 55: wxEND_EVENT_TABLE()
56:
57: WXMainView::WXMainView(wxWindow *parent)
58: : inherited(parent)
59: {
60: // 仮想画面(VM が描画する画面)
61: rendwidth = gRenderer->GetWidth();
62: rendheight = gRenderer->GetHeight();
63:
64: // レンダラバッファは常に仮想画面サイズ
65: int buflen = rendwidth * rendheight * 3;
1.1.1.4 root 66: ImageBuf.reset(new uint8_t[buflen]);
67: memset(&ImageBuf[0], 0x70, buflen);
1.1 root 68: // レンダラに通知
1.1.1.4 root 69: gRenderer->SetBuf(ImageBuf.get(), wxmainview_refresh);
1.1 root 70:
71: // 実画面 (ウィンドウの大きさ)
72: DoResize(screen_scale);
73:
1.1.1.5 root 74: // 描画を律速するためのタイマー
75: timer.SetOwner(this);
76: timer.Start(33);
77:
78: // 最初に一度描画
79: Refresh();
1.1 root 80: }
81:
82: WXMainView::~WXMainView()
83: {
84: }
85:
86: // リフレッシュ要求コールバック。
87: // VM から呼ばれるので一旦グローバル関数を経由する。
88: void
89: wxmainview_refresh(void)
90: {
91: gMainView->DoRefresh();
92: }
93:
94: // リフレッシュ要求コールバック。こっちが実体。
95: void
96: WXMainView::DoRefresh()
97: {
98: #if defined(DONT_USE_REFRESH)
99: // Refresh{,Rect}() が使えないので、再描画範囲は常に全体とする
100: #else
101: // 再描画範囲を更新矩形に限定
102: // XXX のはずだが、今の所全体
103: RefreshRect(wxRect(0, 0, viewwidth, viewheight), false);
104: #endif
105:
1.1.1.5 root 106: // ここは VM Renderer が画面を更新した時に呼ばれるので、本来なら
107: // ここで単に Refresh() を呼んで再描画を指示すればいいのだが、
108: // VM 高速モードになると、VM Renderer が高速で回ってここも高速で
109: // 呼ばれてしまい、その結果 Refresh() を発行しすぎて Mac では
110: // システムイベントが拾えなくなってしまう。
111: // それを避けるため、ここではフラグを立てるだけにしておいて、
112: // こちらで管理している実時間タイマーで Refresh() を律速する。
113: paint_request = true;
1.1 root 114: }
115:
1.1.1.5 root 116: // タイマーイベント
1.1 root 117: void
118: WXMainView::OnTimer(wxTimerEvent& event)
119: {
1.1.1.5 root 120: bool req = paint_request.exchange(false);
1.1 root 121: if (req) {
1.1.1.5 root 122: // 実際に再描画する
123: Refresh();
1.1 root 124: }
125: }
126:
127: // 描画イベント
128: void
129: WXMainView::OnPaint(wxPaintEvent& event)
130: {
131: if (viewwidth == 0 || viewheight == 0)
132: return;
133:
1.1.1.4 root 134: wxImage image(rendwidth, rendheight, ImageBuf.get(), true);
1.1 root 135: if (viewwidth != rendwidth || viewheight != rendheight) {
1.1.1.6 root 136: // wxIMAGE_QUALITY_NORMAL だと速いが、ここは品質優先。
137: #if _BYTE_ORDER == _BIG_ENDIAN
138: // XXX ..のはずだったが wxWidget 3.0.4 の QUALITY_HIGH は
139: // BigEndian だとバグってるようだ。QUALITY_NORMAL のほうは大丈夫。
140: auto quality = wxIMAGE_QUALITY_NORMAL;
141: #else
142: auto quality = wxIMAGE_QUALITY_HIGH;
143: #endif
144: image.Rescale(viewwidth, viewheight, quality);
1.1 root 145: }
146:
147: wxBitmap bitmap(image);
148: wxMemoryDC memDC;
149: memDC.SelectObject(bitmap);
150:
1.1.1.5 root 151: wxPaintDC dc(this);
1.1 root 152: wxRegion region(0, 0, viewwidth, viewheight);
153: wxRegionIterator ri(region);
154: for (; ri; ri++) {
155: int dx, dy, dw, dh;
156: dx = ri.GetX();
157: dy = ri.GetY();
158: dw = ri.GetWidth();
159: dh = ri.GetHeight();
160: int sx = dx;
161: int sy = dy;
162: dc.Blit(dx, dy, dw, dh, &memDC, sx, sy, wxCOPY);
163: }
164: }
165:
166: // リサイズ (UI スレッドから呼ぶこと)
167: void
168: WXMainView::DoResize(double scale)
169: {
170: screen_scale = scale;
171: int width = (double)rendwidth * scale;
172: int height = (double)rendheight * scale;
173: if (viewwidth != width || viewheight != height) {
174: // ウィンドウサイズ変更
175: viewwidth = width;
176: viewheight = height;
177: SetClientSize(viewwidth, viewheight);
178: SetMinSize(wxSize(viewwidth, viewheight));
179: }
180: }
181:
182: // 現在のスケールを返す。
183: // screen_scale は public static なので見えるんだけど一応お行儀で。
184: double
185: WXMainView::GetScale() const
186: {
187: return screen_scale;
188: }
189:
190: // 現在のスケール
191: /*static*/ double WXMainView::screen_scale;
192:
193:
194: //
1.1.1.2 root 195: // マウス入力
196: //
197:
198: // マウスモード設定
199: void
200: WXMainView::SetMouseMode(bool mode)
201: {
202: // XXX マウスモード ON にした時の座標を記憶してそこに戻るのはどうか
203:
204: mousemode = mode;
205: if (mousemode) {
206: // マウスモードを ON にする
207: DMPRINTF("SetMouseMode ON\n");
208:
209: // マウスカーソル OFF
210: ::wxSetCursor(wxCursor(wxCURSOR_BLANK));
211:
1.1.1.4 root 212: CaptureMouse();
213:
1.1.1.2 root 214: // このウィンドウから外れないように移動を検出し続けるため、
215: // マウスカーソルをウィンドウ中央に移す。
216: // ウィンドウとメニューバーが分離してる wxOSX のために必要。
217: MyWarpPointer(GetClientSize() / 2);
218: } else {
219: // マウスモードを OFF にする
220: DMPRINTF("SetMouseMode OFF\n");
221:
1.1.1.4 root 222: ReleaseMouse();
223:
1.1.1.2 root 224: // 分かりやすさのため、マウスカーソルを中央へ戻してから復帰
1.1.1.4 root 225: wxSize pt = GetClientSize() / 2;
226: WarpPointer(pt.x, pt.y);
1.1.1.2 root 227:
228: // マウスカーソル ON
229: ::wxSetCursor(wxNullCursor);
230: }
231: }
232:
233: // マウスカーソルをクライアント座標 (x, y) に移動
234: void
235: WXMainView::MyWarpPointer(wxSize pos)
236: {
237: DMPRINTF("MyWarpPointer %d,%d\n", pos.x, pos.y);
238:
239: // この後の MDWarpPointer() でもう一度 EVT_MOTION が飛ぶので
240: // それを判別するためのフラグ。
241: motion_by_warp_pointer = true;
242:
243: WarpPointer(pos.x, pos.y);
244: }
245:
246: // マウスイベント
247: void
248: WXMainView::OnMouse(wxMouseEvent& event)
249: {
250: // マウスモードの時だけ処理。
251: // XXX 本当はイベントごと Disconnect したい
252: if (mousemode) {
253: bool leaving = event.Leaving();
254: bool moving = event.Moving();
1.1.1.3 root 255: bool dragging = event.Dragging();
1.1.1.2 root 256: // LeftDown() 等は押された時、LeftIsDown() 等は押されてる間 true。
257: bool rb = event.RightIsDown();
258: bool lb = event.LeftIsDown();
259: bool mb = event.MiddleIsDown();
1.1.1.5 root 260: const wxPoint& pos = event.GetPosition();
1.1.1.2 root 261: int dx = 0;
262: int dy = 0;
263:
1.1.1.3 root 264: #if defined(MOUSEDEBUG)
265: std::string dstr = "OnMouse";
266: if (moving || dragging || motion_by_warp_pointer) {
267: dstr += string_format(" (%d,%d)", pos.x, pos.y);
268: }
269: if (moving)
270: dstr += " Moving";
271: if (dragging)
272: dstr += " Dragging";
273: if (motion_by_warp_pointer)
274: dstr += " MotionByWarp";
1.1.1.4 root 275: if (lb || mb || rb) {
1.1.1.3 root 276: dstr += string_format(" Button(%c%c%c)",
277: (lb ? 'L' : '-'),
278: (mb ? 'M' : '-'),
279: (rb ? 'R' : '-'));
280: }
281: if (leaving)
282: dstr += " Leaving";
283: printf("%s\n", dstr.c_str());
284: #endif
1.1.1.2 root 285:
286: if (leaving) {
287: // タスクスイッチした時とかのための自動リリース
288: SetMouseMode(false);
289: }
290:
1.1.1.3 root 291: if (moving || dragging) {
1.1.1.2 root 292: // (My)WarpPointer() で自発的にマウスカーソルを移動させたことで
293: // 来る EVT_MOTION は無視する。
294: if (motion_by_warp_pointer) {
295: motion_by_warp_pointer = false;
296: // ここを基準点にする
297: prevpos = pos;
298: } else {
299: // 前回からの差を求める
300: dx = pos.x - prevpos.x;
301: dy = pos.y - prevpos.y;
302: prevpos = pos;
303:
304: // マウスカーソルを中心に戻す
305: if (dx != 0 || dy != 0) {
306: MyWarpPointer(GetClientSize() / 2);
307: }
308: }
309: }
310:
311: // VM に入力
1.1.1.3 root 312: if (dx != 0 ||
313: dy != 0 ||
314: lb != prevlb ||
315: mb != prevmb ||
316: rb != prevrb )
317: {
1.1.1.2 root 318: DMPRINTF(" Input dx=%d dy=%d %c%c%c\n",
319: dx, dy,
320: (lb ? 'L' : '-'),
321: (mb ? 'M' : '-'),
322: (rb ? 'R' : '-'));
323:
324: gKeyboard->MouseInput(dx, dy, rb, lb, mb);
325: }
1.1.1.3 root 326:
327: prevlb = lb;
328: prevmb = mb;
329: prevrb = rb;
1.1.1.2 root 330: }
331:
332: // EVT_LEFT_DOWN をデフォルト処理するため
333: event.Skip();
334: }
335:
1.1.1.4 root 336: // アクティベートイベント。
337: // この(トップレベル)ウィンドウにフォーカスが当たるか外れるかで飛んでくる。
338: // 実際には WXMainFrame 宛てに飛んできたイベントをこちらに転送してある。
339: // マウスモード中にこのウィンドウからフォーカスが外れたら (例えば ALT+TAB の
340: // ようなウィンドウを切り替える操作)、マウスモードを解除するため。
341: void
342: WXMainView::OnActivate(wxActivateEvent& event)
343: {
344: // フォーカスが外れる際にマウスモード中ならマウスモードを解除
345: if (event.GetActive() == false) {
346: DMPRINTF("OnActivate FocusOut\n");
347: if (mousemode) {
348: SetMouseMode(false);
349: }
350: } else {
351: DMPRINTF("OnActivate FocusIn\n");
352: }
353: }
354:
355:
1.1.1.2 root 356: //
1.1 root 357: // キー入力
358: //
359:
360: // wxKeyEvent でキーコードを得るためのメソッドは
361: // GetKeyCode()、GetRawKeyCode()、GetRawKeyFlags() の3つが用意されていて
362: // wxWigets の port (wxGTK、wxOSX とか) によってそれぞれ内容の定義が違う。
363: //
364: // wxGTK の場合
365: // GetKeyCode() は wxWidgets の WXK_* (/usr/pkg/include/wx-3.0/wx/defs.h)。
366: // これは左右の SHIFT が区別できないが、
367: // それ以外はだいたい使えそうではある。
368: //
369: // GetRawKeyCode() は GDK の keycode っぽい?
370: // (/usr/pkg/include/gtk-2.0/gdk/gdkkeysyms.h)。
371: // X11 の keysym から来てる? (/usr/X11R7/include/X11/keysymdef.h)。
372: // ただし [A] と [SHIFT]+[A] が違うコードを返すというか、文字コードで
373: // 表現出来る時は文字コード、みたいな感じになっているので、ここでは
374: // 使いづらい。
375: // 左右の SHIFT は区別可能。
376: // [^] と [SHIFT]+[^] もそもそも文字コードになるので '^' と '~' になる。
377: //
378: // GetRawKeyFlags() は GDK の hardware keycode らしいけど、それが何か不明。
379: // 左右の SHIFT は違うコードを返す。
380: // SHIFT を押しながらでもコードは変わらないっぽい。
381: // [^] と [SHIFT]+[^] は同じコードを返す。
382: //
383: // wxOSX の場合
384: // GetKeyCode()
385: // これは左右の SHIFT が区別できないが、
386: // それ以外はだいたい使えそうではある。
387: //
388: // GetRawKeyCode()
389: // [A] と [SHIFT]+[A] などは同じコードを返す。
390: // 左右の SHIFT は区別可能。
391: //
392: // GetRawKeyFlags() は状態フラグか何かのようだ。
393: //
394:
395: // キーを押した
396: void
397: WXMainView::OnKeyDown(wxKeyEvent& event)
398: {
1.1.1.2 root 399: DKPRINTF("KeyDown ");
1.1 root 400: int keycode = GetKeyCode(event);
401: gKeyboard->MakeKey(keycode);
1.1.1.2 root 402:
403: // メニューのアクセラレータのために必要
404: event.Skip();
1.1 root 405: }
406:
407: // キーを離した
408: void
409: WXMainView::OnKeyUp(wxKeyEvent& event)
410: {
1.1.1.2 root 411: DKPRINTF("KeyUp ");
1.1 root 412: int keycode = GetKeyCode(event);
413: gKeyboard->BreakKey(keycode);
414: }
415:
416: // 共通キーコードを取得する。
417: // 対応するキーがない場合は -1 を返す。
418: int
419: WXMainView::GetKeyCode(wxKeyEvent& event)
420: {
421: uint32 wxcode __unused = event.GetKeyCode();
422: uint32 rawcode __unused = event.GetRawKeyCode();
423: uint32 rawflags __unused = event.GetRawKeyFlags();
424: uint32 inp;
425: int keycode;
426:
427: #if defined(__WXGTK__)
428: // wxGTK では RawKeyFlags を使う
1.1.1.2 root 429: DKPRINTF("key=0x%03x raw=0x%04x <flags=0x%02x> ",
430: wxcode, rawcode, rawflags);
1.1 root 431: inp = rawflags;
432: #elif defined(__WXOSX__)
433: // wxOSX では RawKeyCode を使う
1.1.1.2 root 434: DKPRINTF("key=0x%03x <raw=0x%02x> flags=0x%06x ",
435: wxcode, rawcode, rawflags);
1.1 root 436: inp = rawcode;
437: #endif
438:
439: // どちらにしてもテーブルを引く
440: if (inp < countof(keycode_table)) {
441: keycode = keycode_table[inp];
442: } else {
443: keycode = KC_none;
444: }
1.1.1.2 root 445: DKPRINTF("keycode=%d %s\n", keycode, Keyboard::keyname[keycode]);
1.1 root 446: return keycode;
447: }
448:
449: #if defined(__WXGTK__)
450: // wxGTK の RawKeyFlags を共通キーコードに変換するテーブル。
451: /*static*/ const int
452: WXMainView::keycode_table[0xd4] = {
453: KC_none, // 0x00
454: KC_none, // 0x01
455: KC_none, // 0x02
456: KC_none, // 0x03
457: KC_none, // 0x04
458: KC_none, // 0x05
459: KC_none, // 0x06
460: KC_none, // 0x07
461: KC_none, // 0x08
462: KC_none, // 0x09
463: KC_1, // 0x0a
464: KC_2, // 0x0b
465: KC_3, // 0x0c
466: KC_4, // 0x0d
467: KC_5, // 0x0e
468: KC_6, // 0x0f
469:
470: KC_7, // 0x10
471: KC_8, // 0x11
472: KC_9, // 0x12
473: KC_0, // 0x13
474: KC_minus, // 0x14
475: KC_circum, // 0x15
476: KC_BS, // 0x16
477: KC_TAB, // 0x17
478: KC_Q, // 0x18
479: KC_W, // 0x19
480: KC_E, // 0x1a
481: KC_R, // 0x1b
482: KC_T, // 0x1c
483: KC_Y, // 0x1d
484: KC_U, // 0x1e
485: KC_I, // 0x1f
486:
487: KC_O, // 0x20
488: KC_P, // 0x21
489: KC_at, // 0x22
490: KC_bracketleft, // 0x23
491: KC_enter, // 0x24
492: KC_CTRL, // 0x25 (CTRL_L)
493: KC_A, // 0x26
494: KC_S, // 0x27
495: KC_D, // 0x28
496: KC_F, // 0x29
497: KC_G, // 0x2a
498: KC_H, // 0x2b
499: KC_J, // 0x2c
500: KC_K, // 0x2d
501: KC_L, // 0x2e
502: KC_semicolon, // 0x2f
503:
504: KC_colon, // 0x30
505: KC_ESC, // 0x31
506: KC_SHIFT_L, // 0x32 (SHIFT_L)
507: KC_bracketright,// 0x33
508: KC_Z, // 0x34
509: KC_X, // 0x35
510: KC_C, // 0x36
511: KC_V, // 0x37
512: KC_B, // 0x38
513: KC_N, // 0x39
514: KC_M, // 0x3a
515: KC_comma, // 0x3b
516: KC_period, // 0x3c
517: KC_slash, // 0x3d
518: KC_SHIFT_R, // 0x3e (SHIFT_R)
519: KC_PAD_multiply,// 0x3f
520:
521: KC_none, // 0x40
522: KC_space, // 0x41
523: KC_none, // 0x42
524: KC_F1, // 0x43
525: KC_F2, // 0x44
526: KC_F3, // 0x45
527: KC_F4, // 0x46
528: KC_F5, // 0x47
529: KC_F6, // 0x48
530: KC_F7, // 0x49
531: KC_F8, // 0x4a
532: KC_F9, // 0x4b
533: KC_F10, // 0x4c
534: KC_none, // 0x4d
535: KC_none, // 0x4e
536: KC_PAD_7, // 0x4f
537:
538: KC_PAD_8, // 0x50
539: KC_PAD_9, // 0x51
540: KC_PAD_minus, // 0x52
541: KC_PAD_4, // 0x53
542: KC_PAD_5, // 0x54
543: KC_PAD_6, // 0x55
544: KC_PAD_plus, // 0x56
545: KC_PAD_1, // 0x57
546: KC_PAD_2, // 0x58
547: KC_PAD_3, // 0x59
548: KC_PAD_0, // 0x5a
549: KC_PAD_decimal, // 0x5b
550: KC_none, // 0x5c
551: KC_none, // 0x5d
552: KC_none, // 0x5e
553: KC_none, // 0x5f
554:
555: KC_none, // 0x60
556: KC_none, // 0x61
557: KC_up, // 0x62
558: KC_none, // 0x63
559: KC_left, // 0x64
560: KC_none, // 0x65
561: KC_right, // 0x66
562: KC_none, // 0x67
563: KC_down, // 0x68
564: KC_none, // 0x69
565: KC_INS, // 0x6a
566: KC_DEL, // 0x6b
567: KC_PAD_enter, // 0x6c
568: KC_CTRL, // 0x6d (CTRL_R)
569: KC_none, // 0x6e
570: KC_none, // 0x6f
571:
572: KC_PAD_divide, // 0x70
573: KC_none, // 0x71
574: KC_none, // 0x72
575: KC_none, // 0x73
576: KC_none, // 0x74
577: KC_none, // 0x75
578: KC_none, // 0x76
579: KC_none, // 0x77
580: KC_none, // 0x78
581: KC_none, // 0x79
582: KC_none, // 0x7a
583: KC_none, // 0x7b
584: KC_none, // 0x7c
585: KC_none, // 0x7d
586: KC_none, // 0x7e
587: KC_none, // 0x7f
588:
589: KC_none, // 0x80
590: KC_none, // 0x81
591: KC_none, // 0x82
592: KC_none, // 0x83
593: KC_none, // 0x84
594: KC_backslash, // 0x85
595: KC_none, // 0x86
596: KC_none, // 0x87
597: KC_none, // 0x88
598: KC_none, // 0x89
599: KC_none, // 0x8a
600: KC_none, // 0x8b
601: KC_none, // 0x8c
602: KC_none, // 0x8d
603: KC_none, // 0x8e
604: KC_none, // 0x8f
605:
606: KC_none, KC_none, KC_none, KC_none, // 0x90
607: KC_none, KC_none, KC_none, KC_none,
608: KC_none, KC_none, KC_none, KC_none,
609: KC_none, KC_none, KC_none, KC_none,
610:
611: KC_none, KC_none, KC_none, KC_none, // 0xa0
612: KC_none, KC_none, KC_none, KC_none,
613: KC_none, KC_none, KC_none, KC_none,
614: KC_none, KC_none, KC_none, KC_none,
615:
616: KC_none, KC_none, KC_none, KC_none, // 0xb0
617: KC_none, KC_none, KC_none, KC_none,
618: KC_none, KC_none, KC_none, KC_none,
619: KC_none, KC_none, KC_none, KC_none,
620:
621: KC_none, KC_none, KC_none, KC_none, // 0xc0
622: KC_none, KC_none, KC_none, KC_none,
623: KC_none, KC_none, KC_none, KC_none,
624: KC_none, KC_none, KC_none, KC_none,
625:
626: KC_none, // 0xd0
627: KC_none, // 0xd1
628: KC_none, // 0xd2
629: KC_underscore, // 0xd3
630: };
631: #endif // __WXGTK__
632:
633: #if defined(__WXOSX__)
634: // wxOSX の RawKeyCode を共通キーコードに変換するテーブル。
635: // Mac の CAPS は押す離すで一回分の KeyDown しか来ないのでちょっと放置。
636: // [英数] と [かな] もちょっと放置。
637: /*static*/ const int
638: WXMainView::keycode_table[0x80] = {
639: KC_A, // 0x00
640: KC_S, // 0x01
641: KC_D, // 0x02
642: KC_F, // 0x03
643: KC_H, // 0x04
644: KC_G, // 0x05
645: KC_Z, // 0x06
646: KC_X, // 0x07
647: KC_C, // 0x08
648: KC_V, // 0x09
649: KC_none, // 0x0a
650: KC_B, // 0x0b
651: KC_Q, // 0x0c
652: KC_W, // 0x0d
653: KC_E, // 0x0e
654: KC_R, // 0x0f
655:
656: KC_Y, // 0x10
657: KC_T, // 0x11
658: KC_1, // 0x12
659: KC_2, // 0x13
660: KC_3, // 0x14
661: KC_4, // 0x15
662: KC_6, // 0x16
663: KC_5, // 0x17
664: KC_circum, // 0x18
665: KC_9, // 0x19
666: KC_7, // 0x1a
667: KC_minus, // 0x1b
668: KC_8, // 0x1c
669: KC_0, // 0x1d
670: KC_bracketleft, // 0x1e
671: KC_O, // 0x1f
672:
673: KC_U, // 0x20
674: KC_at, // 0x21
675: KC_I, // 0x22
676: KC_P, // 0x23
677: KC_enter, // 0x24
678: KC_L, // 0x25
679: KC_J, // 0x26
680: KC_colon, // 0x27
681: KC_K, // 0x28
682: KC_semicolon, // 0x29
683: KC_bracketright,// 0x2a
684: KC_comma, // 0x2b
685: KC_slash, // 0x2c
686: KC_N, // 0x2d
687: KC_M, // 0x2e
688: KC_period, // 0x2f
689:
690: KC_TAB, // 0x30
691: KC_space, // 0x31
692: KC_none, // 0x32
693: KC_BS, // 0x33
694: KC_none, // 0x34
695: KC_ESC, // 0x35
696: KC_none, // 0x36
697: KC_none, // 0x37
698: KC_SHIFT_L, // 0x38
699: KC_none, // 0x39
700: KC_none, // 0x3a
701: KC_CTRL, // 0x3b
702: KC_SHIFT_R, // 0x3c
703: KC_none, // 0x3d
704: KC_none, // 0x3e
705: KC_none, // 0x3f
706:
707: KC_none, // 0x40
708: KC_none, // 0x41
709: KC_none, // 0x42
710: KC_none, // 0x43
711: KC_none, // 0x44
712: KC_none, // 0x45
713: KC_none, // 0x46
714: KC_none, // 0x47
715: KC_none, // 0x48
716: KC_none, // 0x49
717: KC_none, // 0x4a
718: KC_none, // 0x4b
719: KC_none, // 0x4c
720: KC_none, // 0x4d
721: KC_none, // 0x4e
722: KC_none, // 0x4f
723:
724: KC_none, // 0x50
725: KC_none, // 0x51
726: KC_none, // 0x52
727: KC_none, // 0x53
728: KC_none, // 0x54
729: KC_none, // 0x55
730: KC_none, // 0x56
731: KC_none, // 0x57
732: KC_none, // 0x58
733: KC_none, // 0x59
734: KC_none, // 0x5a
735: KC_none, // 0x5b
736: KC_none, // 0x5c
737: KC_backslash, // 0x5d
738: KC_underscore, // 0x5e
739: KC_none, // 0x5f
740:
741: KC_F5, // 0x60
742: KC_F6, // 0x61
743: KC_F7, // 0x62
744: KC_F3, // 0x63
745: KC_F8, // 0x64
746: KC_F9, // 0x65
747: KC_none, // 0x66
748: KC_none, // 0x67 F11
749: KC_none, // 0x68
750: KC_none, // 0x69
751: KC_none, // 0x6a
752: KC_none, // 0x6b
753: KC_none, // 0x6c
754: KC_F10, // 0x6d
755: KC_none, // 0x6e
756: KC_none, // 0x6f F12
757:
758: KC_none, // 0x70
759: KC_none, // 0x71
760: KC_none, // 0x72
761: KC_none, // 0x73
762: KC_none, // 0x74
763: KC_none, // 0x75
764: KC_F4, // 0x76
765: KC_none, // 0x77
766: KC_F2, // 0x78
767: KC_none, // 0x79
768: KC_F1, // 0x7a
769: KC_left, // 0x7b
770: KC_right, // 0x7c
771: KC_down, // 0x7d
772: KC_up, // 0x7e
773: KC_none, // 0x7f
774: };
775: #endif // __WXOSX__
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.