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