OSC: Change ::OscSend format and restore String support to Button Actions. (#388)
* OscSend: support strings poc
- change value delimiter to `;`
- default convert values to String when not converted to another type
* add `_arg<n>="<value>"` format instead of `;` delimiter
that is, vrchat chatbox is controlled like `_press="::OscSend /chatbox/input" _arg0="${send}" _arg1="true" _arg2="true"` now
old format still supported as shorthand, with same "strings can't have spaces" limit as before. `_arg<n>` are appended after these.
* fix accidentally resetting `osc_args` to empty between formats
* update readme to document `::OscSend` paramter-form
* clean up, use `while let` instead of `while match`
* merge `parse_osc_value` into while condition
* remove second log from shortform arg parsing
This commit is contained in:
@@ -80,22 +80,40 @@ This button action executes a shell script using the `sh` shell.
|
|||||||
<button _press="::ShellExec $HOME/myscript.sh test-argument" [...] />
|
<button _press="::ShellExec $HOME/myscript.sh test-argument" [...] />
|
||||||
```
|
```
|
||||||
|
|
||||||
##### `::OscSend <path> <args ..>`
|
##### `::OscSend <path>` `::OscSend <path> <args ..>`
|
||||||
|
|
||||||
Send an OSC message. The target port comes from the `osc_out_port` configuration setting.
|
Send an OSC message. The target port comes from the `osc_out_port` configuration setting.
|
||||||
|
|
||||||
|
There are two formats; here is an example for both formats writing a message to the VRChat Chatbox:
|
||||||
```xml
|
```xml
|
||||||
<button _press="::OscSend /avatar/parameters/MyInt 1i32" [...] />
|
<!-- parameter form - OSC arguments are listed as parameters labelled `_arg<n>` where `n` is 0-indexed -->
|
||||||
|
<Button _press="::OscSend /chatbox/input" _arg0="Hello World! I am WayVR." _arg1="true" _arg2="true"> </Button>
|
||||||
|
<!-- will send: ("Hello World! I am WayVR.", True, True) to /chatbox/input -->
|
||||||
|
```
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- shorthand form - OSC arguments are space-separated in one string. note that single strings cannot contain spaces -->
|
||||||
|
<Button _press="::OscSend /chatbox/input Hello_World!_I_am_WayVR. true true"> </Button>
|
||||||
|
<!-- will send: ("Hello_World!_I_am_WayVR.", True, True) to /chatbox/input -->
|
||||||
|
```
|
||||||
|
|
||||||
|
The two can be combined; parameter-form arguments will be appended after shorthand-form arguments:
|
||||||
|
```xml
|
||||||
|
<!-- combined-form - rectangle bounds with a name -->
|
||||||
|
<Button _press="::OscSend /graphthing/rectangle 0i32 0i32 50i32 200i32" _arg0="tall rectangle"> </Button>
|
||||||
|
<!-- will send: (0, 0, 50, 200, "tall rectangle") to /graphthing/rectangle -->
|
||||||
```
|
```
|
||||||
|
|
||||||
Available argument value types (case insensitive):
|
Available argument value types (case insensitive):
|
||||||
- Bool: `true` or `false`
|
- Bool: `true` or `false`
|
||||||
- Nil: `nil`
|
- Nil: `nil`
|
||||||
- Inf: `inf`
|
- Inf: `inf`
|
||||||
- Int: `-1i32`, `1i32`, etc
|
- Int: suffix `i32` (`-1i32`, `1i32`, etc)
|
||||||
- Long: `-1i64`, `1i64`, etc
|
- Long: suffix `i64` (`-1i64`, `1i64`, etc)
|
||||||
- Float: `1f32`, `1.0f32`, etc
|
- Float: suffix `f32` (`1f32`, `1.0f32`, etc)
|
||||||
- Double: `1f64`, `1.0f64`, etc
|
- Double: suffix `f64` (`1f64`, `1.0f64`, etc)
|
||||||
|
- String: any other value
|
||||||
|
- Shorthand form will treat Strings with spaces as multiple arguments. Use parameter form if you need spaces.
|
||||||
|
|
||||||
##### `::SendKey <VirtualKey> <UP|DOWN>`
|
##### `::SendKey <VirtualKey> <UP|DOWN>`
|
||||||
|
|
||||||
|
|||||||
@@ -692,15 +692,28 @@ pub(super) fn setup_custom_button<S: 'static>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut osc_args = vec![];
|
let mut osc_args = vec![];
|
||||||
|
|
||||||
|
// collect arguments specified in the initial string
|
||||||
for arg in args {
|
for arg in args {
|
||||||
let Ok(osc_arg) = parse_osc_value(arg)
|
if let Ok(osc_arg) = parse_osc_value(arg).inspect_err(|e| {
|
||||||
.inspect_err(|e| log::warn!("Could not parse OSC value '{arg}': {e:?}"))
|
let msg = format!("Could not parse OSC value \"{arg}\": {e:?}");
|
||||||
else {
|
|
||||||
let msg = format!("expected OscValue, found \"{arg}\"");
|
|
||||||
log_cmd_invalid_arg(parser_state, TAG, name, command, &msg);
|
log_cmd_invalid_arg(parser_state, TAG, name, command, &msg);
|
||||||
return;
|
return;
|
||||||
};
|
}) {
|
||||||
|
osc_args.push(osc_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect arguments from _arg<n> attributes.
|
||||||
|
let mut arg_index = 0;
|
||||||
|
while let Some(arg) = attribs.get_value(&format!("_arg{arg_index}"))
|
||||||
|
&& let Ok(osc_arg) = parse_osc_value(arg).inspect_err(|e| {
|
||||||
|
let msg = format!("Could not parse OSC value \"{arg}\": {e:?}");
|
||||||
|
log_cmd_invalid_arg(parser_state, TAG, name, command, &msg);
|
||||||
|
})
|
||||||
|
{
|
||||||
osc_args.push(osc_arg);
|
osc_args.push(osc_arg);
|
||||||
|
arg_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Box::new(move |_common, data, app, _| {
|
Box::new(move |_common, data, app, _| {
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ pub fn parse_osc_value(s: &str) -> anyhow::Result<OscType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anyhow::bail!("Unknown OSC type literal: {s}")
|
Ok(OscType::String(s.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user