99#include " config.h"
1010
1111#include < emscripten.h>
12+ #include < emscripten/key_codes.h>
1213#include " include/osd.h"
1314#include " common/smbas.h"
1415#include " lib/maapi.h"
1516#include " ui/utils.h"
1617#include " ui/theme.h"
1718#include " platform/emcc/runtime.h"
1819#include " platform/emcc/main_bas.h"
20+ #include " platform/emcc/keymap.h"
1921
2022#define MAIN_BAS " __main_bas__"
2123#define WAIT_INTERVAL 10
@@ -32,7 +34,7 @@ MAEvent *getMotionEvent(int type, const EmscriptenMouseEvent *event) {
3234 return result;
3335}
3436
35- MAEvent *getKeyPressedEvent (int keycode, int nativeKey) {
37+ MAEvent *getKeyPressedEvent (int keycode, int nativeKey = 0 ) {
3638 MAEvent *result = new MAEvent ();
3739 result->type = EVENT_TYPE_KEY_PRESSED;
3840 result->key = keycode;
@@ -98,10 +100,6 @@ void Runtime::browseFile(const char *url) {
98100 }, url);
99101}
100102
101- char *Runtime::getClipboardText () {
102- return nullptr ;
103- }
104-
105103char *Runtime::loadResource (const char *fileName) {
106104 logEntered ();
107105 char *buffer = System::loadResource (fileName);
@@ -114,12 +112,38 @@ char *Runtime::loadResource(const char *fileName) {
114112}
115113
116114void Runtime::handleKeyboard (int eventType, const EmscriptenKeyboardEvent *e) {
117- trace (" eventType: %d [%s %s %s] [%d %d %d] %s%s%s%s " ,
118- eventType,
119- e->key , e->code , e->charValue ,
120- e->charCode , e->keyCode , e->which ,
121- e->ctrlKey ? " CTRL" : " " , e->shiftKey ? " SHIFT" : " " , e->altKey ? " ALT" : " " , e->metaKey ? " META" : " " );
122-
115+ int keyCode = e->keyCode ;
116+ switch (e->keyCode ) {
117+ case DOM_VK_SHIFT:
118+ case DOM_VK_CONTROL:
119+ case DOM_VK_ALT:
120+ case DOM_VK_CAPS_LOCK:
121+ // ignore press without modifier key
122+ break ;
123+ default :
124+ for (int i = 0 ; i < KEYMAP_LEN; i++) {
125+ if (keyCode == KEYMAP[i][0 ]) {
126+ keyCode = KEYMAP[i][1 ];
127+ break ;
128+ }
129+ }
130+ if (e->ctrlKey && e->altKey ) {
131+ pushEvent (getKeyPressedEvent (SB_KEY_CTRL_ALT (keyCode)));
132+ } else if (e->ctrlKey && e->shiftKey ) {
133+ pushEvent (getKeyPressedEvent (SB_KEY_SHIFT_CTRL (keyCode)));
134+ } else if (e->altKey && e->shiftKey ) {
135+ pushEvent (getKeyPressedEvent (SB_KEY_ALT_SHIFT (keyCode)));
136+ } else if (e->ctrlKey ) {
137+ pushEvent (getKeyPressedEvent (SB_KEY_CTRL (keyCode)));
138+ } else if (e->altKey ) {
139+ pushEvent (getKeyPressedEvent (SB_KEY_ALT (keyCode)));
140+ } else if (e->shiftKey ) {
141+ pushEvent (getKeyPressedEvent (SB_KEY_SHIFT (keyCode)));
142+ } else {
143+ pushEvent (getKeyPressedEvent (keyCode));
144+ }
145+ break ;
146+ }
123147}
124148
125149void Runtime::handleMouse (int eventType, const EmscriptenMouseEvent *e) {
@@ -221,9 +245,6 @@ void Runtime::runShell() {
221245 _state = kDoneState ;
222246}
223247
224- void Runtime::setClipboardText (const char *text) {
225- }
226-
227248void Runtime::showCursor (CursorType cursorType) {
228249 static CursorType _cursorType;
229250 if (_cursorType != cursorType) {
@@ -234,6 +255,207 @@ void Runtime::showCursor(CursorType cursorType) {
234255 }
235256}
236257
258+ void System::editSource (strlib::String loadPath, bool restoreOnExit) {
259+ logEntered ();
260+
261+ strlib::String fileName;
262+ int i = loadPath.lastIndexOf (' /' , 0 );
263+ if (i != -1 ) {
264+ fileName = loadPath.substring (i + 1 );
265+ } else {
266+ fileName = loadPath;
267+ }
268+
269+ strlib::String dirtyFile;
270+ dirtyFile.append (" * " );
271+ dirtyFile.append (fileName);
272+ strlib::String cleanFile;
273+ cleanFile.append (" - " );
274+ cleanFile.append (fileName);
275+
276+ int w = _output->getWidth ();
277+ int h = _output->getHeight ();
278+ int charWidth = _output->getCharWidth ();
279+ int charHeight = _output->getCharHeight ();
280+ int prevScreenId = _output->selectScreen (SOURCE_SCREEN);
281+ TextEditInput *editWidget;
282+ if (_editor != nullptr ) {
283+ editWidget = _editor;
284+ editWidget->_width = w;
285+ editWidget->_height = h;
286+ } else {
287+ editWidget = new TextEditInput (_programSrc, charWidth, charHeight, 0 , 0 , w, h);
288+ }
289+ auto *helpWidget = new TextEditHelpWidget (editWidget, charWidth, charHeight, false );
290+ auto *widget = editWidget;
291+ _modifiedTime = getModifiedTime ();
292+ editWidget->updateUI (nullptr , nullptr );
293+ editWidget->setLineNumbers ();
294+ editWidget->setFocus (true );
295+
296+ _output->clearScreen ();
297+ _output->addInput (editWidget);
298+ _output->addInput (helpWidget);
299+
300+ if (gsb_last_line && isBreak ()) {
301+ String msg = " Break at line: " ;
302+ msg.append (gsb_last_line);
303+ alert (" Error" , msg);
304+ } else if (gsb_last_error && !isBack ()) {
305+ // program stopped with an error
306+ editWidget->setCursorRow (gsb_last_line + editWidget->getSelectionRow () - 1 );
307+ alert (" Error" , gsb_last_errmsg);
308+ }
309+
310+ bool showStatus = !editWidget->getScroll ();
311+ _srcRendered = false ;
312+ _output->setStatus (showStatus ? cleanFile : " " );
313+ _output->redraw ();
314+ _state = kEditState ;
315+
316+ while (_state == kEditState ) {
317+ MAEvent event = getNextEvent ();
318+ switch (event.type ) {
319+ case EVENT_TYPE_POINTER_PRESSED:
320+ if (!showStatus && widget == editWidget && event.point .x < editWidget->getMarginWidth ()) {
321+ _output->setStatus (editWidget->isDirty () ? dirtyFile : cleanFile);
322+ _output->redraw ();
323+ showStatus = true ;
324+ }
325+ break ;
326+ case EVENT_TYPE_POINTER_RELEASED:
327+ if (showStatus && event.point .x < editWidget->getMarginWidth () && editWidget->getScroll ()) {
328+ _output->setStatus (" " );
329+ _output->redraw ();
330+ showStatus = false ;
331+ }
332+ break ;
333+ case EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED:
334+ if (editWidget->isDirty () && !editWidget->getScroll ()) {
335+ _output->setStatus (dirtyFile);
336+ _output->redraw ();
337+ }
338+ break ;
339+ case EVENT_TYPE_KEY_PRESSED:
340+ if (_userScreenId == -1 ) {
341+ int sw = _output->getScreenWidth ();
342+ bool redraw = true ;
343+ bool dirty = editWidget->isDirty ();
344+ char *text;
345+
346+ switch (event.key ) {
347+ case SB_KEY_F (2 ):
348+ case SB_KEY_F (3 ):
349+ case SB_KEY_F (4 ):
350+ case SB_KEY_F (5 ):
351+ case SB_KEY_F (6 ):
352+ case SB_KEY_F (7 ):
353+ case SB_KEY_F (8 ):
354+ case SB_KEY_F (10 ):
355+ case SB_KEY_F (11 ):
356+ case SB_KEY_F (12 ):
357+ case SB_KEY_MENU:
358+ case SB_KEY_ESCAPE:
359+ case SB_KEY_BREAK:
360+ // unhandled keys
361+ redraw = false ;
362+ break ;
363+ case SB_KEY_F (1 ):
364+ widget = helpWidget;
365+ helpWidget->createKeywordIndex ();
366+ helpWidget->showPopup (-4 , -2 );
367+ helpWidget->setFocus (true );
368+ showStatus = false ;
369+ break ;
370+ case SB_KEY_F (9 ):
371+ _state = kRunState ;
372+ if (editWidget->isDirty ()) {
373+ saveFile (editWidget, loadPath);
374+ }
375+ break ;
376+ case SB_KEY_CTRL (' s' ):
377+ saveFile (editWidget, loadPath);
378+ break ;
379+ case SB_KEY_CTRL (' c' ):
380+ case SB_KEY_CTRL (' x' ):
381+ text = widget->copy (event.key == (int )SB_KEY_CTRL (' x' ));
382+ if (text) {
383+ setClipboardText (text);
384+ free (text);
385+ }
386+ break ;
387+ case SB_KEY_CTRL (' v' ):
388+ text = getClipboardText ();
389+ widget->paste (text);
390+ free (text);
391+ break ;
392+ case SB_KEY_CTRL (' o' ):
393+ _output->selectScreen (USER_SCREEN1);
394+ showCompletion (true );
395+ _output->redraw ();
396+ _state = kActiveState ;
397+ waitForBack ();
398+ _output->selectScreen (SOURCE_SCREEN);
399+ _state = kEditState ;
400+ break ;
401+ default :
402+ redraw = widget->edit (event.key , sw, charWidth);
403+ break ;
404+ }
405+ if (editWidget->isDirty () != dirty && !editWidget->getScroll ()) {
406+ _output->setStatus (editWidget->isDirty () ? dirtyFile : cleanFile);
407+ }
408+ if (redraw) {
409+ _output->redraw ();
410+ }
411+ }
412+ }
413+
414+ if (isBack () && widget == helpWidget) {
415+ widget = editWidget;
416+ helpWidget->hide ();
417+ editWidget->setFocus (true );
418+ _state = kEditState ;
419+ _output->redraw ();
420+ }
421+
422+ if (widget->isDirty ()) {
423+ int choice = -1 ;
424+ if (isClosing ()) {
425+ choice = 0 ;
426+ } else if (isBack ()) {
427+ const char *message = " The current file has not been saved.\n "
428+ " Would you like to save it now?" ;
429+ choice = ask (" Save changes?" , message, isBack ());
430+ }
431+ if (choice == 0 ) {
432+ widget->save (loadPath);
433+ } else if (choice == 2 ) {
434+ // cancel
435+ _state = kEditState ;
436+ }
437+ }
438+ }
439+
440+ if (_state == kRunState ) {
441+ // allow the editor to be restored on return
442+ if (!_output->removeInput (editWidget)) {
443+ trace (" Failed to remove editor input" );
444+ }
445+ _editor = editWidget;
446+ _editor->setFocus (false );
447+ } else {
448+ _editor = nullptr ;
449+ }
450+
451+ // deletes editWidget unless it has been removed
452+ _output->removeInputs ();
453+ if (!isClosing () && restoreOnExit) {
454+ _output->selectScreen (prevScreenId);
455+ }
456+ logLeaving ();
457+ }
458+
237459//
238460// ma event handling
239461//
@@ -262,12 +484,18 @@ void maWait(int timeout) {
262484//
263485// System platform methods
264486//
265- void System::editSource (strlib::String loadPath, bool restoreOnExit) {
266- // empty
267- }
268-
269487bool System::getPen3 () {
270- return false ;
488+ bool result = false ;
489+ if (_touchX != -1 && _touchY != -1 ) {
490+ result = true ;
491+ } else {
492+ // get mouse
493+ processEvents (0 );
494+ if (_touchX != -1 && _touchY != -1 ) {
495+ result = true ;
496+ }
497+ }
498+ return result;
271499}
272500
273501void System::completeKeyword (int index) {
0 commit comments