input reports mod keys now

This commit is contained in:
2025-07-07 15:26:45 -05:00
parent 71c0056df4
commit 6e66bf59f6
2 changed files with 1 additions and 398 deletions

View File

@@ -1,397 +0,0 @@
var ex = this
var input = use('input')
var DEAD = Symbol()
var GARBAGE = Symbol()
var FILE = Symbol()
var TIMERS = Symbol()
var REGGIES = Symbol()
var UNDERLINGS = Symbol()
var OVERLING = Symbol()
function add_timer(obj, fn, seconds) {
var timers = obj[TIMERS]
var stop = function () {
if (!timer) return
timers.delete(stop)
timer.fn = null
timer = null
}
function execute() {
if (fn) timer.remain = fn(stop.seconds)
if (!timer) return
if (!timer.remain) stop()
else stop.seconds = timer.remain
}
// var timer = os.make_timer(execute)
timer.remain = seconds
stop.remain = seconds
stop.seconds = seconds
timers.push(stop)
return stop
}
globalThis.Register = {
registries: [],
add_cb(name) {
var n = {}
var fns = []
n.register = function (fn, oname) {
if (typeof fn != 'function') return
var dofn = function (...args) {
fn(...args)
}
Object.defineProperty(dofn, 'name', {value:`do_${oname}`})
var left = 0
var right = fns.length - 1
dofn.layer = fn.layer
dofn.layer ??= 0
while (left <= right) {
var mid = Math.floor((left + right) / 2)
if (fns[mid] == dofn.layer) {
left = mid
break
} else if (fns[mid].layer < dofn.layer) left = mid + 1
else right = mid - 1
}
fns.splice(left, 0, dofn)
return function () {
fns.delete(dofn)
}
}
prosperon[name] = function (...args) {
fns.forEach(fn => {
fn(...args)
})
}
Object.defineProperty(prosperon[name], 'name', {value:name})
prosperon[name].fns = fns
n.clear = function () {
fns = []
}
Register[name] = n
Register.registries[name] = n
return n
},
}
Register.pull_registers = function pull_registers(obj) {
var reggies = []
for (var reg in Register.registries) {
if (typeof obj[reg] == "function")
reggies.push(reg)
}
return reggies
}
Register.register_obj = function register_obj(obj, reg) {
var fn = obj[reg].bind(obj)
fn.layer = obj[reg].layer
var name = obj.ur ? obj.ur.name : obj.toString()
obj[TIMERS].push(Register.registries[reg].register(fn, name))
if (!obj[reg].name) Object.defineProperty(obj[reg], 'name', {value:`${obj._file}_${reg}`})
}
Register.check_registers = function check_registers(obj) {
if (obj[REGGIES]) {
if (obj[REGGIES].length == 0) return
for (var reg of obj[REGGIES])
Register.register_obj(obj,reg)
return
}
for (var reg in Register.registries) {
if (typeof obj[reg] == "function")
Register.register_obj(obj,reg)
}
}
Register.add_cb("appupdate")
Register.add_cb("update").doc = "Called once per frame."
Register.add_cb("physupdate")
Register.add_cb("gui")
Register.add_cb("hud")
Register.add_cb("draw")
Register.add_cb("imgui")
Register.add_cb("app")
var actor = {}
actor.toString = function() { return this[FILE] }
actor.spawn = function spawn(script, config, actor_context) {
if (this[DEAD]) throw new Error("Attempting to spawn on a dead actor")
var prog
if (!script) {
prog = {}
prog.module_ret = {}
prog.prog_fn = function() {}
} else {
prog = script_fn(script)
if (!prog.prog_fn) throw new Error(`Script ${script} is not an actor script or has no actor component`)
}
var underling
prog.module_ret.__proto__ = actor
underling = Object.create(prog.module_ret)
underling[OVERLING] = this
underling[FILE] = script
underling[TIMERS] = []
underling[UNDERLINGS] = new Set()
// Make $_ available to the actor (either passed context or the engine's $_)
var actor_dollar = actor_context || $_
Object.defineProperty(underling, '$_', {
value: actor_dollar,
writable:false,
enumerable:false,
configurable:false
})
Object.defineProperty(underling, 'overling', {
get() { return this[OVERLING] },
enumerable:true,
configurable:false
})
Object.defineProperty(underling, 'underlings', {
get() { return new Set(this[UNDERLINGS]) },
enumerable:true,
configurable:false
})
Object.defineProperty(underling, 'spawn', {
value: function(script, config) {
return actor.spawn.call(this, script, config, actor_dollar)
},
writable:false,
enumerable:true,
configurable:false
})
Object.defineProperty(underling, 'kill', {
value: actor.kill,
writable:false,
enumerable:true,
configurable:false
})
Object.defineProperty(underling, 'delay', {
value: actor.delay,
writable:false,
enumerable:true,
configurable:false
})
try {
// Pass $_ as a parameter to actor scripts
prog.prog_fn.call(underling, actor_dollar)
} catch(e) { throw e; }
if (underling[DEAD]) return null;
if (typeof config == 'object') Object.assign(underling, config)
if (!underling[REGGIES])
underling.__proto__[REGGIES] = Register.pull_registers(underling)
Register.check_registers(underling)
if (underling.awake) underling.awake()
this[UNDERLINGS].add(underling)
if (underling.tag) act.tag_add(underling.tag, underling)
underling[GARBAGE] = underling.garbage
return underling
}
actor.clear = function actor_clear() {
this[UNDERLINGS].forEach(p => {
p.kill()
})
this[UNDERLINGS].clear()
}
actor.kill = function kill() {
if (this[DEAD]) return
this[DEAD] = true
this[TIMERS].slice().forEach(t => t())
delete this[TIMERS]
input.do_uncontrol(this)
this.clear()
this[OVERLING][UNDERLINGS].delete(this)
delete this[UNDERLINGS]
if (typeof this.garbage == "function") this.garbage()
if (typeof this.then == "function") this.then()
act.tag_clear_guid(this)
}
actor.kill.doc = `Remove this actor and all its underlings from existence.`
actor.delay = function(fn, seconds) {
if (this[DEAD]) return
add_timer(this, fn, seconds)
}
actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`
actor[UNDERLINGS] = new Set()
ex[cell.DOC] = `
A set of utilities for iterating over a hierarchy of actor-like objects, as well
as managing tag-based lookups. Objects are assumed to have a "objects" property,
pointing to children or sub-objects, forming a tree.
`
function eachobj(obj, fn) {
var val = fn(obj)
if (val) return val
for (var o in obj.objects) {
if (obj.objects[o] == obj) log.error(`Object ${obj.toString()} is referenced by itself.`)
val = eachobj(obj.objects[o], fn)
if (val) return val
}
}
ex.all_objects = function (fn, startobj = world) {
return eachobj(startobj, fn)
}
ex.all_objects[cell.DOC] = `
:param fn: A callback function that receives each object. If it returns a truthy value, iteration stops and that value is returned.
:param startobj: The root object at which iteration begins, default is the global "world".
:return: The first truthy value returned by fn, or null if none.
Iterate over each object (and its sub-objects) in the hierarchy, calling fn for each one.
`
ex.find_object = function (fn, startobj = world) {}
ex.find_object[cell.DOC] = `
:param fn: A callback or criteria to locate a particular object.
:param startobj: The root object at which search begins, default "world".
:return: Not yet implemented.
Intended to find a matching object within the hierarchy.
`
var gtags = {}
ex.tag_add = function (tag, obj) {
gtags[tag] ??= new Set()
gtags[tag].add(obj)
}
ex.tag_add[cell.DOC] = `
:param tag: A string tag to associate with the object.
:param obj: The object to add under this tag.
:return: None
Associate the given object with the specified tag. Creates a new tag set if it does not exist.
`
ex.tag_rm = function (tag, obj) {
delete gtags[tag].delete(obj)
}
ex.tag_rm[cell.DOC] = `
:param tag: The tag to remove the object from.
:param obj: The object to remove from the tag set.
:return: None
Remove the given object from the specified tags set, if it exists.
`
ex.tag_clear_guid = function (obj) {
for (var tag in gtags) gtags[tag].delete(obj)
}
ex.tag_clear_guid[cell.DOC] = `
:param obj: The object whose tags should be cleared.
:return: None
Remove the object from all tag sets.
`
ex.objects_with_tag = function (tag) {
if (!gtags[tag]) return []
return Array.from(gtags[tag])
}
ex.objects_with_tag[cell.DOC] = `
:param tag: A string tag to look up.
:return: An array of objects associated with the given tag.
Retrieve all objects currently tagged with the specified tag.
`
function parse_file(content, file) {
if (!content) return {}
if (content.match()
if (!/^\s*---\s*$/m.test(content)) {
var part = content.trim()
if (part.match(/return\s+[^;]+;?\s*$/)) {
return { module: part }
}
return { program: part }
}
var parts = content.split(/\n\s*---\s*\n/)
var module = parts[0]
if (!/\breturn\b/.test(module))
throw new Error(`Malformed file: ${file}. Module section must end with a return statement.`)
try {
new Function(module)()
} catch (e) {
throw new Error(`Malformed file: ${file}. Module section must end with a return statement.\n` + e.message)
}
var pad = '\n'.repeat(module.split('\n').length + 4)
return {
module,
program: pad + parts[1]
}
}
// path is the path of a module or script to resolve
var script_fn = function script_fn(path, args) {
var parsed = {}
var file = resources.find_script(path)
if (!file) {
parsed.module_ret = bare_load(path)
if (!parsed.module_ret) throw new Error(`Module ${path} could not be created`)
return parsed
}
var content = io.slurp(file)
var parsed = parse_file(content, file)
var module_name = file.name()
parsed.module_ret = bare_load(path)
parsed.module_ret ??= {}
if (parsed.module) {
// Create a context object with args
var context = Object.create(parsed.module_ret)
context.__args__ = args || []
var mod_script = `(function setup_${module_name}_module(){ var self = this; var $ = this; var exports = {}; var module = {exports: exports}; var define = null; var arg = this.__args__; ${parsed.module}})`
var module_fn = js.eval(file, mod_script)
parsed.module_ret = module_fn.call(context)
if (parsed.module_ret == null || parsed.module_ret == null)
throw new Error(`Module ${module_name} must return a value`)
parsed.module_fn = module_fn
}
parsed.program ??= ""
var prog_script = `(function use_${module_name}($_) { var self = this; var $ = this.__proto__; ${parsed.program}})`
parsed.prog_fn = js.eval(file, prog_script)
return parsed
}.hashify()
return ex

View File

@@ -505,7 +505,7 @@ static void event2wota_write(WotaBuffer *wb, const SDL_Event *e, int c) {
wota_write_text(wb, "scancode");
wota_write_number(wb, (double)e->key.scancode);
wota_write_text(wb, "mod");
wota_write_number(wb, 0);
wota_write_number(wb, (double)e->key.mod);
break;
case SDL_EVENT_FINGER_MOTION:
case SDL_EVENT_FINGER_DOWN: