Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/windy/platforms/emscripten/emdefs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@ EM_JS(void, open_url, (const char* url), {
window.open(urlUtf8, '_blank');
});

EM_JS(void, setup_paste_handler, (const char* target, void* userData), {
var canvas = document.querySelector(UTF8ToString(target));
canvas.addEventListener('paste', function(event) {
if (!event.clipboardData) return;
var text = event.clipboardData.getData('text/plain');
var size = lengthBytesUTF8(text) + 1;
var pointer = _malloc(size);
stringToUTF8(text, pointer, size);
try {
if (Module._windy_paste_callback(userData, pointer)) {
event.preventDefault();
}
} finally {
_free(pointer);
}
});
});

EM_JS(void, setup_drag_drop_handlers_internal, (const char* target, void* userData), {
const canvas = target ? document.querySelector(UTF8ToString(target)) : Module.canvas;
if (!canvas) {
Expand Down Expand Up @@ -329,6 +347,7 @@ proc get_device_pixel_ratio*(): cdouble {.importc.}
proc open_temp_text_file*(title, text: cstring) {.importc.}
proc open_url*(url: cstring) {.importc.}
proc setup_drag_drop_handlers_internal*(target: cstring, userData: pointer) {.importc.}
proc setup_paste_handler*(target: cstring, userData: pointer) {.importc.}
proc set_cursor*(cursor: cstring) {.importc.}
proc getLocalStorageLength*(key: cstring): cint {.importc: "get_local_storage_length".}
proc getLocalStorageInto*(output: cstring, maxLen: cint, key: cstring): cint {.importc: "get_local_storage_into".}
Expand Down
33 changes: 27 additions & 6 deletions src/windy/platforms/emscripten/platform.nim
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ var
frameDispatchActive: bool
pendingResize: bool
pendingFocusChange: bool
clipboardText: string

proc handleButtonPress(window: Window, button: Button)
proc handleButtonRelease(window: Window, button: Button)
Expand Down Expand Up @@ -375,7 +376,8 @@ proc buttonToggle*(window: Window): ButtonView =

# Clipboard functions
proc clipboardContent*(): string =
"" # Would need JavaScript interop
## Returns the text supplied by the latest browser paste event.
clipboardText

proc `clipboardContent=`*(content: string) =
discard # Would need JavaScript interop
Expand Down Expand Up @@ -508,11 +510,8 @@ proc setClipboardString*(s: string) =
)

proc getClipboardString*(): string =
# TODO: Implement clipboard with Emscripten.
raise newException(
Exception,
"getClipboardString is not supported on emscripten"
)
## Returns the text supplied by the latest browser paste event.
clipboardText

proc getClipboardContentKinds*(): set[ClipboardContentKind] =
## Image clipboard is not implemented on Emscripten yet.
Expand Down Expand Up @@ -795,6 +794,10 @@ proc onKeyDown(eventType: cint, keyEvent: ptr EmscriptenKeyboardEvent, userData:
button = keyEventToButton(keyEvent)
key = $cast[cstring](addr keyEvent.key[0])
window.syncModifiers(keyEvent, button, pressed = true)
if window.runeInputEnabled and button == KeyV and
(keyEvent.metaKey or (keyEvent.ctrlKey and not keyEvent.altKey)):
# Let the browser deliver clipboard text before notifying the editor.
return 0
if button != ButtonUnknown:
window.handleButtonPress(button)
if window.runeInputEnabled and not keyEvent.metaKey and
Expand Down Expand Up @@ -902,6 +905,7 @@ proc setupEventHandlers(window: Window) =

# Drag and drop handler
setup_drag_drop_handlers_internal(window.canvas, cast[pointer](window))
setup_paste_handler(window.canvas, cast[pointer](window))

proc handleButtonPress(window: Window, button: Button) =
handleButtonPressTemplate()
Expand All @@ -912,6 +916,23 @@ proc handleButtonRelease(window: Window, button: Button) =
proc handleRune(window: Window, rune: Rune) =
handleRuneTemplate()

proc windy_paste_callback(userData: pointer, text: cstring): cint {.
exportc, cdecl, codegenDecl: "EMSCRIPTEN_KEEPALIVE $# $#$#"
.} =
## Delivers browser clipboard text as one editor paste operation.
let window = cast[Window](userData)
if window == nil or not window.runeInputEnabled:
return 0
clipboardText = $text
let previous = window.state.buttonDown
window.state.buttonDown.excl(KeyLeftAlt)
window.state.buttonDown.excl(KeyRightAlt)
window.state.buttonDown.incl(KeyLeftControl)
window.handleButtonPress(KeyV)
window.handleButtonRelease(KeyV)
window.state.buttonDown = previous
return 1

proc windy_file_drop_callback(userData: pointer, fileNamePtr: cstring, fileDataPtr: pointer, fileDataLen: cint) {.exportc, cdecl, codegenDecl: "EMSCRIPTEN_KEEPALIVE $# $#$#".} =
## callback to handle the file drop event.
## EMSCRIPTEN_KEEPALIVE is required to avoid dead code elimination.
Expand Down
6 changes: 6 additions & 0 deletions tests/manual_inputs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ window.onButtonPress = proc(button: Button) =
window.runeInputEnabled = not window.runeInputEnabled
of KeyEscape:
text.setLen(0)
of KeyV:
if window.runeInputEnabled and
(set[Button](window.buttonDown) * {
KeyLeftControl, KeyRightControl, KeyLeftSuper, KeyRightSuper
}) != {}:
text.add(getClipboardString().toRunes())
else:
discard
updateTitle()
Expand Down
Loading