Skip to content

Commit 5aeac19

Browse files
committed
EMCC: Emscripten version wip
- added keyboard handling - added text editing
1 parent 5598c41 commit 5aeac19

File tree

5 files changed

+296
-24
lines changed

5 files changed

+296
-24
lines changed

src/platform/emcc/canvas.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,11 +357,11 @@ void maDrawImageRegion(MAHandle maHandle, const MARect *srcRect, const MAPoint2d
357357
}
358358

359359
void maDrawRGB(const MAPoint2d *dstPoint, const void *src, const MARect *srcRect, int opacity, int stride) {
360-
logEntered();
360+
appLog("maDrawRGB not yet implemented");
361361
}
362362

363363
void maGetImageData(MAHandle maHandle, void *dst, const MARect *srcRect, int stride) {
364-
logEntered();
364+
appLog("maGetImageData not yet implemented");
365365
}
366366

367367
//

src/platform/emcc/keymap.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This file is part of SmallBASIC
2+
//
3+
// Copyright(C) 2001-2022 Chris Warren-Smith.
4+
//
5+
// This program is distributed under the terms of the GPL v2.0 or later
6+
// Download the GNU Public License (GPL) from www.gnu.org
7+
//
8+
9+
#pragma once
10+
11+
const int KEYMAP[][2] = {
12+
{DOM_VK_RETURN, SB_KEY_ENTER},
13+
{DOM_VK_ESCAPE, SB_KEY_ESCAPE},
14+
{DOM_VK_ENTER, SB_KEY_ENTER},
15+
{DOM_VK_TAB, SB_KEY_TAB},
16+
{DOM_VK_BACK_SPACE, SB_KEY_BACKSPACE},
17+
{DOM_VK_DELETE, SB_KEY_DELETE},
18+
{DOM_VK_UP, SB_KEY_UP},
19+
{DOM_VK_DOWN, SB_KEY_DN},
20+
{DOM_VK_LEFT, SB_KEY_LEFT},
21+
{DOM_VK_RIGHT, SB_KEY_RIGHT},
22+
{DOM_VK_PAGE_UP, SB_KEY_PGUP},
23+
{DOM_VK_PAGE_DOWN, SB_KEY_PGDN},
24+
{DOM_VK_HOME, SB_KEY_HOME},
25+
{DOM_VK_END, SB_KEY_END},
26+
{DOM_VK_INSERT, SB_KEY_INSERT},
27+
{DOM_VK_F1, SB_KEY_F(1)},
28+
{DOM_VK_F2, SB_KEY_F(2)},
29+
{DOM_VK_F3, SB_KEY_F(3)},
30+
{DOM_VK_F4, SB_KEY_F(4)},
31+
{DOM_VK_F5, SB_KEY_F(5)},
32+
{DOM_VK_F6, SB_KEY_F(6)},
33+
{DOM_VK_F7, SB_KEY_F(7)},
34+
{DOM_VK_F8, SB_KEY_F(8)},
35+
{DOM_VK_F9, SB_KEY_F(9)},
36+
{DOM_VK_F10, SB_KEY_F(10)},
37+
{DOM_VK_F11, SB_KEY_F(11)},
38+
{DOM_VK_F12, SB_KEY_F(12)}
39+
};
40+
41+
const int KEYMAP_LEN = sizeof(KEYMAP) / sizeof(KEYMAP[0]);
42+

src/platform/emcc/runtime.cpp

Lines changed: 247 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
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-
105103
char *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

116114
void 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

125149
void 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-
227248
void 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-
269487
bool 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

273501
void System::completeKeyword(int index) {

src/platform/emcc/runtime.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct Runtime : public System {
1919
void alert(const char *title, const char *message);
2020
int ask(const char *title, const char *prompt, bool cancel=true);
2121
void browseFile(const char *url);
22-
char *getClipboardText();
22+
char *getClipboardText() { return nullptr; }
2323
int getFontSize() { return _output->getFontSize(); }
2424
void enableCursor(bool enabled) {}
2525
int handle(int event);
@@ -37,7 +37,7 @@ struct Runtime : public System {
3737
bool run(const char *bas) { return execute(bas); }
3838
void runShell();
3939
void resize(int w, int h);
40-
void setClipboardText(const char *text);
40+
void setClipboardText(const char *text) {}
4141
void setFontSize(int size);
4242
void setLoadBreak(const char *url) {}
4343
void setLoadPath(const char *url) {}

0 commit comments

Comments
 (0)