|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2018 [email protected]
4: //
5:
6: #include "wxheader.h"
7: #include "keyboard.h"
8: #include "renderer.h"
9: #include "scheduler.h"
10: #include "wxmainview.h"
11: #include <wx/region.h>
12: #include <wx/event.h>
13: #if defined(__NetBSD__)
14: #include <sys/param.h> // __NetBSD_Version__
15: #endif
16:
17: //#define KEYDEBUG 1
18:
19: #if defined(KEYDEBUG)
20: #define DPRINTF(...) printf(__VA_ARGS__)
21: #else
22: #define DPRINTF(...) /**/
23: #endif
24:
25: // 再描画矩形の指定方法について。
26: // DoRefresh() にて、VM スレッドが自発的に画面を更新する際は、
27: // パフォーマンスの観点からも更新矩形だけを再描画すべき。
28: // これを wxWidgets に指示するのが wxWindow::Refresh{,Rect}() であるが
29: // 一部のプラットフォームではこれを呼び出すと、アプリケーションウィンドウ
30: // 全体がささってしまい、MainView だけでなくメニューバーも含めたすべてが
31: // 再描画できなくなってしまう。仕方がないので、これらのプラットフォームでは
32: // Refresh{,Rect}() を呼ばず、再描画矩形を画面全体として運用する。
33: // ちょっと無駄なだけなので (動かないことに比べれば) 気にしない。
34: //
35: // 今のところ NetBSD 5.0 以上(と Linux (CentOS 6.3/x86_64)) が該当する。
36: #if defined(__NetBSD__) && __NetBSD_Version__ >= 500000000
37: #define DONT_USE_REFRESH 1
38: #endif
39:
40: #define TIMERID_PAINTTIMER 1
41:
42: static void wxmainview_refresh();
43:
44: WXMainView *gMainView;
45:
46: wxBEGIN_EVENT_TABLE(WXMainView, inherited)
47: EVT_PAINT(WXMainView::OnPaint)
48: EVT_KEY_DOWN(WXMainView::OnKeyDown)
49: EVT_KEY_UP(WXMainView::OnKeyUp)
50: EVT_TIMER(TIMERID_PAINTTIMER, WXMainView::OnTimer)
51: wxEND_EVENT_TABLE()
52:
53: WXMainView::WXMainView(wxWindow *parent)
54: : inherited(parent)
55: {
56: // 仮想画面(VM が描画する画面)
57: rendwidth = gRenderer->GetWidth();
58: rendheight = gRenderer->GetHeight();
59:
60: // レンダラバッファは常に仮想画面サイズ
61: int buflen = rendwidth * rendheight * 3;
62: ImageBuf = new uint8_t[buflen];
63: memset(ImageBuf, 0x70, buflen);
64: // レンダラに通知
65: gRenderer->SetBuf(ImageBuf, wxmainview_refresh);
66:
67: // 実画面 (ウィンドウの大きさ)
68: DoResize(screen_scale);
69:
70: paintTimer.SetOwner(this, TIMERID_PAINTTIMER);
71: paintTimer.Start(16);
72: paintRequested = true; // first paint request
73: }
74:
75: WXMainView::~WXMainView()
76: {
77: delete[] ImageBuf;
78: }
79:
80: // リフレッシュ要求コールバック。
81: // VM から呼ばれるので一旦グローバル関数を経由する。
82: void
83: wxmainview_refresh(void)
84: {
85: gMainView->DoRefresh();
86: }
87:
88: // リフレッシュ要求コールバック。こっちが実体。
89: void
90: WXMainView::DoRefresh()
91: {
92: #if defined(DONT_USE_REFRESH)
93: // Refresh{,Rect}() が使えないので、再描画範囲は常に全体とする
94: #else
95: // 再描画範囲を更新矩形に限定
96: // XXX のはずだが、今の所全体
97: RefreshRect(wxRect(0, 0, viewwidth, viewheight), false);
98: #endif
99:
100: // PAINT イベントを投げる
101: // XXX んだけど mac だと投げすぎるとシステムイベントを拾えなくなってしまう
102: paintRequested = true;
103: }
104:
105: void
106: WXMainView::OnTimer(wxTimerEvent& event)
107: {
108: bool req = paintRequested.exchange(false);
109: if (req) {
110: // PAINT イベントを投げる
111: wxPaintEvent *ev = new wxPaintEvent();
112: QueueEvent(ev);
113: }
114: }
115:
116: // 描画イベント
117: void
118: WXMainView::OnPaint(wxPaintEvent& event)
119: {
120: wxClientDC dc(this);
121:
122: DoPaint(dc);
123: }
124:
125: // 描画実行
126: void
127: WXMainView::DoPaint(wxDC& dc)
128: {
129: if (viewwidth == 0 || viewheight == 0)
130: return;
131:
132: wxImage image(rendwidth, rendheight, ImageBuf, true);
133:
134: if (viewwidth != rendwidth || viewheight != rendheight) {
135: // wxIMAGE_QUALITY_NORMAL だと速いが、品質優先。
136: image.Rescale(viewwidth, viewheight, wxIMAGE_QUALITY_HIGH);
137: }
138:
139: wxBitmap bitmap(image);
140: wxMemoryDC memDC;
141: memDC.SelectObject(bitmap);
142:
143: wxRegion region(0, 0, viewwidth, viewheight);
144: wxRegionIterator ri(region);
145: for (; ri; ri++) {
146: int dx, dy, dw, dh;
147: dx = ri.GetX();
148: dy = ri.GetY();
149: dw = ri.GetWidth();
150: dh = ri.GetHeight();
151: int sx = dx;
152: int sy = dy;
153: dc.Blit(dx, dy, dw, dh, &memDC, sx, sy, wxCOPY);
154: }
155: }
156:
157: // リサイズ (UI スレッドから呼ぶこと)
158: void
159: WXMainView::DoResize(double scale)
160: {
161: screen_scale = scale;
162: int width = (double)rendwidth * scale;
163: int height = (double)rendheight * scale;
164: if (viewwidth != width || viewheight != height) {
165: // ウィンドウサイズ変更
166: viewwidth = width;
167: viewheight = height;
168: SetClientSize(viewwidth, viewheight);
169: SetMinSize(wxSize(viewwidth, viewheight));
170: }
171: }
172:
173: // 現在のスケールを返す。
174: // screen_scale は public static なので見えるんだけど一応お行儀で。
175: double
176: WXMainView::GetScale() const
177: {
178: return screen_scale;
179: }
180:
181: // 現在のスケール
182: /*static*/ double WXMainView::screen_scale;
183:
184:
185: //
186: // キー入力
187: //
188:
189: // wxKeyEvent でキーコードを得るためのメソッドは
190: // GetKeyCode()、GetRawKeyCode()、GetRawKeyFlags() の3つが用意されていて
191: // wxWigets の port (wxGTK、wxOSX とか) によってそれぞれ内容の定義が違う。
192: //
193: // wxGTK の場合
194: // GetKeyCode() は wxWidgets の WXK_* (/usr/pkg/include/wx-3.0/wx/defs.h)。
195: // これは左右の SHIFT が区別できないが、
196: // それ以外はだいたい使えそうではある。
197: //
198: // GetRawKeyCode() は GDK の keycode っぽい?
199: // (/usr/pkg/include/gtk-2.0/gdk/gdkkeysyms.h)。
200: // X11 の keysym から来てる? (/usr/X11R7/include/X11/keysymdef.h)。
201: // ただし [A] と [SHIFT]+[A] が違うコードを返すというか、文字コードで
202: // 表現出来る時は文字コード、みたいな感じになっているので、ここでは
203: // 使いづらい。
204: // 左右の SHIFT は区別可能。
205: // [^] と [SHIFT]+[^] もそもそも文字コードになるので '^' と '~' になる。
206: //
207: // GetRawKeyFlags() は GDK の hardware keycode らしいけど、それが何か不明。
208: // 左右の SHIFT は違うコードを返す。
209: // SHIFT を押しながらでもコードは変わらないっぽい。
210: // [^] と [SHIFT]+[^] は同じコードを返す。
211: //
212: // wxOSX の場合
213: // GetKeyCode()
214: // これは左右の SHIFT が区別できないが、
215: // それ以外はだいたい使えそうではある。
216: //
217: // GetRawKeyCode()
218: // [A] と [SHIFT]+[A] などは同じコードを返す。
219: // 左右の SHIFT は区別可能。
220: //
221: // GetRawKeyFlags() は状態フラグか何かのようだ。
222: //
223:
224: // キーを押した
225: void
226: WXMainView::OnKeyDown(wxKeyEvent& event)
227: {
228: DPRINTF("KeyDown ");
229: int keycode = GetKeyCode(event);
230: gKeyboard->MakeKey(keycode);
231: }
232:
233: // キーを離した
234: void
235: WXMainView::OnKeyUp(wxKeyEvent& event)
236: {
237: DPRINTF("KeyUp ");
238: int keycode = GetKeyCode(event);
239: gKeyboard->BreakKey(keycode);
240: }
241:
242: // 共通キーコードを取得する。
243: // 対応するキーがない場合は -1 を返す。
244: int
245: WXMainView::GetKeyCode(wxKeyEvent& event)
246: {
247: uint32 wxcode __unused = event.GetKeyCode();
248: uint32 rawcode __unused = event.GetRawKeyCode();
249: uint32 rawflags __unused = event.GetRawKeyFlags();
250: uint32 inp;
251: int keycode;
252:
253: #if defined(__WXGTK__)
254: // wxGTK では RawKeyFlags を使う
255: DPRINTF("key=0x%03x raw=0x%04x <flags=0x%02x> ", wxcode, rawcode, rawflags);
256: inp = rawflags;
257: #elif defined(__WXOSX__)
258: // wxOSX では RawKeyCode を使う
259: DPRINTF("key=0x%03x <raw=0x%02x> flags=0x%06x ", wxcode, rawcode, rawflags);
260: inp = rawcode;
261: #endif
262:
263: // どちらにしてもテーブルを引く
264: if (inp < countof(keycode_table)) {
265: keycode = keycode_table[inp];
266: } else {
267: keycode = KC_none;
268: }
269: DPRINTF("keycode=%d %s\n", keycode, Keyboard::keyname[keycode]);
270: return keycode;
271: }
272:
273: #if defined(__WXGTK__)
274: // wxGTK の RawKeyFlags を共通キーコードに変換するテーブル。
275: /*static*/ const int
276: WXMainView::keycode_table[0xd4] = {
277: KC_none, // 0x00
278: KC_none, // 0x01
279: KC_none, // 0x02
280: KC_none, // 0x03
281: KC_none, // 0x04
282: KC_none, // 0x05
283: KC_none, // 0x06
284: KC_none, // 0x07
285: KC_none, // 0x08
286: KC_none, // 0x09
287: KC_1, // 0x0a
288: KC_2, // 0x0b
289: KC_3, // 0x0c
290: KC_4, // 0x0d
291: KC_5, // 0x0e
292: KC_6, // 0x0f
293:
294: KC_7, // 0x10
295: KC_8, // 0x11
296: KC_9, // 0x12
297: KC_0, // 0x13
298: KC_minus, // 0x14
299: KC_circum, // 0x15
300: KC_BS, // 0x16
301: KC_TAB, // 0x17
302: KC_Q, // 0x18
303: KC_W, // 0x19
304: KC_E, // 0x1a
305: KC_R, // 0x1b
306: KC_T, // 0x1c
307: KC_Y, // 0x1d
308: KC_U, // 0x1e
309: KC_I, // 0x1f
310:
311: KC_O, // 0x20
312: KC_P, // 0x21
313: KC_at, // 0x22
314: KC_bracketleft, // 0x23
315: KC_enter, // 0x24
316: KC_CTRL, // 0x25 (CTRL_L)
317: KC_A, // 0x26
318: KC_S, // 0x27
319: KC_D, // 0x28
320: KC_F, // 0x29
321: KC_G, // 0x2a
322: KC_H, // 0x2b
323: KC_J, // 0x2c
324: KC_K, // 0x2d
325: KC_L, // 0x2e
326: KC_semicolon, // 0x2f
327:
328: KC_colon, // 0x30
329: KC_ESC, // 0x31
330: KC_SHIFT_L, // 0x32 (SHIFT_L)
331: KC_bracketright,// 0x33
332: KC_Z, // 0x34
333: KC_X, // 0x35
334: KC_C, // 0x36
335: KC_V, // 0x37
336: KC_B, // 0x38
337: KC_N, // 0x39
338: KC_M, // 0x3a
339: KC_comma, // 0x3b
340: KC_period, // 0x3c
341: KC_slash, // 0x3d
342: KC_SHIFT_R, // 0x3e (SHIFT_R)
343: KC_PAD_multiply,// 0x3f
344:
345: KC_none, // 0x40
346: KC_space, // 0x41
347: KC_none, // 0x42
348: KC_F1, // 0x43
349: KC_F2, // 0x44
350: KC_F3, // 0x45
351: KC_F4, // 0x46
352: KC_F5, // 0x47
353: KC_F6, // 0x48
354: KC_F7, // 0x49
355: KC_F8, // 0x4a
356: KC_F9, // 0x4b
357: KC_F10, // 0x4c
358: KC_none, // 0x4d
359: KC_none, // 0x4e
360: KC_PAD_7, // 0x4f
361:
362: KC_PAD_8, // 0x50
363: KC_PAD_9, // 0x51
364: KC_PAD_minus, // 0x52
365: KC_PAD_4, // 0x53
366: KC_PAD_5, // 0x54
367: KC_PAD_6, // 0x55
368: KC_PAD_plus, // 0x56
369: KC_PAD_1, // 0x57
370: KC_PAD_2, // 0x58
371: KC_PAD_3, // 0x59
372: KC_PAD_0, // 0x5a
373: KC_PAD_decimal, // 0x5b
374: KC_none, // 0x5c
375: KC_none, // 0x5d
376: KC_none, // 0x5e
377: KC_none, // 0x5f
378:
379: KC_none, // 0x60
380: KC_none, // 0x61
381: KC_up, // 0x62
382: KC_none, // 0x63
383: KC_left, // 0x64
384: KC_none, // 0x65
385: KC_right, // 0x66
386: KC_none, // 0x67
387: KC_down, // 0x68
388: KC_none, // 0x69
389: KC_INS, // 0x6a
390: KC_DEL, // 0x6b
391: KC_PAD_enter, // 0x6c
392: KC_CTRL, // 0x6d (CTRL_R)
393: KC_none, // 0x6e
394: KC_none, // 0x6f
395:
396: KC_PAD_divide, // 0x70
397: KC_none, // 0x71
398: KC_none, // 0x72
399: KC_none, // 0x73
400: KC_none, // 0x74
401: KC_none, // 0x75
402: KC_none, // 0x76
403: KC_none, // 0x77
404: KC_none, // 0x78
405: KC_none, // 0x79
406: KC_none, // 0x7a
407: KC_none, // 0x7b
408: KC_none, // 0x7c
409: KC_none, // 0x7d
410: KC_none, // 0x7e
411: KC_none, // 0x7f
412:
413: KC_none, // 0x80
414: KC_none, // 0x81
415: KC_none, // 0x82
416: KC_none, // 0x83
417: KC_none, // 0x84
418: KC_backslash, // 0x85
419: KC_none, // 0x86
420: KC_none, // 0x87
421: KC_none, // 0x88
422: KC_none, // 0x89
423: KC_none, // 0x8a
424: KC_none, // 0x8b
425: KC_none, // 0x8c
426: KC_none, // 0x8d
427: KC_none, // 0x8e
428: KC_none, // 0x8f
429:
430: KC_none, KC_none, KC_none, KC_none, // 0x90
431: KC_none, KC_none, KC_none, KC_none,
432: KC_none, KC_none, KC_none, KC_none,
433: KC_none, KC_none, KC_none, KC_none,
434:
435: KC_none, KC_none, KC_none, KC_none, // 0xa0
436: KC_none, KC_none, KC_none, KC_none,
437: KC_none, KC_none, KC_none, KC_none,
438: KC_none, KC_none, KC_none, KC_none,
439:
440: KC_none, KC_none, KC_none, KC_none, // 0xb0
441: KC_none, KC_none, KC_none, KC_none,
442: KC_none, KC_none, KC_none, KC_none,
443: KC_none, KC_none, KC_none, KC_none,
444:
445: KC_none, KC_none, KC_none, KC_none, // 0xc0
446: KC_none, KC_none, KC_none, KC_none,
447: KC_none, KC_none, KC_none, KC_none,
448: KC_none, KC_none, KC_none, KC_none,
449:
450: KC_none, // 0xd0
451: KC_none, // 0xd1
452: KC_none, // 0xd2
453: KC_underscore, // 0xd3
454: };
455: #endif // __WXGTK__
456:
457: #if defined(__WXOSX__)
458: // wxOSX の RawKeyCode を共通キーコードに変換するテーブル。
459: // Mac の CAPS は押す離すで一回分の KeyDown しか来ないのでちょっと放置。
460: // [英数] と [かな] もちょっと放置。
461: /*static*/ const int
462: WXMainView::keycode_table[0x80] = {
463: KC_A, // 0x00
464: KC_S, // 0x01
465: KC_D, // 0x02
466: KC_F, // 0x03
467: KC_H, // 0x04
468: KC_G, // 0x05
469: KC_Z, // 0x06
470: KC_X, // 0x07
471: KC_C, // 0x08
472: KC_V, // 0x09
473: KC_none, // 0x0a
474: KC_B, // 0x0b
475: KC_Q, // 0x0c
476: KC_W, // 0x0d
477: KC_E, // 0x0e
478: KC_R, // 0x0f
479:
480: KC_Y, // 0x10
481: KC_T, // 0x11
482: KC_1, // 0x12
483: KC_2, // 0x13
484: KC_3, // 0x14
485: KC_4, // 0x15
486: KC_6, // 0x16
487: KC_5, // 0x17
488: KC_circum, // 0x18
489: KC_9, // 0x19
490: KC_7, // 0x1a
491: KC_minus, // 0x1b
492: KC_8, // 0x1c
493: KC_0, // 0x1d
494: KC_bracketleft, // 0x1e
495: KC_O, // 0x1f
496:
497: KC_U, // 0x20
498: KC_at, // 0x21
499: KC_I, // 0x22
500: KC_P, // 0x23
501: KC_enter, // 0x24
502: KC_L, // 0x25
503: KC_J, // 0x26
504: KC_colon, // 0x27
505: KC_K, // 0x28
506: KC_semicolon, // 0x29
507: KC_bracketright,// 0x2a
508: KC_comma, // 0x2b
509: KC_slash, // 0x2c
510: KC_N, // 0x2d
511: KC_M, // 0x2e
512: KC_period, // 0x2f
513:
514: KC_TAB, // 0x30
515: KC_space, // 0x31
516: KC_none, // 0x32
517: KC_BS, // 0x33
518: KC_none, // 0x34
519: KC_ESC, // 0x35
520: KC_none, // 0x36
521: KC_none, // 0x37
522: KC_SHIFT_L, // 0x38
523: KC_none, // 0x39
524: KC_none, // 0x3a
525: KC_CTRL, // 0x3b
526: KC_SHIFT_R, // 0x3c
527: KC_none, // 0x3d
528: KC_none, // 0x3e
529: KC_none, // 0x3f
530:
531: KC_none, // 0x40
532: KC_none, // 0x41
533: KC_none, // 0x42
534: KC_none, // 0x43
535: KC_none, // 0x44
536: KC_none, // 0x45
537: KC_none, // 0x46
538: KC_none, // 0x47
539: KC_none, // 0x48
540: KC_none, // 0x49
541: KC_none, // 0x4a
542: KC_none, // 0x4b
543: KC_none, // 0x4c
544: KC_none, // 0x4d
545: KC_none, // 0x4e
546: KC_none, // 0x4f
547:
548: KC_none, // 0x50
549: KC_none, // 0x51
550: KC_none, // 0x52
551: KC_none, // 0x53
552: KC_none, // 0x54
553: KC_none, // 0x55
554: KC_none, // 0x56
555: KC_none, // 0x57
556: KC_none, // 0x58
557: KC_none, // 0x59
558: KC_none, // 0x5a
559: KC_none, // 0x5b
560: KC_none, // 0x5c
561: KC_backslash, // 0x5d
562: KC_underscore, // 0x5e
563: KC_none, // 0x5f
564:
565: KC_F5, // 0x60
566: KC_F6, // 0x61
567: KC_F7, // 0x62
568: KC_F3, // 0x63
569: KC_F8, // 0x64
570: KC_F9, // 0x65
571: KC_none, // 0x66
572: KC_none, // 0x67 F11
573: KC_none, // 0x68
574: KC_none, // 0x69
575: KC_none, // 0x6a
576: KC_none, // 0x6b
577: KC_none, // 0x6c
578: KC_F10, // 0x6d
579: KC_none, // 0x6e
580: KC_none, // 0x6f F12
581:
582: KC_none, // 0x70
583: KC_none, // 0x71
584: KC_none, // 0x72
585: KC_none, // 0x73
586: KC_none, // 0x74
587: KC_none, // 0x75
588: KC_F4, // 0x76
589: KC_none, // 0x77
590: KC_F2, // 0x78
591: KC_none, // 0x79
592: KC_F1, // 0x7a
593: KC_left, // 0x7b
594: KC_right, // 0x7c
595: KC_down, // 0x7d
596: KC_up, // 0x7e
597: KC_none, // 0x7f
598: };
599: #endif // __WXOSX__
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.