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