768 lines
22 KiB
Plaintext
768 lines
22 KiB
Plaintext
var video = use('sdl_video');
|
|
|
|
log.console("STATED VIDE")
|
|
|
|
// SDL Video Actor
|
|
// This actor runs on the main thread and handles all SDL video operations
|
|
var surface = use('surface');
|
|
var input = use('input')
|
|
|
|
var ren
|
|
var win
|
|
|
|
var default_window = {
|
|
// Basic properties
|
|
title: "Prosperon Window",
|
|
width: 640,
|
|
height: 480,
|
|
|
|
// Position - can be numbers or "centered"
|
|
x: undefined, // SDL_WINDOWPOS_UNDEFINED by default
|
|
y: undefined, // SDL_WINDOWPOS_UNDEFINED by default
|
|
|
|
// Window behavior flags
|
|
resizable: true,
|
|
fullscreen: false,
|
|
hidden: false,
|
|
borderless: false,
|
|
alwaysOnTop: false,
|
|
minimized: false,
|
|
maximized: false,
|
|
|
|
// Input grabbing
|
|
mouseGrabbed: false,
|
|
keyboardGrabbed: false,
|
|
|
|
// Display properties
|
|
highPixelDensity: false,
|
|
transparent: false,
|
|
opacity: 1.0, // 0.0 to 1.0
|
|
|
|
// Focus behavior
|
|
notFocusable: false,
|
|
|
|
// Special window types (mutually exclusive)
|
|
utility: false, // Utility window (not in taskbar)
|
|
tooltip: false, // Tooltip window (requires parent)
|
|
popupMenu: false, // Popup menu window (requires parent)
|
|
|
|
// Graphics API flags (let SDL choose if not specified)
|
|
opengl: false, // Force OpenGL context
|
|
vulkan: false, // Force Vulkan context
|
|
metal: false, // Force Metal context (macOS)
|
|
|
|
// Advanced properties
|
|
parent: undefined, // Parent window for tooltips/popups/modal
|
|
modal: false, // Modal to parent window (requires parent)
|
|
externalGraphicsContext: false, // Use external graphics context
|
|
|
|
// Input handling
|
|
textInput: true, // Enable text input on creation
|
|
};
|
|
|
|
var config = Object.assign({}, default_window, arg[0] || {});
|
|
win = new video.window(config);
|
|
|
|
// Resource tracking
|
|
var resources = {
|
|
texture: {},
|
|
surface: {},
|
|
cursor: {}
|
|
};
|
|
|
|
// ID counter for resource allocation
|
|
var next_id = 1;
|
|
|
|
// Helper to allocate new ID
|
|
function allocate_id() {
|
|
return next_id++;
|
|
}
|
|
|
|
// Message handler
|
|
$_.receiver(function(msg) {
|
|
if (!msg.kind || !msg.op) {
|
|
send(msg, {error: "Message must have 'kind' and 'op' fields"});
|
|
return;
|
|
}
|
|
|
|
var response = {};
|
|
|
|
try {
|
|
switch (msg.kind) {
|
|
case 'window':
|
|
response = handle_window(msg);
|
|
break;
|
|
case 'renderer':
|
|
response = handle_renderer(msg);
|
|
break;
|
|
case 'texture':
|
|
response = handle_texture(msg);
|
|
break;
|
|
case 'surface':
|
|
response = handle_surface(msg);
|
|
break;
|
|
case 'cursor':
|
|
response = handle_cursor(msg);
|
|
break;
|
|
case 'mouse':
|
|
response = handle_mouse(msg);
|
|
break;
|
|
case 'keyboard':
|
|
response = handle_keyboard(msg);
|
|
break;
|
|
case 'input':
|
|
response = input.get_events();
|
|
break;
|
|
default:
|
|
response = {error: "Unknown kind: " + msg.kind};
|
|
}
|
|
} catch (e) {
|
|
response = {error: e.toString()};
|
|
log.error(e)
|
|
}
|
|
|
|
send(msg, response);
|
|
});
|
|
|
|
// Window operations
|
|
function handle_window(msg) {
|
|
switch (msg.op) {
|
|
case 'destroy':
|
|
win.destroy();
|
|
win = undefined
|
|
return {success: true};
|
|
|
|
case 'show':
|
|
win.visible = true;
|
|
return {success: true};
|
|
|
|
case 'hide':
|
|
win.visible = false;
|
|
return {success: true};
|
|
|
|
case 'get':
|
|
var prop = msg.data ? msg.data.property : null;
|
|
if (!prop) return {error: "Missing property name"};
|
|
|
|
// Handle special cases
|
|
if (prop === 'surface') {
|
|
var surf = win.surface;
|
|
if (!surf) return {data: null};
|
|
var surf_id = allocate_id();
|
|
resources.surface[surf_id] = surf;
|
|
return {data: surf_id};
|
|
}
|
|
|
|
return {data: win[prop]};
|
|
|
|
case 'set':
|
|
var prop = msg.data ? msg.data.property : null;
|
|
var value = msg.data ? msg.data.value : undefined;
|
|
if (!prop) return {error: "Missing property name"};
|
|
|
|
// Validate property is settable
|
|
var readonly = ['id', 'pixelDensity', 'displayScale', 'sizeInPixels', 'flags', 'surface'];
|
|
if (readonly.indexOf(prop) !== -1) {
|
|
return {error: "Property '" + prop + "' is read-only"};
|
|
}
|
|
|
|
win[prop] = value;
|
|
return {success: true};
|
|
|
|
case 'fullscreen':
|
|
win.fullscreen();
|
|
return {success: true};
|
|
|
|
case 'updateSurface':
|
|
win.updateSurface();
|
|
return {success: true};
|
|
|
|
case 'updateSurfaceRects':
|
|
if (!msg.data || !msg.data.rects) return {error: "Missing rects array"};
|
|
win.updateSurfaceRects(msg.data.rects);
|
|
return {success: true};
|
|
|
|
case 'raise':
|
|
win.raise();
|
|
return {success: true};
|
|
|
|
case 'restore':
|
|
win.restore();
|
|
return {success: true};
|
|
|
|
case 'flash':
|
|
win.flash(msg.data ? msg.data.operation : 'briefly');
|
|
return {success: true};
|
|
|
|
case 'sync':
|
|
win.sync();
|
|
return {success: true};
|
|
|
|
case 'setIcon':
|
|
if (!msg.data || !msg.data.surface_id) return {error: "Missing surface_id"};
|
|
var surf = resources.surface[msg.data.surface_id];
|
|
if (!surf) return {error: "Invalid surface id"};
|
|
win.set_icon(surf);
|
|
return {success: true};
|
|
|
|
case 'makeRenderer':
|
|
log.console("MAKE RENDERER")
|
|
if (ren)
|
|
return {reason: "Already made a renderer"}
|
|
ren = win.make_renderer()
|
|
return {success:true};
|
|
|
|
default:
|
|
return {error: "Unknown window operation: " + msg.op};
|
|
}
|
|
}
|
|
|
|
// Renderer operations
|
|
function handle_renderer(msg) {
|
|
if (!ren) return{reason:'no renderer!'}
|
|
|
|
switch (msg.op) {
|
|
case 'destroy':
|
|
ren = undefined
|
|
return {success: true};
|
|
|
|
case 'clear':
|
|
ren.clear();
|
|
return {success: true};
|
|
|
|
case 'present':
|
|
ren.present();
|
|
return {success: true};
|
|
|
|
case 'flush':
|
|
ren.flush();
|
|
return {success: true};
|
|
|
|
case 'get':
|
|
var prop = msg.data ? msg.data.property : null;
|
|
if (!prop) return {error: "Missing property name"};
|
|
|
|
// Handle special getters that might return objects
|
|
if (prop === 'drawColor') {
|
|
var color = ren[prop];
|
|
if (color && typeof color === 'object') {
|
|
// Convert color object to array format [r,g,b,a]
|
|
return {data: [color.r || 0, color.g || 0, color.b || 0, color.a || 255]};
|
|
}
|
|
}
|
|
|
|
return {data: ren[prop]};
|
|
|
|
case 'set':
|
|
var prop = msg.prop
|
|
var value = msg.value
|
|
if (!prop) return {error: "Missing property name"};
|
|
|
|
if (!value) return {error: "No value to set"}
|
|
|
|
// Validate property is settable
|
|
var readonly = ['window', 'name', 'outputSize', 'currentOutputSize', 'logicalPresentationRect', 'safeArea'];
|
|
if (readonly.indexOf(prop) !== -1) {
|
|
return {error: "Property '" + prop + "' is read-only"};
|
|
}
|
|
|
|
// Special handling for render target
|
|
if (prop === 'target' && value !== null && value !== undefined) {
|
|
var tex = resources.texture[value];
|
|
if (!tex) return {error: "Invalid texture id"};
|
|
value = tex;
|
|
}
|
|
|
|
ren[prop] = value;
|
|
return {success: true};
|
|
|
|
case 'line':
|
|
if (!msg.data || !msg.data.points) return {error: "Missing points array"};
|
|
ren.line(msg.data.points);
|
|
return {success: true};
|
|
|
|
case 'point':
|
|
if (!msg.data || !msg.data.points) return {error: "Missing points"};
|
|
ren.point(msg.data.points);
|
|
return {success: true};
|
|
|
|
case 'rect':
|
|
if (!msg.data || !msg.data.rect) return {error: "Missing rect"};
|
|
ren.rect(msg.data.rect);
|
|
return {success: true};
|
|
|
|
case 'fillRect':
|
|
if (!msg.data || !msg.data.rect) return {error: "Missing rect"};
|
|
ren.fillRect(msg.data.rect);
|
|
return {success: true};
|
|
|
|
case 'rects':
|
|
if (!msg.data || !msg.data.rects) return {error: "Missing rects"};
|
|
ren.rects(msg.data.rects);
|
|
return {success: true};
|
|
|
|
case 'lineTo':
|
|
if (!msg.data || !msg.data.a || !msg.data.b) return {error: "Missing points a and b"};
|
|
ren.lineTo(msg.data.a, msg.data.b);
|
|
return {success: true};
|
|
|
|
case 'texture':
|
|
if (!msg.data) return {error: "Missing texture data"};
|
|
var tex_id = msg.data.texture_id;
|
|
if (!tex_id || !resources.texture[tex_id]) return {error: "Invalid texture id"};
|
|
ren.texture(
|
|
resources.texture[tex_id],
|
|
msg.data.src,
|
|
msg.data.dst,
|
|
msg.data.angle || 0,
|
|
msg.data.anchor || {x:0.5, y:0.5}
|
|
);
|
|
return {success: true};
|
|
|
|
case 'copyTexture':
|
|
if (!msg.data) return {error: "Missing texture data"};
|
|
var tex_id = msg.data.texture_id;
|
|
if (!tex_id || !resources.texture[tex_id]) return {error: "Invalid texture id"};
|
|
var tex = resources.texture[tex_id];
|
|
|
|
// Use the texture method with normalized coordinates
|
|
ren.texture(
|
|
tex,
|
|
msg.data.src || {x:0, y:0, width:tex.width, height:tex.height},
|
|
msg.data.dest || {x:0, y:0, width:tex.width, height:tex.height},
|
|
0, // No rotation
|
|
{x:0, y:0} // Top-left anchor
|
|
);
|
|
return {success: true};
|
|
|
|
case 'sprite':
|
|
if (!msg.data || !msg.data.sprite) return {error: "Missing sprite data"};
|
|
ren.sprite(msg.data.sprite);
|
|
return {success: true};
|
|
|
|
case 'geometry':
|
|
if (!msg.data) return {error: "Missing geometry data"};
|
|
var tex_id = msg.data.texture_id;
|
|
var tex = tex_id ? resources.texture[tex_id] : null;
|
|
ren.geometry(tex, msg.data.geometry);
|
|
return {success: true};
|
|
|
|
case 'debugText':
|
|
if (!msg.data || !msg.data.text) return {error: "Missing text"};
|
|
ren.debugText([msg.data.pos.x, msg.data.pos.y], msg.data.text);
|
|
return {success: true};
|
|
|
|
case 'clipEnabled':
|
|
return {data: ren.clipEnabled()};
|
|
|
|
case 'texture9Grid':
|
|
if (!msg.data) return {error: "Missing data"};
|
|
var tex_id = msg.data.texture_id;
|
|
if (!tex_id || !resources.texture[tex_id]) return {error: "Invalid texture id"};
|
|
ren.texture9Grid(
|
|
resources.texture[tex_id],
|
|
msg.data.src,
|
|
msg.data.leftWidth,
|
|
msg.data.rightWidth,
|
|
msg.data.topHeight,
|
|
msg.data.bottomHeight,
|
|
msg.data.scale,
|
|
msg.data.dst
|
|
);
|
|
return {success: true};
|
|
|
|
case 'textureTiled':
|
|
if (!msg.data) return {error: "Missing data"};
|
|
var tex_id = msg.data.texture_id;
|
|
if (!tex_id || !resources.texture[tex_id]) return {error: "Invalid texture id"};
|
|
ren.textureTiled(
|
|
resources.texture[tex_id],
|
|
msg.data.src,
|
|
msg.data.scale || 1.0,
|
|
msg.data.dst
|
|
);
|
|
return {success: true};
|
|
|
|
case 'readPixels':
|
|
var surf = ren.readPixels(msg.data ? msg.data.rect : null);
|
|
if (!surf) return {error: "Failed to read pixels"};
|
|
var surf_id = allocate_id();
|
|
resources.surface[surf_id] = surf;
|
|
return {id: surf_id};
|
|
|
|
case 'loadTexture':
|
|
if (!msg.data) throw new Error("Missing data")
|
|
|
|
var tex;
|
|
// Direct surface data
|
|
var surf = new surface(msg.data)
|
|
|
|
if (!surf)
|
|
throw new Error("Must provide surface_id or surface data")
|
|
|
|
tex = ren.load_texture(surf);
|
|
|
|
if (!tex) throw new Error("Failed to load texture")
|
|
var tex_id = allocate_id();
|
|
resources.texture[tex_id] = tex;
|
|
return {
|
|
id: tex_id,
|
|
};
|
|
|
|
case 'flush':
|
|
ren.flush();
|
|
return {success: true};
|
|
|
|
case 'coordsFromWindow':
|
|
if (!msg.data || !msg.data.pos) return {error: "Missing pos"};
|
|
return {data: ren.coordsFromWindow(msg.data.pos)};
|
|
|
|
case 'coordsToWindow':
|
|
if (!msg.data || !msg.data.pos) return {error: "Missing pos"};
|
|
return {data: ren.coordsToWindow(msg.data.pos)};
|
|
|
|
case 'batch':
|
|
if (!msg.data || !Array.isArray(msg.data)) return {error: "Missing or invalid data array"};
|
|
|
|
var results = [];
|
|
for (var i = 0; i < msg.data.length; i++) {
|
|
var result = handle_renderer(msg.data[i]);
|
|
results.push(result);
|
|
}
|
|
|
|
return {results: results};
|
|
|
|
default:
|
|
return {error: "Unknown renderer operation: " + msg.op};
|
|
}
|
|
}
|
|
|
|
// Texture operations
|
|
function handle_texture(msg) {
|
|
// Special case: create needs a renderer
|
|
if (msg.op === 'create') {
|
|
if (!msg.data) return {error: "Missing texture data"};
|
|
var ren_id = msg.data.renderer_id;
|
|
if (!ren_id || !resources.renderer[ren_id]) return {error: "Invalid renderer id"};
|
|
|
|
var tex;
|
|
var renderer = resources.renderer[ren_id];
|
|
|
|
// Create from surface
|
|
if (msg.data.surface_id) {
|
|
var surf = resources.surface[msg.data.surface_id];
|
|
if (!surf) return {error: "Invalid surface id"};
|
|
tex = new video.texture(renderer, surf);
|
|
}
|
|
// Create from properties
|
|
else if (msg.data.width && msg.data.height) {
|
|
tex = new video.texture(renderer, {
|
|
width: msg.data.width,
|
|
height: msg.data.height,
|
|
format: msg.data.format || 'rgba8888',
|
|
pixels: msg.data.pixels,
|
|
pitch: msg.data.pitch
|
|
});
|
|
}
|
|
else {
|
|
log.console(json.encode(msg.data))
|
|
return {error: "Must provide either surface_id or width/height"};
|
|
}
|
|
|
|
var tex_id = allocate_id();
|
|
resources.texture[tex_id] = tex;
|
|
return {id: tex_id, data: {size: tex.size}};
|
|
}
|
|
|
|
// All other operations require a valid texture ID
|
|
if (!msg.id || !resources.texture[msg.id]) {
|
|
return {error: "Invalid texture id: " + msg.id};
|
|
}
|
|
|
|
var tex = resources.texture[msg.id];
|
|
|
|
switch (msg.op) {
|
|
case 'destroy':
|
|
delete resources.texture[msg.id];
|
|
// Texture is automatically destroyed when all references are gone
|
|
return {success: true};
|
|
|
|
case 'get':
|
|
var prop = msg.data ? msg.data.property : null;
|
|
if (!prop) return {error: "Missing property name"};
|
|
return {data: tex[prop]};
|
|
|
|
case 'set':
|
|
var prop = msg.data ? msg.data.property : null;
|
|
var value = msg.data ? msg.data.value : undefined;
|
|
if (!prop) return {error: "Missing property name"};
|
|
|
|
// Validate property is settable
|
|
var readonly = ['size', 'width', 'height'];
|
|
if (readonly.indexOf(prop) !== -1) {
|
|
return {error: "Property '" + prop + "' is read-only"};
|
|
}
|
|
|
|
tex[prop] = value;
|
|
return {success: true};
|
|
|
|
case 'update':
|
|
if (!msg.data) return {error: "Missing update data"};
|
|
tex.update(
|
|
msg.data.rect || null,
|
|
msg.data.pixels,
|
|
msg.data.pitch || 0
|
|
);
|
|
return {success: true};
|
|
|
|
case 'lock':
|
|
var result = tex.lock(msg.data ? msg.data.rect : null);
|
|
return {data: result};
|
|
|
|
case 'unlock':
|
|
tex.unlock();
|
|
return {success: true};
|
|
|
|
case 'query':
|
|
return {data: tex.query()};
|
|
|
|
default:
|
|
return {error: "Unknown texture operation: " + msg.op};
|
|
}
|
|
}
|
|
|
|
// Surface operations (mainly for cleanup)
|
|
function handle_surface(msg) {
|
|
switch (msg.op) {
|
|
case 'destroy':
|
|
if (!msg.id || !resources.surface[msg.id]) {
|
|
return {error: "Invalid surface id: " + msg.id};
|
|
}
|
|
delete resources.surface[msg.id];
|
|
return {success: true};
|
|
|
|
default:
|
|
return {error: "Unknown surface operation: " + msg.op};
|
|
}
|
|
}
|
|
|
|
// Cursor operations
|
|
function handle_cursor(msg) {
|
|
switch (msg.op) {
|
|
case 'create':
|
|
var surf = new surface(msg.data)
|
|
|
|
var hotspot = msg.data.hotspot || [0, 0];
|
|
var cursor = video.createCursor(surf, hotspot);
|
|
|
|
var cursor_id = allocate_id();
|
|
resources.cursor[cursor_id] = cursor;
|
|
return {id: cursor_id};
|
|
|
|
case 'set':
|
|
var cursor = null;
|
|
if (msg.id && resources.cursor[msg.id]) {
|
|
cursor = resources.cursor[msg.id];
|
|
}
|
|
video.setCursor(cursor);
|
|
return {success: true};
|
|
|
|
case 'destroy':
|
|
if (!msg.id || !resources.cursor[msg.id]) {
|
|
return {error: "Invalid cursor id: " + msg.id};
|
|
}
|
|
delete resources.cursor[msg.id];
|
|
return {success: true};
|
|
|
|
default:
|
|
return {error: "Unknown cursor operation: " + msg.op};
|
|
}
|
|
}
|
|
|
|
// Utility function to create window and renderer
|
|
prosperon.endowments = prosperon.endowments || {};
|
|
|
|
// Mouse operations
|
|
function handle_mouse(msg) {
|
|
var mouse = video.mouse;
|
|
|
|
switch (msg.op) {
|
|
case 'show':
|
|
if (msg.data === undefined) return {error: "Missing show parameter"};
|
|
mouse.show(msg.data);
|
|
return {success: true};
|
|
|
|
case 'capture':
|
|
if (msg.data === undefined) return {error: "Missing capture parameter"};
|
|
mouse.capture(msg.data);
|
|
return {success: true};
|
|
|
|
case 'get_state':
|
|
return {data: mouse.get_state()};
|
|
|
|
case 'get_global_state':
|
|
return {data: mouse.get_global_state()};
|
|
|
|
case 'get_relative_state':
|
|
return {data: mouse.get_relative_state()};
|
|
|
|
case 'warp_global':
|
|
if (!msg.data) return {error: "Missing position"};
|
|
mouse.warp_global(msg.data);
|
|
return {success: true};
|
|
|
|
case 'warp_in_window':
|
|
if (!msg.data || !msg.data.window_id || !msg.data.pos)
|
|
return {error: "Missing window_id or position"};
|
|
var window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
mouse.warp_in_window(window, msg.data.pos);
|
|
return {success: true};
|
|
|
|
case 'cursor_visible':
|
|
return {data: mouse.cursor_visible()};
|
|
|
|
case 'get_cursor':
|
|
var cursor = mouse.get_cursor();
|
|
if (!cursor) return {data: null};
|
|
// Find or create cursor ID
|
|
for (var id in resources.cursor) {
|
|
if (resources.cursor[id] === cursor) {
|
|
return {data: id};
|
|
}
|
|
}
|
|
// Not tracked, add it
|
|
var cursor_id = allocate_id();
|
|
resources.cursor[cursor_id] = cursor;
|
|
return {data: cursor_id};
|
|
|
|
case 'get_default_cursor':
|
|
var cursor = mouse.get_default_cursor();
|
|
if (!cursor) return {data: null};
|
|
// Find or create cursor ID
|
|
for (var id in resources.cursor) {
|
|
if (resources.cursor[id] === cursor) {
|
|
return {data: id};
|
|
}
|
|
}
|
|
// Not tracked, add it
|
|
var cursor_id = allocate_id();
|
|
resources.cursor[cursor_id] = cursor;
|
|
return {data: cursor_id};
|
|
|
|
case 'create_system_cursor':
|
|
if (msg.data === undefined) return {error: "Missing cursor type"};
|
|
var cursor = mouse.create_system_cursor(msg.data);
|
|
var cursor_id = allocate_id();
|
|
resources.cursor[cursor_id] = cursor;
|
|
return {id: cursor_id};
|
|
|
|
case 'get_focus':
|
|
var window = mouse.get_focus();
|
|
if (!window) return {data: null};
|
|
// Find window ID
|
|
for (var id in resources.window) {
|
|
if (resources.window[id] === window) {
|
|
return {data: id};
|
|
}
|
|
}
|
|
// Not tracked, add it
|
|
var win_id = allocate_id();
|
|
resources.window[win_id] = window;
|
|
return {data: win_id};
|
|
|
|
default:
|
|
return {error: "Unknown mouse operation: " + msg.op};
|
|
}
|
|
}
|
|
|
|
// Keyboard operations
|
|
function handle_keyboard(msg) {
|
|
var keyboard = video.keyboard;
|
|
|
|
switch (msg.op) {
|
|
case 'get_state':
|
|
return {data: keyboard.get_state()};
|
|
|
|
case 'get_focus':
|
|
var window = keyboard.get_focus();
|
|
if (!window) return {data: null};
|
|
// Find window ID
|
|
for (var id in resources.window) {
|
|
if (resources.window[id] === window) {
|
|
return {data: id};
|
|
}
|
|
}
|
|
// Not tracked, add it
|
|
var win_id = allocate_id();
|
|
resources.window[win_id] = window;
|
|
return {data: win_id};
|
|
|
|
case 'start_text_input':
|
|
var window = null;
|
|
if (msg.data && msg.data.window_id) {
|
|
window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
}
|
|
keyboard.start_text_input(window);
|
|
return {success: true};
|
|
|
|
case 'stop_text_input':
|
|
var window = null;
|
|
if (msg.data && msg.data.window_id) {
|
|
window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
}
|
|
keyboard.stop_text_input(window);
|
|
return {success: true};
|
|
|
|
case 'text_input_active':
|
|
var window = null;
|
|
if (msg.data && msg.data.window_id) {
|
|
window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
}
|
|
return {data: keyboard.text_input_active(window)};
|
|
|
|
case 'get_text_input_area':
|
|
var window = null;
|
|
if (msg.data && msg.data.window_id) {
|
|
window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
}
|
|
return {data: keyboard.get_text_input_area(window)};
|
|
|
|
case 'set_text_input_area':
|
|
if (!msg.data || !msg.data.rect) return {error: "Missing rect"};
|
|
var window = null;
|
|
if (msg.data.window_id) {
|
|
window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
}
|
|
keyboard.set_text_input_area(msg.data.rect, msg.data.cursor || 0, window);
|
|
return {success: true};
|
|
|
|
case 'clear_composition':
|
|
var window = null;
|
|
if (msg.data && msg.data.window_id) {
|
|
window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
}
|
|
keyboard.clear_composition(window);
|
|
return {success: true};
|
|
|
|
case 'screen_keyboard_shown':
|
|
if (!msg.data || !msg.data.window_id) return {error: "Missing window_id"};
|
|
var window = resources.window[msg.data.window_id];
|
|
if (!window) return {error: "Invalid window id"};
|
|
return {data: keyboard.screen_keyboard_shown(window)};
|
|
|
|
case 'reset':
|
|
keyboard.reset();
|
|
return {success: true};
|
|
|
|
default:
|
|
return {error: "Unknown keyboard operation: " + msg.op};
|
|
}
|
|
}
|
|
|