#leafwing-input-manager
1 messages ยท Page 4 of 1
I've completed the UserInput part, but I'm now working on modifying the InputMap and input mocking API
I feel like these could be split out from #490 because they're not particularly related and involve too many aspects
Great, let's do that then
#513 ready
I'm a bit unclear about the current issue with Gamepad input mocking
According to this comment: https://github.com/Leafwing-Studios/leafwing-input-manager/pull/401#issuecomment-1776403469
Bevy #9446 broke the behavior where Axis<GamepadButton> was not modified by GamepadButtonChangedEvent
@river cliff maybe you remember more?
And then I've reviewed Bevy's gamepad_axis_event_system and gamepad_button_event_system
and there haven't been any logical changes to these systems since #9008 (included in Bevy 0.12)
the modifications made by GamepadButtonChangedEvent to ButtonInput<GamepadButton> seem to still be effective
Since GamepadButton is primarily treated as a button in LWIM, it seems feasible to modify the VirtualDPad implementation to check for presses from this perspective?
Yes I'm on board with this
looking into it to see if I can jog my memory
Oops, I see the problem lies elsewhere
the main issue just is that GameButtonType should get its value from Axis<GameButtonType>, but the external GamepadButtonChangedEvent cannot modify the value in this resource
It's not a problem with the implementation of VirtualDpad.
Directly modifying Axis<GamepadButton> in send_input mocking works for game_pad_virtual_dpad testing, but it might be too hacky
This resource is only used by gilrs_event_system in bevy_gilrs and gamepad_connection_system in bevy_input
with_gamepad() is used for this case
using set_gamepad would return a &mut Self
perhaps we could rename with_gamepad
@karmic monolith
Ah okay, I see now
Yeah that's fine, merging now
@candid vigil once you get a chance can you resolve the conflicts in https://github.com/Leafwing-Studios/leafwing-input-manager/pull/514 ?
Then we can merge that one
And then we can have a clearer view of 515, which seems trickier
๐
done
Awesome, thank you ๐ 514 is merged
And review left for 515
Really excellent progress!
A potential fix would be to modify the Axis<GamepadButton> simultaneously with sending the GamepadButtonChangedEvent
but this approach is quite hacky, and I'm unsure of any potential side effects.
Yeah, I think we should consider just not allowing gamepad buttons to be mocked for now
until it's fixed upstream
rebased
Merging now @candid vigil ๐
That should give you a nice clean base to tackle some of the more fundamental splitting tasks
fix a typo in RELEASES.md, disabled auto-merge
And re-enabled ๐
Off to bed for the night now
yeah good night!
I should be able to finish #490 in a few hours
trait refactoring
I just had this idea that we could add another trait, like MockRawInputEvent for UserInput
where the input itself decides how to send fake input events
Instead of dealing with it in MockInput for MutableInputStreams
MockInput would just call methods from UserInput within MockRawInputEvent
After that we can get rid of RawInputs since it also limit how we can extend new input types
I like that!
I'm unsure of appropriate names for the dual-axis versions of mouse motion and mouse wheel inputs
These names are currently used by Bevy for the corresponding input events
in the current implementation
DualAxis::mouse_motionandDualAxis::mouse_wheelare nowMouseMoveandMouseScroll.MouseMotionAxisTypeandMouseWheelAxisTypeare nowMouseMoveAxisandMouseScrollAxis.MouseMotionDirectionandMouseWheelDirectionare nowMouseMoveDirectionandMouseScrollDirection.
I think these are about as good as we're going to get
We can do another pass once they're upstreamed
unity decided to make delta into a property(trait) for pointer devices (pen, touchscreen, mouse), I think removing mouse from the name is really appropriate
#490 is done
but I'm not sure what format to use for writing doc examples for these input structs
Should I directly describe the various constructors and constants, or use InputMap, or use input mocking?
I think I would go with the former. We'll have tons of examples that cover InputMap
I think the latter can be used as an additional example
but the QueryInput could be improved
Currently, it can only check whether a button is pressed
we can add new methods to read the value of axes
I feel like using InputMap in the documentation for each UserInput is a bit redundant
each case requires an additional Action
using MockInput and QueryInput seems like a better way to describe the behavior of the input, and what data the input will respond to
Yeah, that seems more reasonable
Are there any good examples showing context-based actions? I'm implementing an editor where there's different edit states, and the same key will trigger a different action based on the state. Would it make sense to just have an Actionlike enum per edit state and enable/disable based on the state? Or maybe attach them to components that are added/removed based on the state?
This could be a use case for entity disabling if it gets into 0.14
That's not going to happen, but there's a PR open on LWIM for better control over enabling/disabling actions at least ... Idk what it's blocked on tho ๐ค
Just me reviewing it I believe
You mean entity disabling? I thought default query filters was fairly uncontroversial
It's still open on X-Controversial so I'm not too sure, but at the very least adding the proposed Disabled marker on top is pretty controversial: https://github.com/bevyengine/bevy/pull/12928. I also doubt LWIM would handle things correctly if it was disabled without warning ... If we get observers and trigger a disable/enable event it should be fairly easy to handle tho ๐ค
Hmmm, too bad. Seemed pretty straightforward. Anything need reviews?
My current plans for disabled entities (and components) #ecs-dev message
Definitely would be nice if LWIM could be toggled in a way that doesn't even require checking the docs tho. The current ToggleActions is also hard to discover, but iirc that PR for enabling/disabling individual actions would move it to the type itself which would be a lot easier to discover
Right, this is the pr I've been referring to. If I'm not mistaken, you could implement disabling as a third-party create and add Without<Disabled> as a default query filter. That would stop lwim action states being updated and essentially do what sycotropic was asking, just put all your context actions on different entities, then add Disabled as necessary
Doesn't that mean if we can get default filters in, we could basically get entity disabling for free?
Not entirely. LWIM could show some very strange behavior if disabled like this, because it will consider all actions to stay the same as before being disabled, which means actions could still be held. The current ToggleActions approach is also slightly broken in that regard (tho it does behave a bit better because iirc there's a system that releases the actions when disabled), I think that toggle per-action PR is also supposed to fix those issues
๐ค but even if an action is held, the user wouldn't be able to query for it since it'd be disabled. I guess once your reenabled it it'd probably break...
Yea it would trigger just released and that's probably not what you'd expect (there are some exceptions to that ofc)
And this is where observers would come in handy right? If Bevy had first-party disabling, lwim would want to add an observer that properly handle Disabled being inserted
Yep, LWIM would definitely need some special handling to respond to that
PR #490 (trait refactoring) is ready for review
But it contains the new processors added in the new PR #521
Hi, is there a path forward for https://github.com/bevyengine/bevy/issues/6183?
It's pretty important for me in lightyear because my networking is tick-based so my input-handling systems run in FixedUpdate.
Would making the Schedule where most systems run (tick_action_state, update_action_state) configurable work? So that those systems run in FixedPreUpdate instead of PreUpdate
But I guess in that case you would miss some inputs in systems that run in the Update schedule
I think the main issue here is that we need timestamps on inputs to meaningfully assign them to FixedUpdate ticks, and iirc the issue with that is that the event loop for winit is blocked while the app is updating ... I think someone recently adopted a PR that is necessary to even start fixing that problem, tho I have also seen work on an alternative approach where input timesteps are retrieved from the OS but that seemed like it was full of edgecases ๐ค
I mostly just need to be able to use just_pressed and just_released in FixedUpdate. I think if the tick_action_state system ran in FixedPreUpdate it would accomplish that.
Or are you saying that update_action_state wouldn't work in FixedUpdate because of some winit stuff?
I think currently the best we can do is:
- Create inputs during PreUpdate, combining them if one is already built (happens constantly when FPS >= tickrate)
- Finalize them inside the fixed loop
- If another fixed tick runs the same frame, assume the previous input is still valid
- If a fixed tick has run this Update, clear the inputs after FixedMain as ran
I"m not sure I understand..
- create-inputs = read them from the bevy
ButtonInputandMouseWheelevents? - finalize = go from 'just-pressed' to 'pressed'?
Creating it depends on where you handle it, if you handle it in your own code it would be like making your own input type, and finalizing would be any steps that are taken to turn it into a real input, like sending it to the server or firing some event or whatever
Hm; so what does it mean in terms of LWIM handling just_pressed and just_released in FixedUpdate?
If it's handled on the LWIM side, everything that becomes just_* would stay just_* until a FixedUpdate consumes the just_* ๐ค
So the change would be to make the tick_action_system run in FixedPreUpdate?
That could be one part of the changes maybe ... I'd imagine release_on_disable would also need to be in there (tho hat might become irrelevant with the PR replacing toggle actions with per-action toggles) ... And there would need to be some logic that decides where to run these things
Is it possible to easily detect double click on a single keyboard button yet?
I would like to create a controller where KeyS click would be coupled to a MoveBackward action and KeyS double-click would be coupled to a 180 degree character's rotation.
EDIT: I guess my answer is here: https://github.com/Leafwing-Studios/leafwing-input-manager/issues/485
I think I have something that works well while being minimally invasive (doesn't require many code changes): https://github.com/Leafwing-Studios/leafwing-input-manager/pull/522
The idea is to swap the state of the ActionData between a update_state updated in PreUpdate , and a fixed_update_state updated before we run the FixedMainRunLoop schedule. (credit to @karmic monolith for the idea!)
(exactly like how Time<()> swaps between Time<Virtual> and Time<Fixed> in the FixedMainRunLoop schedule).
I added some unit tests to show that it fixed the problems described in https://github.com/bevyengine/bevy/issues/6183
I think it's a huge improvement because right now using leafwing in FixedUpdate systems effectively has massive footguns and requires great care.
Context
Fixes #252
(see description of the issue in bevyengine/bevy#6183)
It would also fix cBournhonesque/lightyear#349
(I did a write-up here: https://hackmd.io/_TGuaUTnRBeuisvUMr0QoQ?both)
i.e. ...
Thank you โค๏ธ I'm not going to look at this until early next week (weekends!), but I do really appreciate the effort here
What are the odds the bevy_ui integration could be completely replaced by the mod_picking upstream?
Extremely high
Awesome, that was my impression after trying it
@karmic monolith I wonder if you had the time to look at my input PR? (no rush)
Not yet!
Hey, is this a good place for support around crates too?
I'm having an issue where my switch pro controller is picked up and used about half the time, I also can't seem to get buttons to work. (DualAxis is what works half the time). I've searched github but couldn't find anyone with the same behaviour as me. I'm grateful for any breadcrumbs of hope. I've not tested other controllers yet.
Hmm, that was my issue last night, just tried first thing this morning and it worked. So looks like a classic PEBKAC issue.
whats the status on the upstreaming effort/are there any PRs to review/refactors in need of completing
Any of the recent open PRs would benefit from a review
I want to land the trait refactor, let that bake for a bit and then start upstreaming
Thank you!
It's been harder to keep on top of it while I'm doing Bevy itself full time
I should just accept that I need to take work time on my crates sometimes
i think that is an entirely valid use of work time
especially given that it will imminently be upstreamed
Yep
I also want to look into the input sequence alternative and see if there are things to learn there
man this PR is gargantuan. https://github.com/Leafwing-Studios/leafwing-input-manager/pull/490
positively colossal
im happy to rebase https://github.com/Leafwing-Studios/leafwing-input-manager/pull/456 if / when necessary, can @ me
@swift summit i responded in the pr
im gonna approve, i just dont understand the reasoning
responded
the reasoning is to fix issue #446 specifically, and it happens to also fix #416 incidentally
i see thanks
This PR actually touched on a lot of aspects, significantly impacting the core input abstraction. However, there might be better approaches to address what it's trying to do
how would you suggest going about reviewing such a beast
Most of the new input impls involve breaking down the logic of the original, large InputStreams
The secondary focus might be on naming these implementations, which I'm not particularly good at
I'm also unsure whether we should keep the original cross-device VirtualAxis and VirtualDPad. This PR only includes separate versions for keyboards and gamepads
My primary concern is that these two input types are essentially simulating directions
and a cross-device layout might feel strange
and using Chord (multiple buttons pressed simultaneously) as one direction for these inputs might also make it less convenient for players
Thanks!
Does someone understand why all the tests suddenly fail on https://github.com/Leafwing-Studios/leafwing-input-manager/pull/522 ? they were working before
Context
Fixes #252
(see description of the issue in bevyengine/bevy#6183)
It would also fix cBournhonesque/lightyear#349
(I did a write-up here: https://hackmd.io/_TGuaUTnRBeuisvUMr0QoQ?both)
i.e. ...
release_on_disable and run_if_enabled are removed in #456
thanks
Can I get a second review on https://github.com/bevyengine/bevy/pull/13653 from one of y'all?
Objective
Implements #13647
Solution
Created two enums, CompassQuadrant and CompassOctant inside compass.rs with impls To and From Dir2. Used dir.to_angle().to_degrees() and matched against the res...
That's the last missing piece for removing LWIM's own competing direction machinery in the 0.14 patch
Done
Working on the LWIM upgrade today
Starting with the trivial bump
Then leafwing_abilities
Then updating main
I've prepared https://github.com/Leafwing-Studios/leafwing-input-manager/tree/v0.14-rc now. Once https://github.com/mvlabat/bevy_egui/pull/284 is merged, I'll cut a release candidate version
Then once Bevy 0.14 is released, we'll cut another little bump from this branch as LWIM 0.14
And then ship main as LWIM 0.15
@topaz stratus has mostly done this for me already! https://github.com/Leafwing-Studios/leafwing-input-manager/pull/531
I'm going to work off that, then push and merge my own fixes to it ๐
Merged ๐
@candid vigil, I've left feedback on the traitification: https://github.com/Leafwing-Studios/leafwing-input-manager/pull/490#pullrequestreview-2106381405
I don't think it's the optimal design yet, but I'm inclined to merge it in approximately its current state and then iterate, but if you have strong feelings otherwise I'll defer to you
@karmic monolith Yeah, Iโve left some comments as well. Could I hear your thoughts if you have time?
Most of changes in my comments seemed too much for a single PR before, but now there are already many changes in this PR. I'm not sure how to split it up step by step
I've taken a look, and your responses are very reasonable
I'd really like to have an input mocking trait
But that can definitely be another PR
IMO we should merge now
And then I can spend the next week refining further
Maybe we could change the implementation of BasicInputs first, or handle it in a later PR
returning a Vec and just check the lengths and basic inputs of each should be enough?
Follow-up ๐
sure
Hi, any opinions on this? https://github.com/Leafwing-Studios/leafwing-input-manager/pull/522
It would make the crate more usable for networking if inputs could be handled in FixedUpdate
Context
Fixes #252
(see description of the issue in bevyengine/bevy#6183)
It would also fix cBournhonesque/lightyear#349
(I did a write-up here: https://hackmd.io/_TGuaUTnRBeuisvUMr0QoQ?both)
i.e. ...
I'm nervous but I really do want to solve this problem
Reviewing in earnest now
Yes it's a fairly big change, but it stays in the spirit of the Time resource (swapping between Time<Fixed>, Time<Virtual> and Time<()>).
It might have some perf or ergonomics implication though?
Yeah, but I'm currently at "correctness and API" in my mindset for this crate
I'm sold. Add release notes and I'll merge it
awesome! will do
Once that's in I'm going to resolve conflicts and merge in @candid vigil's monster
Then take a crack at splitting the UserInput traits
How extensively did you test this? Do inputs get generated consistently even if FixedUpdate runs at 60tick/s and FPS is way off like at 30 or 200? ๐ค
I haven't done extensive testing; i've only tested the cases where fixed update runs multiple times in a frame, and fixed update runs 0 times in a frame. I'll fully test it in lightyear soon; previously I had to do weird workarounds for handling inputs in FixedUupdate
I'm using some ugly workarounds too, generating inputs outside of FixedUpdate, but somewhere something goes wrong causing half of inputs to get dropped anyway when FPS is not exactly 60
Ideally we would've had input timestamps by now, but it's been blocked by some winit specifics for a long time and every attempt to unblock it ends up in review limbo until it's so hard to rebase it needs to be redone ๐ค
Merging https://github.com/Leafwing-Studios/leafwing-input-manager/pull/534, which is a lightly cleaned up version of the monster above
https://github.com/Leafwing-Studios/leafwing-input-manager/issues/538 needs a fix before LWIM's next release. It should be straightforward enough (and you can gawk at my terrible code!) if you, the reader, would like to help out ๐
Version Just after a513ad0 What you did Many tests are failing. See https://github.com/Leafwing-Studios/leafwing-input-manager/actions/runs/9452237797/job/26034969670?pr=534 This isn't particul...
I don't really get it. What changed that caused these failures? Did something change with the Bevy input?
Yeah I'm not fully sure yet. Maybe the event bug linked?
I found the issue. It seems that EventReader has undergone some breaking changes
for example, with this code
in Bevy 0.13, the arrow position would only read a single MouseMotion { delta: [0.0, 5.0] }
but in Bevy 0.14, it reads both the old MouseMotion { delta: [0.0, -5.0] } and the new MouseMotion { delta: [0.0, 5.0] }
this causes the error, as the accumulated result ends up being 0.0 and doesn't being pressed ๐
Is there a migration guide ready?
I felt the fourth wall break reading this message ๐
I think that this is likely a result of https://github.com/bevyengine/bevy/issues/13758. I don't remember any other meaningful change to how events work ๐ค I'll do another look
https://github.com/bevyengine/bevy/commits/release-0.14.0/crates/bevy_ecs/src/event.rs Yeah, nothing else plausible in the history
Taking a crack at this bug myself now
What do you think about filling the ActionState hashmap with the default value for ActionData for all possible actions on spawn?
Currently they are initializd on the first press or release, which is a bit confusing
I had considered this point in my previous PR
but it seems impossible now that Actionlike can use tuples and even struct variants
On the other hand, although OnAdd and OnChange can be used to detect changes in InputMap and update the corresponding ActionState, I am not completely sure whether this will have the expected effect
You can't: the set of actions is not knowable
Since Actionlike is no longer restricted to simple enums
Oh i see
https://github.com/Leafwing-Studios/leafwing-input-manager/pull/543 It's finally fixed!
I took the time to do it right, and now all the tests (except the gamepad input mocking one) are green
Alright, I've started on the next phase of the trait refactor, splitting apart UserInput into more semantically meaningful traits
https://github.com/Leafwing-Studios/leafwing-input-manager/pull/548 is a bit of a beast, but you can get a good sense of the direction at this stage
I spent all day on this today, and I'll be back on it Tuesday or Wednesday of next week (long weekend)
Generally pleased though: I think this is the right direction!
For networking, I have a usecase where users want to transmit stuff like Cursor position in world-space + maybe camera rotation.
I think the cursor position part is possible by first converting the cursor coordinates from window-space to world-space and then setting them as a DualAxis input.
But for camera rotation I would need a TripleAxis Input.
Will the refactor allow me to send arbitrary data inside ActionLike? Such as a vec3?
cc @woeful totem
Also will it be possible to send 2 inputs at the same time (i.e. WorldPosition AND CameraRotation)? Basically a struct vs an enum
Hmm. So, ActionDiff itself is effectively unchanged
I would probably use a custom message for more exotic things
Although if there's demand for other forms of input beyond just bool/f32/Vec2 this makes it really easy to add more subtraits
I guess it's just a matter of adding a TripleAxis input; I see that unity has Vec3 inputs: https://docs.unity3d.com/Packages/[email protected]/manual/Processors.html
Yeah, I'm super down for that in the future ๐
Let's land the refactor first though, then build on it
Agreed on "land it then build on it", and once it is landed, consider this comment as extra support for wanting triple-axis input kind ๐
What are y'all looking to bind for this?
VR? A space mouse?
For me it's the 3D world-space orientation of a character (I can't just use the 2d mouse input values, since they have to be converted to world space when sent to the server)
I've wanted to use it for vr controls yes, but one of the more mundane things I've wanted was just to have a character that moves in 3d space, then create a virtual triaxis for it
The alternative is to split up my motion into enum Motion { Regular, Vertical } or else enum Motion { Vertical, Lateral, Longitudinal }
Both work, it's just that things get ever so slightly cleaner and nicer to work with when the input abstraction just hands me a 3d direction
How can you detect a down press + button on a controller?
Like for a dropdown movement, you would press on the left stick down + the South button.
I tried with:
input_map.insert_chord(Action::DropDown, [SingleAxis::negative_only(GamepadAxisType::LeftStickY, 0.3), GamepadButtonType::South]);
But the single axis is not a button.
In the upcoming release, we'll introduce GamepadAxisDirection. However, it's worth noting that currently, they lack a deadzone threshold
And in the previous release? (upcoming one for 14.0 looks very promising!)
there probably won't be a way in LWIM 0.13
Yeah, you may be able to synthesize it somehow, but I'm really not sure of the best way in 0.13
Does ActionState.pressed(Action::DropDown) not return true?
In theory, this Chord should achieve that effect
Or are you referring to an error during the Chord construction?
The insert_chord function takes an iterator as a parameter, and Rust requires all items in an iterable to be of the same type
However, in the current version, there's a huge InputKind enum that encompasses all input kinds supported by LWIM
Thank you!, wrapping it from the InputKind makes it compile:
input_map.insert_chord(PlayerAction::DropDown, [
InputKind::from(SingleAxis::negative_only(GamepadAxisType::LeftStickY, 0.3)),
InputKind::from(GamepadButtonType::South)]
);
Hitting this again in a new system and it continues to be surprising / confusing.
https://github.com/Leafwing-Studios/leafwing-input-manager/pull/548
The second half of the UserInput refactor is now done*; take a look and let me know how you feel about the API?
*: except actually testing that it works
Sorry for the monstrous PR: this really did end up touching the whole stack ๐
Generally feeling very good about the split and traitification as a whole: this is a much less leaky abstraction. No more wondering about "what does it mean for a control stick to be pressed" or other nonsense
So pressed/released only make sense for ButtonLike now?
Exactly
I redid how action-diffs are generated @umbral linden; you might be interested in those changes
Thanks, i'll take a look.
In general I don't use the action-diffs system directly anymore, because it's too risky to only send diffs. (if they arrive too late or don't arrive then it's hard to recover)
Instead I have a buffer of past ActionStates, and I send a base ActionState + diffs since that action state. I will probably have to update my logic to match what you did
One thing I don't really get is that an action could have independently all 3 (button/axis/2d-axis)? Do you have an example for where this is useful/relevant?
I think maybe we can add a with_button method to AxislikeChord and DualAxislikeChord
Otherwise, creating a chord that binds to more than one button requires creating a ButtonlikeChord first
I just added this crate (0.13.3) to my Bevy app, but bevy_mod_picking seems to have completely stopped working. Is this expected? Is there a way to make both work side-by-side?
In v0.13.3 as well as current main, is it expected that the mouse_position example isn't working?
(main does nothing, v0.13.3 panics at examples/mouse_position.rs:64:22:)
๐ฅบ
ngl i haven't actually tried to integrate LWIM with bevy_oxr yet, i didn't realize it was lacking a Vec3
whenever I do get around to it i'll make a fork of the repo with the changes I need and then see which ones you want to adopt ( if i ever do end up getting to it
)
( my brain is so adhd i can't help myself, i code as a coping mechanism to deal with the stress of school so it's not entirely within my control )
i think the end goal is to have them though
whatever input you use, it should just work out of the box ๐คทโโ๏ธ
(heavy) workout usually works better

and with VR it could be way more fun
Anyone want to update the 0.14 branch? I think you need to clean up features mostly ๐
I'm pretty low on time this weekend (dad's in town), but I'd like to get the LWIM update out at least
Oh, I already did that. I guess I forgot to submit a PR. Let me see.
I didn't submit it because bevy_egui hasn't updated.
Yeah, a PR would be useful at least
Is it that you want to release the 0.14 branch and then release main as 0.15?
Yep, that's the plan
There's a bit more to do on main before I want to ship it
is there a migration guide ? ๐ฅบ
i think i just need to figure out how to keep my ActionLike enums
cause the compiler doesn't like them now, saying they can't possibly implement FromReflect or smth
oh i had 2 bevy version in the tree
Good that's what I expected ๐
In case it helps I use cargo tree -d 2>&1 | less all the time when upgrading to figure out which crate is still pulling the old bevy ๐
Yay
This is just the compatability bump
is it normal to have
name = "leafwing_input_manager_macros"
version = "0.13.0"
in my .lock after upgrading to leafwing 0.14 ?
Yes; I didn't bother updating the macros crate because nothing changed
ok, ty ๐
I don't get why, but some of my tests with leafwing don't seem to be deterministic
Tests of the form:
app.world_mut()
.resource_mut::<ButtonInput<KeyCode>>()
.press(KeyCode::KeyA);
app.update()
sometimes my input-press isn't registered for some reason
Hmm that's very weird
this kind of bug is probably some system ordering error on my part, but I can't figure it out
It's funny, I literally just came to this channel to ask if there was a way to force a press for testing
another day another forget to .add_plugins(InputManagerPlugin::<XyzAction>::default())
wish it printed errors when i tried to read actions that arent registered
Issue please?
That's a great idea
i was brainstorming last night how exactly i'd go about implementing that and i think its possible, it would resolve my most common footgun with lwim
not really a footgun tbh but not sure what else to call it. its definitely user error just easy to froget
Yeah, I've done this too lol
Wrote an issue about disabling an entire ActionState: https://github.com/Leafwing-Studios/leafwing-input-manager/issues/563
how much latency does lwim add on top of bevy's input latency and whats the lowest latency way to do input in bevy
im looking to fire a midi note as soon as possible when a key is pressed, i dont care about framerate
I don't think lwim adds any latency as long as things are ordered correctly, but bevy's entire input system is currently tied to FPS and you don't actually receive input timestamps so you can't do a nice workaround like playing the notes with a consistent delay so it doesn't mess with timing ๐ค
how is input lag normally solved anyway? it can't be just fixedupdate because it's too slow, and i can't imagine mixing both being a good idea
FixedUpdate would just add more lag, since it's just a loop running inside the frame's logic (tho that could possibly be decoupled, but that still wouldn't help outside of making things more consistent than FPS)
The usual solution here is to just not care about the lag. If you press a button, the sound comes out 50ms later, your mind will convince you that it was instant, despite that clearly not being the case
Alternatively you can handle inputs async and play sounds immediately with minimal lag and most importantly a perfectly consistent way
The obvious downside here is that you can't really use any built-in systems, which can be very problematic if it's not an app trying to do one specific thing, but a game that potentially does multiple things based on an input
https://github.com/Leafwing-Studios/leafwing-input-manager/pull/548/ is passing CI, kinda ๐
There's some follow-up that must be done before shipping, namely investigating why action diffing is failing and refactoring how clashing inputs are handled
This is already a very very large PR though, so I've marked the failing tests as ignored and I'm going to merge
Generally very pleased with the results though: the API and general contract of the crate is much clearer
And there's less "well, the user asked us a malformed question, what do we do?" nonsense like asking if axes are pressed
what happened to @candid vigil btw
Overall i think the refactor goes in the right direction, it was strange to have both button/1d-axis/2d-axis data in the same ActionData
I'm not fully convinced about having 3 separate hashmaps for each action though
Each action will only ever be represented in one of them
This is really strict now
So the 3 hashmaps are really just an implementation detail
How can I check if I'm focusing on an egui node to turn off leafwing's input processing?
I used this https://github.com/mvlabat/bevy_egui/issues/47#issuecomment-1922695612 : basically get the egui context, then use .wants_pointer_input() or .is_pointer_over_area() (according to your needs). Then you could put this in a Resource or a run-condition e.g. egui_has_focus
Question regarding this feature in LWIM's readme:
Create an arbitrary number of strongly typed disjoint action sets by adding multiple copies of this plugin: decouple your camera and player state
Concretely, when two input maps exist that use the same keys, do both get actions when I press that key? Is there a way to set priorities / disambiguate which of the non-disjoint input maps gets the action?
Yes. No, but you could disable them ๐
Would there any way to record a set amount of inputs and replay them?
Not out of the box
You probably want a dedicated crate for that
leafwing_input_playback?
https://github.com/Leafwing-Studios/leafwing_input_playback
doesn't seem to be updated for 0.14 though
Yep ๐ There's another crate that came out in this space too...
What are the best LWIM practices for letting the user configure keybindings? Probably something like modifying input maps, but I'm not sure what's the "right" way to do that.
Modify the input maps, ideally with a menu
It's sorely in need of an example though
& probably serialize it & save to the user's profile somewhere
https://github.com/Leafwing-Studios/leafwing-input-manager/pull/570
-1k lines of code for the input mocking refactor
Love to see it
i'm noticing that if i press A and then press Shift, then release Shift, it's yielding "action just pressed" for A, then Shift+A, then A again
i would expect just A
(i have one action mapped from A and one action mapped from Shift+A using insert_modified)
the second A is definitely a bug, the Shift+A may be debatable
this is in the latest LWIM release + bevy 0.14. i can open an issue later if there isn't one already, just busy with jam rn
Issue please!
trying to do mouse position stuff for the first time, ran into https://github.com/Leafwing-Studios/leafwing-input-manager/issues/567 - anyone know if there's a workaround to do mouse position things in 0.14?
I think you might need to add a value to the ActionState first because by default the hashmaps are empty
thanks, yes i figured out how to write DualAxisData to the action state myself, which works nicely
Hi, how does the result action.axis_pair() is computed? Is it accumulated of EventReader<MouseMotion>?
Is it safe to use action.axis_pair in FixedUpdate for physic based rotation? I'm concerning that it will lost some frames because its seem action data is reset every Update
Yes
These values will be cached correctly, but that change isn't shipped yet ๐ฆ
Ok I can wait then. Thanks for the information.
I ran into an issue where using .pressed() and other variants respond to all gamepads regardless of the associated_gamepad. Did some looking an I think it is due to this line in input_streams:
InputKind::GamepadButton(button_type) => self
.associated_gamepad
.into_iter()
.chain(self.gamepads.iter())
.any(|gamepad| {
self.gamepad_buttons.pressed(GamepadButton {
gamepad,
button_type,
})
}),
It iterates over the associated, but then also chains all the gamepads into the iterator to check for the press. .value() correctly only responds to the associated_gamepad when set though.
Can you reproduce this on main?
It seems I cannot. Looks to work on main
Alright, rubberducking a bit
The input mocking PR is now merged, which is great
This is the set of issues I want to hit before the release
There's a few refactors, and a few bug fixes
I should do the refactors first, because there's a good chance I'll discover better ways to solve the bugs
Better disabling should be done following share metadata
And trait-based clashes are probably a good follow-up to remove input streams
Both of these are pretty orthogonal
I think the metadata one is the easier one, so I'm going to start there 
i'm wondering if the way that https://github.com/Leafwing-Studios/leafwing-input-manager/pull/573 works means that if a key is held down while an ActionState is disabled, and then the ActionState gets enabled, it will trigger "just pressed"?
at a glance it seems that way, since all the ActionData get reset and update is skipped while disabled
if so, i think that's an issue. since "just pressed" is used to trigger in-game effects, it should correspond to the user physically pressing a key from unpressed, not from disabled
the way this was handled at the ActionData level was to continue updating the input state, but report it as "released" regardless of the actual state (while disabled)
tldr "input is pressed but the action is disabled" is an important state to keep track of
Yes, I think that's the case
I think that's what consumed is supposed to represent, but I'm regularly frustrated by how unclear / unituitive it is
@swift summit can you make an issue for this so I fix it before release?
sounds good
I just did a quick and dirty migration from Bevy 0.12 to 0.14 and 0.11 LWIM to 0.14, but I am noticing an issue where alt+key is not registering
unless I click at the same time
This is probably a simple mistake on my part
It's the despawn here that is failing```rs
fn spawn_or_despawn_gizmos<'a>(
mut commands: Commands,
window: Query<&Window, With<PrimaryWindow>>,
window_dimensions: Res<WindowDimensions>,
action_state: Query<&'a ActionState<Action>>,
gizmos: Query<(Entity, &'a Transform, &'a GizmoType, Option<&'a Positive>)>,
) {
let action_state = action_state.single();
let window = unwrap_or_return!(window.get_single().ok());
let cursor_pos = unwrap_or_return!(window.cursor_position());
let cursor_pos = Vec2::new(cursor_pos.x, window.height() - cursor_pos.y);
for gizmo in GIZMOS {
for (variant, positive) in [
(Some(&gizmo.neutral_or_negative_variant), false),
(gizmo.positive_variant.as_ref(), true),
]
.iter()
.filter_map(|(x, p)| x.map(|x| (x, p)))
{
if action_state.just_pressed(&variant.action) {
if action_state.pressed(&Action::DespawnAllModifier) {
despawn_all_gizmos(&mut commands, &gizmo, &gizmos, *positive);
} else if action_state.pressed(&Action::DespawnModifier) {
despawn_gizmo(
&mut commands,
cursor_pos,
window_dimensions.0,
&gizmo,
&gizmos,
*positive,
);
} else {
spawn_gizmo(&mut commands, cursor_pos, &gizmo, *positive);
}
}
}
}
}
especially the despawn all. the spawn always seems to work
I only ask because I suspect it's a simple migration oversight, if it's not then just ignore this and I'll try to dig deeper
It could easily be a scheduling thing, actually
Most of my application runs in FixedUpdate but that specific system runs in Update
It doesn't even run the just_pressed when alt is down so it's not recognising alt+1 as a press of 1, unless I am also holding down LMB at the time. That can't be intended behaviour
I don't think that this is likely to be a migration oversight
Can you check on main please?
I really don't want to try and push fixes to the 0.14 branch if possible
๐ Once https://github.com/Leafwing-Studios/leafwing-input-manager/pull/576 is merged, all of the barriers to "just add your own input type" will be removed ๐
Trying```toml
leafwing-input-manager = { git = "https://github.com/Leafwing-Studios/leafwing-input-manager.git", branch = "main" }
Unchanged
It's hard not to blame myself because I haven't even touched Bevy in months though, this was just me being bored and going for a quick migration to pass time
but it worked before
Yep ๐
If you can get me a minimal reproduction I'll take a look โค๏ธ
I suppose I am constructing a chord in an unusual way
Before I do that, I wanna make it clear: if 1 is bound to Action::Blah, and alt is bound to Action::Bloo, then is alt+1 supposed to activate Action::Blah, and return true on Action::Bloo being pressed?
assuming alt was pressed down before 1 was
(implied by alt+1 but I figured I'd be explicit)
Bloo should stop being pressed
Assuming standard clash handling
Is the same true for shift+1?
I do vaguely recall something being changed in this area
Yes
My shift+1 action is coded the same way as my alt+1 action, with makeshift chords, but that one always works. I also confirmed that just holding RMB is enough to make alt+1 work, even though RMB is not bound to anything
That's super weird
On a whim I tried ctrl+alt+1 and that works.
To be clear though I already confirmed that the 1 action never triggers on alt+1, rather than 1 triggering but the alt not being pressed anymore
shift+alt+1 does not work
Doing the minimal thingy now
does not have minimal compile time
Doesn't repro in minimal
and to be clear what happens in miminal is every modifier is individually detected
In my actual project I have a very unusual way of handling the binds, actually, because I have a const array of 4 items like ```rs
Gizmo {
gizmo_type: GizmoType::Deleter,
neutral_or_negative_variant: GizmoVariant {
action: Action::Deleter,
draw_properties: draw_properties::DELETER,
},
positive_variant: None,
has_movement: false,
},
I will try that in my minimal repro next
Didn't change behaviour
Is there anything to be mindful of when mixing FixedUpdate and Update reading of the action state?
You really want to wait until the next release to try and read the actionstate in FixedUpdate at all
(soon! I'm working on it...)
I was only reading it in fixed update in 1 random place, and I changed that now
doesn't change bug (nor could I reproduce bug by reading in fixed update on purpose)
It's one of those bugs ๐ฉ
Are you changing window focus during this maybe? Winit has some freaky phantom button presses
I don't see how I would be doing this by accident in the one application but not in the other. Can the application itself cause a loss of focus?
Generally not no
Does it work if you change the key bind? Especially to a non modifier
It already does work currently with another modifier, shift, but I'll try that
It detects alt press, but it no longer recognises the 1 press, during the alt press
(unless holding LMB or RMB)
It's like a different action is capturing alt+1, but I have no chords set through LWIM
In my minimal repro, holding down both shifts counts as holding down shift, holding both ctrls counts as holding down ctrl, but holding down both alts does not count as holding down alt (I bound both of each)
Yes
Debug your input map?
(debug-print)
How do I like... do it at the right moment? It floods my terminal if I do it all the time
and I can't do it in reaction to pressing the 1 since it's not being picked up
Hmm ๐ค You could try just checking ButtonInput<Keycode>?
Although TBH for the InputMap, you should just be able to info_once! it, since it should be static after startup
I did log it btw, nothing suspicious to me
just a whole bunch of ```rs
SpawnParticle: ActionData { disabled: false, kind_data: Button(ButtonData { state: Released, update_state: Released, fixed_update_state: Released, consumed: false }) }
Maybe I should log the other one
I guess you said input map
Nothing suspicious there
Isn't the double alt thing already quirky behaviour? It's in my minimum repro, fwiw
How do you mean?
Also: what happens if you change the clash strategy to None?
Pressing both shifts is recognized as the action they're both bound to being pressed, same for ctrl, but not for alt. either alt works, but not both
This has the exact same behaviour```rs
if keys.just_pressed(KeyCode::Digit1) {
if keys.pressed(KeyCode::AltLeft) {
println!("Seen");
}
}
So weird
What OS?
Windows 10, but it's extra weird that I can't reproduce it, same Bevy version
Maybe I should've gone the other way and deleted things from my project until the problem goes away
Both alts down it takes no input in repro, in the real project it's only left alt that works that way
Or right alt (either alt)
(this is my project, it's not far beyond the minimal project)
if keys.pressed(KeyCode::Digit1) {
if keys.pressed(KeyCode::AltLeft) {
println!("Seen");
}
}
```this now actually does work, even as the 1 action fails to activate. I'm just giving up, ctrl works I'll change to that
GL
@umbral linden action-diffing is fixed ๐
Note that the behavior will change a bit for 0.15
Rather than generating 3 events every time you press a button (setting the axis value, dual-axis value and button state), it only generates 1 (button was pressed)
And vice versa for axislike inputs
Much simpler, and less wasteful
That's way better, awesome!
@swift summit thanks for the design / prompt on how to handle disabling actions
This is much simpler / less buggy
#crates message and released ๐
Why would InputMap<PlayerAction> and ActionState<PlayerAction> return None for TypeRegistration::data ?
er, specifically .data::<ReflectComponent>()
I may have forgotten to reflect component
In my troubleshooting I added #[reflect(Component)] to both InputMap and ActionState but it didn't solve the specific issue (which came when using blenvy to spawn a blueprint and registering the inputs in a hook). Maybe something more needs to be changed for that workflow to work.
@valid stratus, any tips?
there's an open issue for the issue @silent drum mentioned, which my question is connected to.
tldr; it came down to InputMap/ActionState not having .data when trying to reflect the component information, but I wasn't sure if they should have data.
Did the stuff necessary to use LWIM in FixedUpdate get in yet? ๐ค
https://github.com/Leafwing-Studios/leafwing-input-manager/pull/586 I added the reflect(Component)s as it seems to fix the blenvy issue consuming the types.
Yes this is in
actions are not initialized as ButtonData right?
The first time i try to call set_axis_pair on an Actionlike that never appeared before (and I can verify via logging that it's not in the ActionState) my app crashes
Ah i see that the trait must be manually implemented
if you are storing non-buttonlike actions (e.g. movement) inside of your Actionlike enum, you must manually implement the trait
That's a bit misleading, i propose 2 changes:
- add a
#[actionlike(Button)],#[actionlike(Axis)]attribute on theActionlikederive macro to make it easier to configure the action type
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy, Hash, Reflect, Actionlike)]
pub enum PlayerActions {
Up,
Down,
Left,
Right,
Shoot,
#[actionlike(AxisPair)]
MoveCursor,
}
- don't require the user to specify the action type at all; the first time the user calls
set_axis_pairthen you can just create anActionData::AxisPairfor this action. Do we need to statically know the action type of an action?
(also because I would like to use Button for some of my actions, like Up/Down/Left/Right, and AxisPair for other actions like MoveCursor; even though they are part of the same Actionlike
ah actually that seems supported
Nice, guess I can finally write something sensible if I refactor my input stuff again (to fix inputs getting dropped at non-60FPS)
Correct
I really like the first idea: can you make an issue or PR?
As for the second... I'm a bit more nervous
I don't think that's an easy refactor, and it risks correctness elsewhere
the checks wouldn't check against InputControlKind, they would check by matching against the ActionDataKind, but fair enough it's a pretty big change
there's no consume anymore?
Yeah. Did you see https://github.com/Leafwing-Studios/leafwing-input-manager/pull/582 ?
Closes #443.
This functionality is complex, niche and extremely confusing for users. As we prepare for upstreaming, this needs to be cut.
Generally speaking, to work with this sort of "cap...
ah i see, thanks
I ran into an issue where I'm using the pressed function on an ActionState. I'm triggering this assert https://github.com/Leafwing-Studios/leafwing-input-manager/blob/main/src/action_state/mod.rs#L737. When I double checked my code with the axis_inputs example by running the example locally I'm also triggering the same assert. Is this example no longer correct? I'm not sure how to solve it otherwise.
assertion `left == right` failed
left: DualAxis
right: Button
Btw, I was also wondering why LWIM depends on rc3 of Bevy 0.14. I saw now for the LWIM 0.14 release that the dependency on rc2 was removed, but was it reverted later to rc3? Or am I reading the Cargo file wrong?
It depends on 0.14.0-rc.3 or a later semver compatable version, 0.14.0 is considered compatible and so is 0.14.1, so it doesn't really matter ๐ค
Oh ok. I asked ChatGPT about Rust semver versions and it claimed that a rc version works differently and only matches exactly and not ^ like normal. But it was at first saying that it always matches exactly on regular version numbers as well so I had to correct it, and it "promised" that it was saying the truth after the correction ๐คฃ Damn ChatGPT with all its lies.
It's honestly hard to find accurate info on how rcs work. Iirc the book is the only place that's accurate, but you'll probably find tons of issues with very old info or things that are very misleading
i don't think examples got updated, but InputMap has a doc that shows how to use it in 0.15
not sure why .pressed doesn't work with axis anymore, but i'm not sure if it made sense in the first place
You mean here: https://docs.rs/leafwing-input-manager/0.15.0/leafwing_input_manager/input_map/struct.InputMap.html ? It doesn't really show the update function AFAICS.
The example on the main page only shows the Jump and not the Run update ๐
yeah, documentation/examples could be better
for now just don't check if axis is pressed and assume that it always is
Oh right, didn't even think of that. It's just a no op if it's 0 anyway.
@karmic monolith that assert could give a better explanation, and btw the doc implies that it can be "not a buttonlike action"
@karmic monolith I updated some examples where I use JustPressed in FixedUpdate, it seems to work fine ๐
Are you up for opening an issue? It's helpful to have a better sense of what exactly users are confused/annoyed about
is it actually intended though? i was using it with assumption that the code block won't run if it's in deadzone/idle
I'm really not sure what you mean here ๐
if pressed(axis input) used to work before, not sure if it actually did anything though since like perry's case it wasn't something i'd notice if it just was using 0
if e.g. stick is in dead zone, i expected if pressed(axis input) to return false, is it supposed to just be if input == Vec2::ZERO now?
Yep, that's the correct migration ๐
what if it's not 0 but input is disabled? do i need to check that manually?
Disabled inputs will always return 0 / released when you check their value ๐
Just updated this crate, what is the new way of doing:
input_map.insert(Self::Zoom, SingleAxis::mouse_wheel_y());?
input_map.insert_axis(Self::Zoom, MouseScrollAxis::Y);
I dont have MouseScrollAxis , my cargo toml has : leafwing-input-manager = {version="0.15", default-features = false}
In the middle of updating all my deps, so I might have messed up somewhere
You need to enable the "mouse" feature ๐
The various input modes are now feature-flagged
I would like to pan the camera:
.with(Pan, ButtonlikeChord::with_multiple([KeyCode::Space, MouseButton::Left]))
but MouseButton is not a KeyCode. My rust-fu is not good enough for this. How do I combine Keyboard and Mouse input?
with_multiple requires a homogeneous type. You have to call ButtonlikeChord::new().with(A).with(B) โค๏ธ
Thank you! Works like a charm (had to swap new with default but even my rust-fu is strong enough for that one ๐ )
am I missing something or is the previous_duration broken? (macOs 14.5, bevy 0.14, leafwing-input-manager 0.15)
It might be: we don't have a ton of tests there. Can you open an issue?
Will do!
I'm getting this error in wasm but i'm not sure why:
--> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/leafwing-input-manager-0.15.0/src/action_state/mod.rs:203:51
|
203 | .for_each(|action_datum| action_datum.tick(_current_instant, _previous_instant));
| ^^^^ ---------------- ----------------- expected `std::time::Instant`, found `bevy::bevy_utils::Instant`
| |
| expected `std::time::Instant`, found `bevy::bevy_utils::Instant`
I'm using bevy::bevy_utils::Instant everywhere
I screwed this up; a patch is merged but not shipped
what is the problem, out of curiosity? couldn't figure it out
I used the standard library time types internally in one spot
Which breaks on web
I'm trying to send ActionDiffEvents from client to server, and used to do this by wrapping it in a MappedActionDiffEvents that implements MapEntities (& making a copy of the generate_action_diffs system to support the wrapped type), so that client entity IDs can be translated to server entity IDs.
But maybe I should just impl MapEntities for ActionDiffEvents<A> directly in LWIM and get rid of all the wrappers & copies -- would this be a good idea? (can write a PR)
i updated to LWIM 0.15 and had to replace Actionlike derives with manual impls + match on all my action variants, which feels bad. i assume there's a good reason this is necessary? also i wonder if the derive macro could support field attributes like #[dual_axis] to make this easier
yup thanks gave ๐
Yes I think it's a good idea
Yeah, field macros will help a lot IMO
Welp, here's something concrete to talk about https://github.com/Leafwing-Studios/leafwing-input-manager/pull/598
LGTM ๐
hey, trying to use DualAxis for character movement.
looking at the virtual_dpad example, it seems like it's exactly what i want.
now, at line 53 action_state.pressed is used.
... but i struggle to make that work on my end, as it crashes because of the assert in the beginning:
assertion `left == right` failed
left: DualAxis
right: Button
I really should have fixed up the examples... ๐
You need to change the Actionlike impl
And probably don't check if a dual-axis is pressed
I'll get a full set of fixes up for the examples early next week when I'm back from vacation
#1034547742262951966 message
It's been a while since I've been over here. I was in the hospital
I guess there could be two small improvements to LWIM
First, for the input_control_kind method of Actionlike, I feel we could add [axis] and [dual_axis] field macros to the Actionlike to reduce some redundant code
But I don't think the InputControlKind design is ideal
Second, the InputManagerBundle might be able to be removed
Could we add the corresponding ActionState in the InputMap's component hook?
And the once::Lazy used for trait serde could be replaced with the std ones
I feel like this should stay how it is until required components drops
I think there's an issue for this already! It'd be a very nice ergo improvement
done by PR #603
I'm trying to understand the purpose of the Triggerlike trait
Could you elaborate on the conditions that would lead to a ButtonInput<Trigger> being false while the corresponding Axis<Trigger> is non-zero?
welcome back, i was actually wondering where you've been [for a while now](#1034547742262951966 message)
Seconding this ๐
Damn, I hope you're doing alright!
I am very pleased by this!
So, triggers have fairly unique behavior compared to single-axes:
- 0 to 1, versus -1 to 1
- can be pressed and released
- thresholds for when they are considered pressed and released
We could add this behavior onto Buttonlike instead though.
That's not how gilrs exposes the data
i mean it doesn't really make sense to me why they're connected in the first place, they feel more like 2x single axis
and couldn't threshold be done with axis too, since it needs a deadzone anyway? or is that pointless and handled somewhere else already
Deadzone behavior for axes versus triggers is different though: for axes it sets the values to 0, but for triggers you want a zone in the middle that will neither trigger a press or a release
wouldn't some kind of a processor be better for both? i'm pretty sure it'd be easy to find cases where setting to 0 would be needed from triggers, and i wouldn't be surprised if someone wanted to use press/release with axes
That's the sort of muddling that I found myself in a lot of trouble for in the previous design ๐
I think I want to steal the axis processor tech for triggerlikes though
did you already try making visual editor or rebinding for players? they'll probably affect the final design a lot
and i'm mostly thinking from that end... processor would allow splitting the triggers or any other weird thing players might throw at it
If a trgger is made up of two triggers ... Isn't trigger_pos - trigger_neg enough to get the -1 to 1 behavior with correct deadzones? ๐ค
So Triggers need a saturation processor
Will axes use that?
I'm leaning towards adding TripleAxis first
It seems useful for a RTS camera
Any ideas for what to call the virtual buttons? DPad3D?
VirtualSpaceMouse 
Then we'd have these really long names like KeyboardVirtualSpaceMouse and GamepadVirtualSpaceMouse...
I'm not sure if we should separate them
Previously I feel like virtual axes and dpads, which use multiple Boxes, are frequently used for common actions like moving and zooming
Given LWIM isn't event-based, input values are checked every frame, and those pointers might impede compiler optimizations
My original plan was for Input to take &World as a parameter, which means it would read the Resources multiple times without optimization
But now using CentralInputStore seems to address this concern
Thanks! It's been tough, but I'm feeling much better now
Yeah, triple axis is much easier
Man I'm at a loss for this. DPad3D can do for now
that would be awesome. It's indeed important for 3d fps like games
Oh and FYI the space mouse is actually 6 axis ๐จ
We'll probably add support for that later lol
imo 6dof inputs can just be two 3dof ones
I typically would use one for rotation and the other for translation. As a counterpoint to that, VR controllers
That said, you could always bind something to controller rotatoin and something else to controller translation
Being able to get an Isometry3d straight from your inputs would be so sweet though
InputKind::Isometric would be the name IMO
I have a question
In Bevy's scene coordinate system, forward is -Z and backward is +Z
So, does the DPad for TripleAxis also need to follow this rule?
I think we should coordinate with this yeah ๐ค
yeah, TripleAxislike is ready, after #608 is reviewed and merged, I can rebase and push it
Fantastic
Thanks for reviewing and cleaning up the mistakes I made during all the refactoring ๐
That was too much all at once lol
I feel like if I had to copy-paste the same code three times, I'd probably mess up big time too haha
ready!
And https://github.com/Leafwing-Studios/leafwing-input-manager/pull/609 is reviewed!
added TripleAxislike trait for inputs that track all X, Y, and Z axes.
added KeyboardVirtualDPad3D that consists of six KeyCodes to represent a triple-axis-like input.
added TripleAxislikeChord th...
I feel like making inputs trait-based and splitting them to Buttonlike, Axislike, etc. seems to complicate InputMap and ActionState
Their interfaces wouldn't be compatible with other inputlike traits unless we add support in LWIM manually
A simpler approach might be to split them up as well: ButtonBindings, ButtonActionState, AxisBindings, AxisActionState, etc.
I mean, if users follow good coding practices that an input handling system probably only handle a few kinds of input
Even if there's overlap, we could just change spawn(InputMap) to spawn(ButtonBindings, AxisBindings) and Query<ActionState<Action>> to Query<(ButtonActionState<Button>, AxisActionState<AxisAction>)>
But obviously, this would be a huge breaking change
bevy's coordinate system is already cursed enough, you don't have to make it even worse by messing with input
I think that aligh with Web design that z-index means depth
i changed to Z-up Y-forward and i doubt i'll be the last person to do it
+Z means closer to you, and -Z means farther away
it might make sense for ui, but it's completely counter-intuitive for 3d
yeah
Yeah, I think this would make things easier on the implementation side, but IMO it's worse on the user side
Being able to clearly list "here are the things the player can do" is really nice for conceptual organization, input binding and handling more complex state machines
BTW @candid vigil I think I'm going to tackle triggerlike today
agreed
I got that idea mainly because of these two functions. We have to add a lot of suffixes.
Yeah ๐
We could be less picky about what we accept, and then rely on a constant or method on UserInput to put it in the right map
And if a user wants to add their own Input-like trait, the current InputMap and ActionState don't support it
Yeah
I'm not sure we're going to run into that many more ways to extend it though
Unlike novel input mechanisms
If stable rust supports dyn T where T is a type parameter, I think it would be much easier
Perhaps when bringing this up to bevy, we can benefit from the collective wisdom of a larger community ๐ค
Not many people are talking about it here
๐ I believe deserialization for inputs must be broken
because their deserializers are only registered in UserInputRegistry, but the actually used ones like ButtonlikeInputRegistry are empty
I've got another idea
We could probably remove all Inputlike traits and only keep the UserInput trait, like in my previous version
That PR was designed to minimize API changes, so the trait had methods like pressed, value, axis_pair, and so on
But I had an idea to make it simpler with just a fn get_data<T: DataType>(&self) -> Option<T::ValueType>, where DataType is a trait with implementors like Pressed, Released, AxisValue, etc
Essentially, there's a Res similar to the current CentralInputStore, but each input store a HashMap<DataType, DataType::ValueType>
For instance, a Trigger could have Data like {Pressed: true, AxisValue: 0.6}.
So, action_state.get_data<Pressed>(Trigger) returns Some(true), and action_state.get_data<AxisValue>(Trigger) get Some(0.6)
Or Result?
๐ค Maybe returning Some((true, 0.6)) by calling action_state.get_data<(Pressed, AxisValue)>(Trigger) and action_state.get_data<Trigger>(Trigger)
like Query
Associated types aren't object safe ๐ฆ
Well, they kind of are
But you can't mix them
just googled "bevy playground" to try and prove a point, thanks Alice
i don't remember if this counts as object safety, or if i need to slap it in a Box
but if you specify the GAT you can use a dyn trait
but yeah, having to specify the GAT destroys the whole point
๐ค Just unit structs, and their TypeId as the map's keys, then use TypeId to retrieve the value?
type erasure will work but you need to have a safe API for retrieving the type
I'm not familiar enough with LWIM to say anything about that
wouldn't an enum work just fine here? no one is gonna invent a new action type, will they?
LWIM now does have a type-erasued one, so I think that might not be a problem
Yeah ๐ค
does LWIM require every action to be a new type?
like, if I define a "jump" i need a struct Jump marker type?
okay, then it's not as easy
if every input was a different type you could derive the input type at compile time and have a very clean api
yeah it could be
eg
struct Jump;
impl ActionMarker for Jump {
trait ActionType = Buttonlike;
}
// [...]
let jump = actions.get::<Jump>(); // knows the return type from <Jump as ActionMarker>::ActionType
if it's an enum and every variant returns something different then it has to happend at runtime and you need falliable API
like, try_get::<Buttonlike>(PlayerAction::Jump)
and probably a bunch of helper methods that provide the generic, try_get_button(PlayerAction::Jump)
honestly, that doesn't look too bad
just a little bit of sugar
but you need to deal with unwraps
I think the problem with this code lies in the type of actions
Since Rust doesn't have wildcard generic types in parameter types, we can't get something like Actions<_>
So if we have a new action type, we will need a new system that processes its state ๐ค
Currenty in LWIM, if you add a new action type, you'll need to add an InputManagerPlugin::<Action> to your plugin set
which is more annoying I think ๐
each plugin adds 11 systems to your app
there isn't much of a difference between adding a generic plugin and using a generic add plugin method
I mean, if you have two different action types, for example, Move and Jump
LWIM requires you to write down app.add_plugins((InputManagerPlugin::<Move>::default(), InputManagerPlugin::<Jump>::default()))
If they're just different variants of enum PlayerAction, we only need app.add_plugins(InputManagerPlugin::<PlayerAction>::default())
Anyone have more ideas for https://github.com/Leafwing-Studios/leafwing-input-manager/discussions/610 ?
I think my upgrade to 0.15 is mostly complete, but I'm hitting one small issue. I use actions for navigation from other systems. I have a dual-axis Translate action used from my pathfinding sys...
Wait there's no deadzone by default? ๐
I took it out. It used to be there
but I think the default deadzone of 0.1 for both X and Y isn't great for many cases
People might want to tweak it
Also, the new processing pipeline is a Vec, so you have to know the exact index to change anything
I think it would be better if all built-in inputs started with an empty pipeline
yeah, i think that'd require trait queries?
Yea that makes sense ... I'm just surprised I never had issues with no deadzone ... I'll have to add some deadzone tho, people already complained in my last game release (before those reworks) that they got drift from a random connected controller ๐
I see now that my actions caused an issue. Sorry about that ๐
Since that was on the version before these reworks I'm pretty sure deadzones were still there
changing default behaviour is evil because your application will still work in a lot of scenarios
breaking changes at least force you to address the issue
yeah
It's a big change but I think it's also a huge enhancement
Before, things like sensitivity, inversion, and deadzone were just fields of an input, and the order they were applied was fixed
That means input.sensitivity(2.0).inverted().deadzone(0.15) was just modifying the corresponding fields, and the order couldn't be specified
if you wanted Sensitivity to be applied after Deadzone, you had to calculate the result manually
In the new version, there's a field that's a Vec<Processor>, so you can specify any order of processors and can also apply different Deadzones simultaneously (some games are quite complex)
Do we have a "multiply_by_delta" yet tho? ๐ค
Previously input.sensitivity(0.5).inverted().deadzone(0.15).sensitivity(2.0) means:
- Scale up the input value by 2.0 (sensitivity has been overriden)
- Flip its sign.
- Apply a deadzone of 0.15
After 0.14 it means:
- Scale down the input value by 0.5
- Flip its sign.
- Apply a deadzone of 0.15
- Scale up the result by 2.0
The fact that sensitivity comes before deadzone sounds especially unintuitive ๐
The old code was like that. I hadn't used Bevy back then
not having to guess the order of execution is nice
I'm really pleased with how this design came together ๐
I remembered needing it but not why, but it's pretty obvious: To make the camera stick and mouse movement match, and to have button-based zooming match scroll-wheel based zooming
Yep!
So do we have anything for that yet? ๐ค
Doesn't sensitivity cover it?
Sensitivity doesn't make my inputs FPS independant right? ๐ค
I don't think it should?
Yea, sensitivity definitely shouldn't ... But inputs like "Hold input to move" should be scaled by time while inputs like "Move by X units to move" shouldn't
If they're both "Hold input" it's easy to handle at the system level, like WASD vs a gamepad stick. But with gamepad stick vs mouse movement you can't handle that unless you look what's in the input (which seems counter to what LWIM tries to achieve)
And the same applies with scroll wheel to zoom vs hold left stick to zoom in and right stick to zoom in or whatever zooming scheme you come up with for controller
(Are those even reasonable bindings for zooming on a controller? Idk, I literally still have "TODO: controller bindings for zooming" in my code)
Sorry to interrupt with a tangent: What's the best way to dig out the mapped input for an action so it can be displayed in a menu? Let's say for gamepads only for now, as I don't want to open the keyboard input pandora's box in this discussion. ๐
I'd basically like to match over the mapped input to translate it to another value (for example a string to display a character in a font). I could do it with 0.14 and earlier, but now that everything's a dyn Buttonlike I don't know how.
I think you can get the bindings with methods on InputMap
But you do get boxed traits that you'd have to turn back I think, which might not be the most painless thing ๐ค
Hey @candid vigil did you run into a pile of RA warnings about "unexpected token"?
Something is funky with the macros locally, even though cargo build runs fine
Trying a cargo clean...
welp, that fixed most of them
???
Bah lol
Oh, nope, it didn't
Well, I can cope ๐ฅฒ
if i want to fake keypresses to appear like the user pressed them am i right in thinking i just do: action_state.press(&PlayerActions::Up); and .release(..)? where should i order my system that does that so it's detected correctly?
Yes, or you can send real key press events ๐
You generally want to send synthetic events like that in PreUpdate in ManualControl
SystemSets for the crate::systems used by this crate
The key thing there is "after InputManagerSystem::Update"
fab, thanks!
if i say action_state.press(..) does that stay pressed until i release(), or do i need to call press() each tick to synthetically hold the key down?
i'm getting some flickering of my fake inputs atm
i'm reading the action_state in FixedUpdate fwiw
I don't remember the current behavior ๐
think i have to set it every frame..
Yeah, that sounds right
sometimes I get similar errors when running CI locally, like "can't find crate for bevy" and "unresolved import bevy::prelude::*"
Yeah, I got that far when trying to migrate my old implementation onto 0.15. I guess I'll just need to learn some more rust to get the boxed traits into actual concrete types ๐ค
the latest RA release broke something... going back one version should fix it
Oh useful, thank you
Ah, i was getting these unexpected tokens this morning. Annoying.
For 0.15, is there a built-in run condition for detecting dual-axis inputs? Used to use action_pressed / etc. but looks like they only support button inputs now.
Nothing write now, but I'd welcome a PR that adds variants for this
3DPad ๐
Surely it should be 3d in all cases, rather than 3D
my inputmap maps mouse left click to an action, and i enabled the "egui" feature, hoping that would stop the actions if i'm clicking on egui things, but they still register. is there somethine else i need to do, or am i misunderstanding the feature? i don't want my engines to fire when i left click egui buttons etc.
There's a bug open for this: something seems to have broken recently
ah, ok. thanks
Would somebody have some insight into this conundrum I posted a couple of days ago?
There's InputMap::get that takes an action and returns a Vec<UserInputWrapper>
That's a start at least... not sure how to get the actual button represented
It almost looks like you have to do it yourself. Maybe some struct that stores mappings from input <-> action, then can be converted into an InputMap. Then any time that struct changes, you regenerate the input map
Seems like a sizable hole in lwim's API, but also can't think of any way to fix it off the top given that we can map arbitrary inputs to actions, which is something nobody wants to give up
You get boxed traits so you should be able to downcast them to the impls no?
But yea having a better API for that would be great. LWIM has had varying levels of difficulty for this but afaik it has never been easy, which is one of ther reasons I haven't attempted to make any keybinding UI or accurate input prompts
Yep agreed
Probably the biggest question is what the API would look like ... I guess you ultimately want an enum that's easy to translate to some icons, and you can probably group the enums by separate groups like button vs axis
I think that starting with a Display impl would be nice
Which you can then map to icons using localization / asset path style tech
Ah makes sense
having a clear list of goals would be a nice start for that
along with a list of everything that can go wrong
can LWIM distinguish between PS/xbox/nintendo controllers btw?
i guess it's just north/east/south/west that change between them though, i'm still not sure how UI would handle that
Iโm a rust newb so Iโm completely not sure about this, but isnโt it so that I can only downcast to the concrete impls if dyn Buttonlike can first be cast to dyn Any?
Yeah, even a simple Display impl would work to just get something identifiable out.
Yea, I think two important ones are:
- Give you something to map to a set of icons
- Have LWIM provide a decent baseline for picking which to use if there's multiple but only 1 shown
If we can recognize differnent controllers and use that in the display too that would be great
actually showing alternative bindings could be interesting though
If we can recognize differnent controllers and use that in the display too that would be great
IIRC this is viable with a bit of gilrs integration
"press c or ctrl to crouch"
A decent baseline would probably be:
Has this input been used? If yes, show the last used input
Has any inputs of the types registered been used? If yes, prefer that
Is a controller connected? If yes, prefer that
Is one of the input options missing? If yes, deprioritize that
If all else fails pick the first option
wait, is it possible to make a key toggle with LWIM?
like "press c or hold ctrl to crouch", where c is toggle and ctrl isn't?
There are also some other considerations, like the API needs to be friendly to chords
Because chances are Shift + 1 is just as valid of an input as Q
i always have a controller connected, it's not a good idea to check that...
on PC it should default to MKB until controller is actually used
Defaulting to controller generally makes the most sense so people can immediately recognize the game can be played with controller ... But it gets really annoying when it only shows controller just because you have one connected. If you use kb/mouse it should show kb/mouse bindings
If you have one of those annoying 7 layers splash screens that are skippable people will also already have picked their input of choice before they see any prompts ๐
i also found that both controller and KBM are active at all times, even if it's only 1 being shown in ui
like sometimes character is stuck walking in 1 direction and it takes a while to realize it's the controller deadzone failing, even though i never touched controller
That's kind of what you want for accessability anyway, as well as support for things like the steam controller
or you start playing and it starts violently convulsing on the table in the middle of the night waking up the entire house
Games should really have a well functioning deadzone (that's ideally configurable tho)
Yea now that ... That one never makes sense to me ... You can't just trigger rumble on a controller that literally hasn't been touched ... What if you have 8 controllers connected? ๐
I don't think rumble is in scope for LWIM tho, right?
If it was it would be leafwing-input-output-manager 
it's shocking that it's pretty big games that fuck it up too
Triple A games are just lazy console ports anyway
lAAAzy
I'm not sure LWIM should be too opinionated for example on whether gamepad or keyboard input or which key binding in general is prioritized - it might depend on the game. It could very well be that a tutorial wants to show a certain keybinding as it's the easiest for most players, while a settings screen just wants to show everything.
In my case it would be nice to just get an analyzable dump of all the inputs bound to a certain action, so I can make my own choices as to how they are shown on screen.
Well yea, there should probably be both a plain dump of inputs and some logic to pick what to show. There's also plenty of cases where you can show all the bound inputs, rather than only fitting one
Is there a migration guide between 14 and 15? I'm getting the trait bound bevy::prelude::KeyCode: leafwing_input_manager::user_input::Buttonlike is not satisfied [E0277] but my code looks the same as in examples. Can't spot the difference.
That should work just fine ๐ค
Do you have two different versions of Bevy in your tree?
No but i have two different versions of leafwing-input-manager. Thanks for pointing out to the problem.
Ha, I'm encountering that too tonight: I need to actually work on leafwing_abilities again...
How much will y'all hate me if I add a Display trait bound to UserInput in a minor version
Technically semver incompatible but I really don't think that there's many users manually implementing this yet
And it would give us a start on the "how do I actually display a key binding menu" problem
I'm not totally sure it's possible: Bevy's winit types may not implement it
So I may be stuck adding an optional method to the trait
This would get pretty ugly when trying to map icons probably but it's decent for a PoC keybinding menu at least ๐ค
I'm not sure that strings are really that bad for icons ๐ค
You end up needing to map them to file paths ultimately
i was thinking about it actually, I have a very basic inventory system and though of how to debug it visually
I was considering a Debug equivalent for UI-stuff, but it'd have to be immediate and rely on gizmos
and you can have a Display equivalent for spawning a permament UI element that shows that button
once new UI is somewhat stable Bevy should probably introduce traits for visual debugging
is there a solution in leafwing input manager for letting you hold a button down to perform an action on a cooldown?
i.e. if I hold space, then every 500ms it triggers another jump action, maybe via just_pressed or something
note that you can still manually press space at an interval shorter than 500ms, but it's just that if you keep it held down, you will repeatedly "press" it every 500ms
autorepeat delay / rate would be neat
I think that this is probably best handled in game code
idk I think this would be a useful feature at the input layer
since game logic usually just uses pressed, just_pressed, and it's inconvenient to have to keep track of a bunch of timers as well
you could have the timer/autorepeat logic in LIM, then use just_pressed to listen for the autorepeats
it would, but once you start adding that there will be more stuff that will eventually creep in like charges and mana cost
no, not at all
this is better described as an autorepeat key delay
not an actual game-level cooldown system
you should still handle e.g. ability cooldowns at your gameplay layer
it's similar to what minecraft does with its left and right clicks
where you can click as fast as you want and it'll break a block each time you left click, but you can also hold it down and break the block in front of you every 200ms
yeah, or consumables that you don't want to accidentally use twice in a row but can configure it to be any delay from user side
not sure it would work for this use case, if you mean [pressed, unpressed, pressed] within 3 updates, then that would still count as 2 just_pressed
but it could let you e.g. consume 10 items quickly if you just hold down the use key, instead of the player having to spam press
input already tracks duration
for other use cases you might want to make duration threshold to cancel the action or release automatically
-# unity input system can do that, not sure about LWIM
and re-use is just another step on top of that
no, even better
the + button
when you press and hold the + button, you usually want it to keep adding and ramp up over time
that's a good use case as well
not sure if that should be in LWIM though, i think mod_picking had something like it? or was it in example
if you have two configurable properties, an initial resend delay, then a resend interval
like you have on a regular keyboard, where you can press a key, keep it held, then after like 500ms it'll start repeatedly entering the same key
and my thinking of auto-resend is just a special case of that where the initial delay is 0ms
yeah. i'm not sure how often you'd actually need it though
I want to use this for interactions and consuming items in an inventory
so that players wouldn't have to spam click to use up a lot of items
i'm sure there are valid use cases for this
i guess it could also be useful for feedback, limiting the amount of sounds or ui animations that play
it's still just input, just that you don't have to worry about handling the case where spamming the key(s) causes a noise bomb and abruptly flashing ui if you have that
Sounds useful, but I'd maybe differentiate it from just_pressed and keep just_pressed as only the very first press event and have some just_pressed_repeat (naming tbd) for when you want auto-repeating behavior
i think it's something you'd want to leave up to players, so it'd be bad if hardcoded
but yeah in some cases it just wouldn't make sense, like for aim/movement
i wouldn't expect autorepeat for an axislike, and i'd expect it to be something you have to opt in to anyways
for sure, I don't expect it to be automatically enabled, but this sounds like a useful input-level feature that is opt-in
Not exactly. It delays how often the action is repeated when held, but if you, say, point into the sky, hold down left click, then point at a block, it'll immediately break the block and then start the timer. I know that feels like a nitpick, but to me it's very indicative of how tightly coupled the behavior is with game logic. I feel like that's far out of scope for lwim (which I see as an action abstraction with an input manager tacked on) but could be a crate
wth
is inputkind no longer a thing?
heeeeeeeeelp
i'm trying to move to bevy 0.14 for funny reasons
uouuurgghhhee!!! i'm trying to just get my stuff set up and ignore the weird const thing i have for the moment
but i cant even do that because .insert returns a &mut for some reason that i cant use? and dereffing wont work
sorry if this should be in a help thread or something
whyyy does this work in the examples but not hereeee
i just want my damn code to compile PLEASE
is the examples code old and outdated or something?? i think i remember seeing something about that
im going to tear out functionality for looking for the time being
check if you have 2 versions of lwim in your .lock
i had this at some point and it breaks everything
ah
The examples are too new, just like what happens with Bevy
The fancy derive didn't make the initial release
Exactly the same as the manual impl
i wasnt aware there was a migration guide for this crate, could you send it to me?
There are small notes in https://github.com/Leafwing-Studios/leafwing-input-manager/blob/main/RELEASES.md
Note that 0.15.1 is still unreleased
Hi! I trying to migrate to 0.15, but faced an issue.
Looks like InputMap::insert have impl Buttonlike in the signature, which means that I have to know the type I insert.
But in games you rarely have hardcoded logic like input_map.insert(MyAction::A, [KeyCode::ShiftLeft]);, you usually load settings from the configuration file.
Previosly I just ser/de InputKind enum. But how can I pass dynamically deserialized input now? ๐ค
Hi there, i would like to have my action to contain the mouse position in world coordinates so it can be sent over network instead of the clients relative mouse position since that is not really useful, is there a way to hook into the dualaxis data or make a custom one?
its not really abt converting them, more so abt how to hook into the data itself, im not sure if/how i could modify that in an optimal way
hm wdym?
its just two floats, whats the issue?
well yea a dualaxis action is just two floats
mouse x and y

even then it should be acceptable, it shouldnt be too much of an issue
havent looked too much into how lightyear sends inputs but its prob as efficiently as possible so two floats shouldnt be that costly
its not like there is an alternative to sending them over anyways soo
then i wouldnt have the benefit of things like redundancy
actually isnt actionstate just a regular component? So maybe i could just query for it mutably, modify the underlying data
so basically the goal is to just
- user puts mouse somewhere
- convert the mouse coords to game coords
- send over said coords through inputs
- let the server use said coords in some way, in this case to take aim
adding what?
Well because it is an input and lightyear has redundancy for inputs by default which is useful for packetloss and such
it would be pretty weird to have mouse position split from all other inputs including stuff like mouse wheel
uhhh i was thinking from server side, but i guess for client/host it makes sense
Either way, this should work no?
ill just have no processor
it would just need to run before the input buffering

i guess ill try that
What is the idiomatic way to get the current mouse position with leafwing? Do I still have to use window.cursor_position() ?
@karmic monolith thinking about this.
We have 2 separate concepts:
- Actions that can be checked for
just_pressed,pressedetc. - Inputs that update actions state.
I think that old design with enum for inputs was okay.
If user want to have some esoteric input, they can create its own enum and just update actions state on their own, just provide the ability to do so.
With enums we have no issues with serialization (very important!), no small allocations on heap and unified interface to assign inputs to an action.
Yes
@karmic monolith sorry for bothering, but what do you think about it?
I've been very pleased with how the refactor went overall: splitting the input types apart was the right call
The enum was really bloated and took to a huge amount of space due to the need to model chords
But I do need to get a realistic working example up for input key bindings, including serialization
Wasn't there a crate to provide serialization/deserialization for such Box<dyn X> usecases?
Yeah, @candid vigil has a nice solution in place already
Quite complex
But functional
Other than that I think the small allocs aren't a huge problem (tho maybe it would be more efficient if more of them were combined), and the unified interface for assigning inputs we had in the past was deceptive
Assigning an axis to a button action never should've been a thing ๐
But you can't insert the Box back, all InputMap methods accept concrete type, not a fat pointer.
A Multi-Map that allows you to map actions to multiple UserInputss, whether they are Buttonlike, Axislike or DualAxislike.
Maybe we could have an enum between 4 traits?
And accept this enum everywhere.
It does internally do self.insert_boxed(action, Box::new(button));, so I don't think it would be hard to make a function that takes a Box
Yep, it's just not exposed
But exposing insert_boxed, insert_axis_boxed and insert_dual_axis_boxed isn't nice ๐
So maybe this would work?
I.e.
enum ActionInput {
Buttonlike(Box<dyn ButtonLike>),
Axislike(Box<dyn Axislike>),
DualAxisLike(Box<dyn DualAxisLike>),
}
Yea, it would be better if the other function works on non-concrete types. impl T not taking Box<dyn T> is always one of those things that catches you by surprise in APIs where that makes sense to do
Can't you assign W and a gamepad stick to go forward? ๐ค
Yes, but not by itself, it needs to be part of a virtual axis made up of 4 buttons
Because a gamepad stick doesn't have a binary "forward"
So mapping it as 4 buttons instead of 1 dual axis would be very weird
Agree!
Maybe just make all methods accept Into<Box<dyn Trait>>?
What I also found a little bit inconsistent is that this method works only for Buttonlike:
https://docs.rs/leafwing-input-manager/latest/leafwing_input_manager/input_map/struct.InputMap.html#method.insert_one_to_many
And there are no alternatives for other traits.
A Multi-Map that allows you to map actions to multiple UserInputss, whether they are Buttonlike, Axislike or DualAxislike.
Can you make an issue please? That's easy to do
Sure!
I asked here first to make sure I wasn't missing anything.
Yep, it just got overlooked in the refactoring ๐
or maybe impl Buttonlike for Box<dyn Buttonlike>
Wouldn't you end up with things like Box<Box<Box<Box<Box<dyn ButtonLike>>>>>?
impl A for Box<dyn A> compiles for me in rust playground
i think you only end up with that type if you create it yourself
It will work, but you will box a box
oh you mean in the implementation it will get boxed
Internals do Box::new
Buttonlike could expose a method that creates the Box<dyn Buttonlike> to avoid that :p
not pretty though
Yea, and then if you serialize it and deserialize and re-insert it again it becomes 3 levels of box, then 4, etc
trait Buttonlike { fn into_boxed_buttonlike(self) -> Box<dyn Buttonlike> { Box::new(self) } }
impl Buttonlike for Box<dyn Buttonlike> { fn into_boxed_buttonlike(self) -> Box<dyn Buttonlike> { self } }
ig at that point.. it's just impl Into<Box<dyn Buttonlike>> with extra steps :)
Ser/de is bigger issue, I don't like any of the proposed solutions ๐
Maybe we could just have better enums. Like keep all insert, insert_axislike, etc., but use enums instead of boxes.
Like make it enum dispatch but still keep them in some form where chord buttonlikes don't explode the enum dispatch?
Yep
Wait but if serialization/deserialization doesn't already work, what does LWIM use serde_flexitos for? ๐ค
Yeah, we should have a functional serde solution already
It does need to be fully tested and taught though
LWIM development be like
how do you even deserialize trait objects
serde_flexitos apparantly 
Afaict it uses some type registry and probably a lot of cursed unsafe stuff 
I was super burnt out on the refactor ๐
Ah, I missed it. I also never used it ๐
But we still need Into<Box<dyn Trait>> in order to make it usable.
Yea it's understandable, I have this with lots of refactors too ... Can't wait till I'm done with fixing the networking rework of my game, I've been working on this for months now ๐คฌ
Yeah, totally understand you both ๐
Previously, there was only one UserInput trait and I added Serde support to its boxed objects
However, Alice split it into inputlike traits, which are not currently compatible with Serde I think, since the deserializer registry isn't updated ๐ค
Ha, that's what I get for not writing an example...
I'm surprised LWIM even works considering the state of the examples 
I actually haven't hit any bugs, only the bad UX of the macro being bad
typetag crate works in all environments except Wasm
wasm strikes again 
The reason for this is that when serializing trait objects with Serde, you need a way to identify the exact type being serialized
Typetag solves this by using inventory to create a registry of all possible implementations and placing it before the main function
However, wasm_init can only be used once, preventing typetag's use in this environment
LWIM currently uses serde_flexitos, which manually creates a registry but requires pre-creation and subsequent calls during deserialization
So kind of like bevy_reflect, which requires you to register things before the app does stuff with it?
yeah
So in the docs for the UserInput trait, I added this
๐ค but now we need register_buttonlike_input and friends, because InputMap stores HashMap<Action, Vec<Box<dyn Buttonlike>>> rather than UserInput objects
I think we can do this because we already have https://docs.rs/leafwing-input-manager/latest/leafwing_input_manager/user_input/enum.UserInputWrapper.html
A wrapper type to get around the lack of trait upcasting coercion.
and add fn insert(&mut self, action: A, input: impl Into<UserInputWrapper>) to InputMap
๐ค It's an uncovered type
Perhaps I can add a new UserInput derive
the first attribute could be inputlike(...) for example #[inputlike(Button)], which implements UserInput::kind() -> InputControlKind::Button
the second attr could beclash_with(...), for example, clash_with(Simple(self)) for generating BasicInputs::Simple(self), clash_with(Composite(self.negative, self.positive)) for VirtualAxis, and clash_with(Chord(self.buttons)) for ButtonlikeChord
๐ค but I think we could split to another trait, or even refactor how input clashing check works
Weird. Compiler cannot get information of trait impls from another module?
Buttonlike is already implemented for GamepadButtonType in user_input/gamepad module
@candid vigil have you considered using enum dispatch instead?
Like keep Buttonlike, Axislike, but make them enums as before.
Actually, I think it's fine too
InputProcessors were originally trait objects, but we changed them to enum with a Custom(Box<dyn CustomInputProcessor>) variant
Reflection and serde for trait objects can be quite troublesome
Yes, I think the direction with enum dispatch worth exploring as well