feat(core): expose state and event API to WASM

This commit is contained in:
Eberhard Beilharz 2025-03-01 18:33:17 +01:00
parent 8e8816adc2
commit c297c66a64
No known key found for this signature in database
GPG key ID: E9140597606020D3
6 changed files with 116 additions and 17 deletions

View file

@ -1166,7 +1166,7 @@ returned by [km_core_keyboard_load_from_blob].
```c */
KMN_API
void
km_core_keyboard_dispose(km_core_keyboard *keyboard);
km_core_keyboard_dispose(km_core_keyboard const* keyboard);
/*
```
@ -1384,7 +1384,7 @@ the environment passed.
```c */
KMN_API
km_core_status
km_core_state_create(km_core_keyboard *keyboard,
km_core_state_create(km_core_keyboard const *keyboard,
km_core_option_item const *env,
km_core_state **out);
@ -1470,7 +1470,7 @@ invalid.
```c */
KMN_API
void
km_core_state_dispose(km_core_state *state);
km_core_state_dispose(km_core_state const *state);
/*
```
@ -1677,7 +1677,7 @@ the state may also be modified.
```c */
KMN_API
km_core_status
km_core_process_event(km_core_state *state,
km_core_process_event(km_core_state const *state,
km_core_virtual_key vk,
uint16_t modifier_state,
uint8_t is_key_down,
@ -1733,7 +1733,7 @@ the state may also be modified.
KMN_API
km_core_status
km_core_event(
km_core_state *state,
km_core_state const *state,
uint32_t event,
void* data
);

View file

@ -81,7 +81,7 @@ km_core_keyboard_load_from_blob(
}
void
km_core_keyboard_dispose(km_core_keyboard *keyboard)
km_core_keyboard_dispose(km_core_keyboard const* keyboard)
{
delete keyboard;
}

View file

@ -15,7 +15,7 @@
km_core_status
km_core_event(
km_core_state *state,
km_core_state const *state,
uint32_t event,
void* data
) {
@ -37,19 +37,20 @@ km_core_event(
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
return state->processor().external_event(state, event, data);
return const_cast<km_core_state*>(state)->processor().external_event(const_cast<km_core_state*>(state), event, data);
}
km_core_status
km_core_process_event(km_core_state *state,
km_core_process_event(km_core_state const *state_,
km_core_virtual_key vk,
uint16_t modifier_state,
uint8_t is_key_down,
uint16_t event_flags) {
assert(state != nullptr);
if(state == nullptr) {
assert(state_ != nullptr);
if(state_ == nullptr) {
return KM_CORE_STATUS_INVALID_ARGUMENT;
}
km_core_state *state = const_cast<km_core_state*>(state_);
km_core_status status = state->processor().process_event(state, vk, modifier_state, is_key_down, event_flags);
if (state_should_invalidate_context(state, vk, modifier_state, is_key_down, event_flags)) {

View file

@ -28,7 +28,7 @@ using namespace km::core;
// Forward declarations
class context;
km_core_status km_core_state_create(km_core_keyboard * keyboard,
km_core_status km_core_state_create(km_core_keyboard const *keyboard,
km_core_option_item const *env,
km_core_state ** out)
{
@ -38,7 +38,7 @@ km_core_status km_core_state_create(km_core_keyboard * keyboard,
try
{
*out = new km_core_state(static_cast<abstract_processor&>(*keyboard), env);
*out = new km_core_state(static_cast<abstract_processor&>(*const_cast<km_core_keyboard*>(keyboard)), env);
}
catch (std::bad_alloc &)
{
@ -60,7 +60,7 @@ km_core_status km_core_state_clone(km_core_state const *state,
}
void km_core_state_dispose(km_core_state *state)
void km_core_state_dispose(km_core_state const *state)
{
delete state;
}

View file

@ -9,8 +9,9 @@
#define EXTERN EMSCRIPTEN_KEEPALIVE
#endif
#include "processor.hpp"
#include <keyman_core.h>
#include "processor.hpp"
#include "state.hpp"
namespace em = emscripten;
@ -137,6 +138,30 @@ km_core_keyboard_get_attrs_wasm(const km_core_keyboard* keyboard) {
return new CoreReturn<km_core_keyboard_attrs_wasm>(retVal, attrs_wasm);
}
EMSCRIPTEN_KEEPALIVE const CoreReturn<km_core_state>*
km_core_state_create_wasm(const km_core_keyboard* keyboard,
const std::vector<km_core_option_item_wasm>& env) {
km_core_option_item* env_c = new km_core_option_item[env.size() + 1];
for (size_t i = 0; i < env.size(); ++i) {
env_c[i].key = env[i].key.c_str();
env_c[i].value = env[i].value.c_str();
env_c[i].scope = env[i].scope;
}
env_c[env.size()] = {nullptr, nullptr, 0};
km_core_state* state = nullptr;
km_core_status retVal = km_core_state_create(keyboard, env_c, &state);
delete[] env_c;
return new CoreReturn<km_core_state>(retVal, state);
}
EMSCRIPTEN_KEEPALIVE const CoreReturn<km_core_state>*
km_core_state_clone_wasm(const km_core_state* state) {
km_core_state* new_state = nullptr;
km_core_status retVal = km_core_state_clone(state, &new_state);
return new CoreReturn<km_core_state>(retVal, new_state);
}
EMSCRIPTEN_BINDINGS(core_interface) {
em::value_object<km_core_attr>("km_core_attr")
@ -184,7 +209,17 @@ EMSCRIPTEN_BINDINGS(core_interface) {
.property("id", &km_core_keyboard_attrs_wasm::id)
.property("default_options", &km_core_keyboard_attrs_wasm::default_options);
em::class_<km_core_state>("km_core_state");
em::class_<CoreReturn<km_core_state>>("CoreStateReturn")
.property("status", &CoreReturn<km_core_state>::getStatus)
.property("object", &CoreReturn<km_core_state>::getObject, em::allow_raw_pointers());
em::function("keyboard_load_from_blob", &km_core_keyboard_load_from_blob_wasm, em::allow_raw_pointers());
em::function("keyboard_dispose", &km_core_keyboard_dispose, em::allow_raw_pointers());
em::function("keyboard_get_attrs", &km_core_keyboard_get_attrs_wasm, em::allow_raw_pointers());
em::function("state_create", &km_core_state_create_wasm, em::allow_raw_pointers());
em::function("state_clone", &km_core_state_clone_wasm, em::allow_raw_pointers());
em::function("state_dispose", &km_core_state_dispose, em::allow_raw_pointers());
em::function("process_event", &km_core_process_event, em::allow_raw_pointers());
}
#endif

View file

@ -40,10 +40,25 @@ describe('Unit tests for wasm Core API', function () {
assert.isOk(result.object);
});
function loadKeyboard(name) {
const kmxdata = fs.readFileSync(path.join(__dirname, `tests/unit/kmx/${name}.kmx`));
const result = km_core.keyboard_load_from_blob(name, kmxdata);
assert.equal(result.status, 0);
assert.isOk(result.object);
return result.object;
}
it('can dispose keyboard', function () {
// Setup
const keyboard = loadKeyboard('k_020___deadkeys_and_backspace');
// Execute
km_core.keyboard_dispose(keyboard);
});
it('can get keyboard attributes', function () {
// Setup
const kmxdata = fs.readFileSync(path.join(__dirname, 'tests/unit/kmx/k_022___options_with_preset.kmx'));
const keyboard = km_core.keyboard_load_from_blob('k_022___options_with_preset', kmxdata).object;
const keyboard = loadKeyboard('k_022___options_with_preset');
// Execute
const result = km_core.keyboard_get_attrs(keyboard);
@ -55,4 +70,52 @@ describe('Unit tests for wasm Core API', function () {
assert.equal(result.object.version_string, '0.0');
assert.deepEqual(result.object.default_options, [{ key: 'foo', value: '0', scope: 1 }]);
});
it('can create the state object', function () {
// Setup
const keyboard = loadKeyboard('k_020___deadkeys_and_backspace');
// Execute
const result = km_core.state_create(keyboard, []);
// Verify
assert.equal(result.status, 0);
assert.isOk(result.object);
});
it('can dispose the state object', function () {
// Setup
const keyboard = loadKeyboard('k_020___deadkeys_and_backspace');
const state = km_core.state_create(keyboard, []);
// Execute
km_core.state_dispose(state.object);
});
it('can clone the state object', function () {
// Setup
const keyboard = loadKeyboard('k_020___deadkeys_and_backspace');
const state = km_core.state_create(keyboard, []);
// Execute
const result = km_core.state_clone(state.object);
// Verify
assert.equal(result.status, 0);
assert.isOk(result.object);
// TODO-web-core: add deeper tests
});
it('can process event', function () {
// Setup
const keyboard = loadKeyboard('k_020___deadkeys_and_backspace');
const state = km_core.state_create(keyboard, []);
// Execute
const status = km_core.process_event(state.object, 0x20, 0, 1, 0);
// Verify
assert.equal(status, 0);
// TODO-web-core: add more asserts
});
});