mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-27 02:01:42 +00:00
[commands] Extract common trigger binding logic (#7550)
This makes the logic clearer in the actual binding methods and will hopefully make it less annoying to make changes such as allowing control over initial edges. Also changes Java to use previous and current to match C++.
This commit is contained in:
@@ -24,6 +24,18 @@ import java.util.function.BooleanSupplier;
|
|||||||
* <p>This class is provided by the NewCommands VendorDep
|
* <p>This class is provided by the NewCommands VendorDep
|
||||||
*/
|
*/
|
||||||
public class Trigger implements BooleanSupplier {
|
public class Trigger implements BooleanSupplier {
|
||||||
|
/** Functional interface for the body of a trigger binding. */
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface BindingBody {
|
||||||
|
/**
|
||||||
|
* Executes the body of the binding.
|
||||||
|
*
|
||||||
|
* @param previous The previous state of the condition.
|
||||||
|
* @param current The current state of the condition.
|
||||||
|
*/
|
||||||
|
void run(boolean previous, boolean current);
|
||||||
|
}
|
||||||
|
|
||||||
private final BooleanSupplier m_condition;
|
private final BooleanSupplier m_condition;
|
||||||
private final EventLoop m_loop;
|
private final EventLoop m_loop;
|
||||||
|
|
||||||
@@ -49,6 +61,27 @@ public class Trigger implements BooleanSupplier {
|
|||||||
this(CommandScheduler.getInstance().getDefaultButtonLoop(), condition);
|
this(CommandScheduler.getInstance().getDefaultButtonLoop(), condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a binding to the EventLoop.
|
||||||
|
*
|
||||||
|
* @param body The body of the binding to add.
|
||||||
|
*/
|
||||||
|
private void addBinding(BindingBody body) {
|
||||||
|
m_loop.bind(
|
||||||
|
new Runnable() {
|
||||||
|
private boolean m_previous = m_condition.getAsBoolean();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
boolean current = m_condition.getAsBoolean();
|
||||||
|
|
||||||
|
body.run(m_previous, current);
|
||||||
|
|
||||||
|
m_previous = current;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the command when the condition changes.
|
* Starts the command when the condition changes.
|
||||||
*
|
*
|
||||||
@@ -57,19 +90,10 @@ public class Trigger implements BooleanSupplier {
|
|||||||
*/
|
*/
|
||||||
public Trigger onChange(Command command) {
|
public Trigger onChange(Command command) {
|
||||||
requireNonNullParam(command, "command", "onChange");
|
requireNonNullParam(command, "command", "onChange");
|
||||||
m_loop.bind(
|
addBinding(
|
||||||
new Runnable() {
|
(previous, current) -> {
|
||||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
if (previous != current) {
|
||||||
|
command.schedule();
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean pressed = m_condition.getAsBoolean();
|
|
||||||
|
|
||||||
if (m_pressedLast != pressed) {
|
|
||||||
command.schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pressedLast = pressed;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@@ -83,19 +107,10 @@ public class Trigger implements BooleanSupplier {
|
|||||||
*/
|
*/
|
||||||
public Trigger onTrue(Command command) {
|
public Trigger onTrue(Command command) {
|
||||||
requireNonNullParam(command, "command", "onTrue");
|
requireNonNullParam(command, "command", "onTrue");
|
||||||
m_loop.bind(
|
addBinding(
|
||||||
new Runnable() {
|
(previous, current) -> {
|
||||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
if (!previous && current) {
|
||||||
|
command.schedule();
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean pressed = m_condition.getAsBoolean();
|
|
||||||
|
|
||||||
if (!m_pressedLast && pressed) {
|
|
||||||
command.schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pressedLast = pressed;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@@ -109,19 +124,10 @@ public class Trigger implements BooleanSupplier {
|
|||||||
*/
|
*/
|
||||||
public Trigger onFalse(Command command) {
|
public Trigger onFalse(Command command) {
|
||||||
requireNonNullParam(command, "command", "onFalse");
|
requireNonNullParam(command, "command", "onFalse");
|
||||||
m_loop.bind(
|
addBinding(
|
||||||
new Runnable() {
|
(previous, current) -> {
|
||||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
if (previous && !current) {
|
||||||
|
command.schedule();
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean pressed = m_condition.getAsBoolean();
|
|
||||||
|
|
||||||
if (m_pressedLast && !pressed) {
|
|
||||||
command.schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pressedLast = pressed;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@@ -139,21 +145,12 @@ public class Trigger implements BooleanSupplier {
|
|||||||
*/
|
*/
|
||||||
public Trigger whileTrue(Command command) {
|
public Trigger whileTrue(Command command) {
|
||||||
requireNonNullParam(command, "command", "whileTrue");
|
requireNonNullParam(command, "command", "whileTrue");
|
||||||
m_loop.bind(
|
addBinding(
|
||||||
new Runnable() {
|
(previous, current) -> {
|
||||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
if (!previous && current) {
|
||||||
|
command.schedule();
|
||||||
@Override
|
} else if (previous && !current) {
|
||||||
public void run() {
|
command.cancel();
|
||||||
boolean pressed = m_condition.getAsBoolean();
|
|
||||||
|
|
||||||
if (!m_pressedLast && pressed) {
|
|
||||||
command.schedule();
|
|
||||||
} else if (m_pressedLast && !pressed) {
|
|
||||||
command.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pressedLast = pressed;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@@ -171,21 +168,12 @@ public class Trigger implements BooleanSupplier {
|
|||||||
*/
|
*/
|
||||||
public Trigger whileFalse(Command command) {
|
public Trigger whileFalse(Command command) {
|
||||||
requireNonNullParam(command, "command", "whileFalse");
|
requireNonNullParam(command, "command", "whileFalse");
|
||||||
m_loop.bind(
|
addBinding(
|
||||||
new Runnable() {
|
(previous, current) -> {
|
||||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
if (previous && !current) {
|
||||||
|
command.schedule();
|
||||||
@Override
|
} else if (!previous && current) {
|
||||||
public void run() {
|
command.cancel();
|
||||||
boolean pressed = m_condition.getAsBoolean();
|
|
||||||
|
|
||||||
if (m_pressedLast && !pressed) {
|
|
||||||
command.schedule();
|
|
||||||
} else if (!m_pressedLast && pressed) {
|
|
||||||
command.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pressedLast = pressed;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@@ -199,23 +187,14 @@ public class Trigger implements BooleanSupplier {
|
|||||||
*/
|
*/
|
||||||
public Trigger toggleOnTrue(Command command) {
|
public Trigger toggleOnTrue(Command command) {
|
||||||
requireNonNullParam(command, "command", "toggleOnTrue");
|
requireNonNullParam(command, "command", "toggleOnTrue");
|
||||||
m_loop.bind(
|
addBinding(
|
||||||
new Runnable() {
|
(previous, current) -> {
|
||||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
if (!previous && current) {
|
||||||
|
if (command.isScheduled()) {
|
||||||
@Override
|
command.cancel();
|
||||||
public void run() {
|
} else {
|
||||||
boolean pressed = m_condition.getAsBoolean();
|
command.schedule();
|
||||||
|
|
||||||
if (!m_pressedLast && pressed) {
|
|
||||||
if (command.isScheduled()) {
|
|
||||||
command.cancel();
|
|
||||||
} else {
|
|
||||||
command.schedule();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pressedLast = pressed;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
@@ -229,23 +208,14 @@ public class Trigger implements BooleanSupplier {
|
|||||||
*/
|
*/
|
||||||
public Trigger toggleOnFalse(Command command) {
|
public Trigger toggleOnFalse(Command command) {
|
||||||
requireNonNullParam(command, "command", "toggleOnFalse");
|
requireNonNullParam(command, "command", "toggleOnFalse");
|
||||||
m_loop.bind(
|
addBinding(
|
||||||
new Runnable() {
|
(previous, current) -> {
|
||||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
if (previous && !current) {
|
||||||
|
if (command.isScheduled()) {
|
||||||
@Override
|
command.cancel();
|
||||||
public void run() {
|
} else {
|
||||||
boolean pressed = m_condition.getAsBoolean();
|
command.schedule();
|
||||||
|
|
||||||
if (m_pressedLast && !pressed) {
|
|
||||||
if (command.isScheduled()) {
|
|
||||||
command.cancel();
|
|
||||||
} else {
|
|
||||||
command.schedule();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pressedLast = pressed;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -15,159 +15,117 @@ using namespace frc2;
|
|||||||
|
|
||||||
Trigger::Trigger(const Trigger& other) = default;
|
Trigger::Trigger(const Trigger& other) = default;
|
||||||
|
|
||||||
|
void Trigger::AddBinding(wpi::unique_function<void(bool, bool)>&& body) {
|
||||||
|
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||||
|
body = std::move(body)]() mutable {
|
||||||
|
bool current = condition();
|
||||||
|
|
||||||
|
body(previous, current);
|
||||||
|
|
||||||
|
previous = current;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Trigger Trigger::OnChange(Command* command) {
|
Trigger Trigger::OnChange(Command* command) {
|
||||||
m_loop->Bind(
|
AddBinding([command](bool previous, bool current) {
|
||||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
if (previous != current) {
|
||||||
bool current = condition();
|
command->Schedule();
|
||||||
|
}
|
||||||
if (previous != current) {
|
});
|
||||||
command->Schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::OnChange(CommandPtr&& command) {
|
Trigger Trigger::OnChange(CommandPtr&& command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||||
command = std::move(command)]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (previous != current) {
|
if (previous != current) {
|
||||||
command.Schedule();
|
command.Schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::OnTrue(Command* command) {
|
Trigger Trigger::OnTrue(Command* command) {
|
||||||
m_loop->Bind(
|
AddBinding([command](bool previous, bool current) {
|
||||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
if (!previous && current) {
|
||||||
bool current = condition();
|
command->Schedule();
|
||||||
|
}
|
||||||
if (!previous && current) {
|
});
|
||||||
command->Schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::OnTrue(CommandPtr&& command) {
|
Trigger Trigger::OnTrue(CommandPtr&& command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||||
command = std::move(command)]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (!previous && current) {
|
if (!previous && current) {
|
||||||
command.Schedule();
|
command.Schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::OnFalse(Command* command) {
|
Trigger Trigger::OnFalse(Command* command) {
|
||||||
m_loop->Bind(
|
AddBinding([command](bool previous, bool current) {
|
||||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
if (previous && !current) {
|
||||||
bool current = condition();
|
command->Schedule();
|
||||||
|
}
|
||||||
if (previous && !current) {
|
});
|
||||||
command->Schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::OnFalse(CommandPtr&& command) {
|
Trigger Trigger::OnFalse(CommandPtr&& command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||||
command = std::move(command)]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (previous && !current) {
|
if (previous && !current) {
|
||||||
command.Schedule();
|
command.Schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::WhileTrue(Command* command) {
|
Trigger Trigger::WhileTrue(Command* command) {
|
||||||
m_loop->Bind(
|
AddBinding([command](bool previous, bool current) {
|
||||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
if (!previous && current) {
|
||||||
bool current = condition();
|
command->Schedule();
|
||||||
|
} else if (previous && !current) {
|
||||||
if (!previous && current) {
|
command->Cancel();
|
||||||
command->Schedule();
|
}
|
||||||
} else if (previous && !current) {
|
});
|
||||||
command->Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::WhileTrue(CommandPtr&& command) {
|
Trigger Trigger::WhileTrue(CommandPtr&& command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||||
command = std::move(command)]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (!previous && current) {
|
if (!previous && current) {
|
||||||
command.Schedule();
|
command.Schedule();
|
||||||
} else if (previous && !current) {
|
} else if (previous && !current) {
|
||||||
command.Cancel();
|
command.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::WhileFalse(Command* command) {
|
Trigger Trigger::WhileFalse(Command* command) {
|
||||||
m_loop->Bind(
|
AddBinding([command](bool previous, bool current) {
|
||||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
if (previous && !current) {
|
||||||
bool current = condition();
|
command->Schedule();
|
||||||
|
} else if (!previous && current) {
|
||||||
if (previous && !current) {
|
command->Cancel();
|
||||||
command->Schedule();
|
}
|
||||||
} else if (!previous && current) {
|
});
|
||||||
command->Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::WhileFalse(CommandPtr&& command) {
|
Trigger Trigger::WhileFalse(CommandPtr&& command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||||
command = std::move(command)]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (!previous && current) {
|
if (!previous && current) {
|
||||||
command.Schedule();
|
command.Schedule();
|
||||||
} else if (previous && !current) {
|
} else if (previous && !current) {
|
||||||
command.Cancel();
|
command.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::ToggleOnTrue(Command* command) {
|
Trigger Trigger::ToggleOnTrue(Command* command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command](bool previous, bool current) {
|
||||||
command = command]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (!previous && current) {
|
if (!previous && current) {
|
||||||
if (command->IsScheduled()) {
|
if (command->IsScheduled()) {
|
||||||
command->Cancel();
|
command->Cancel();
|
||||||
@@ -175,17 +133,12 @@ Trigger Trigger::ToggleOnTrue(Command* command) {
|
|||||||
command->Schedule();
|
command->Schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::ToggleOnTrue(CommandPtr&& command) {
|
Trigger Trigger::ToggleOnTrue(CommandPtr&& command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||||
command = std::move(command)]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (!previous && current) {
|
if (!previous && current) {
|
||||||
if (command.IsScheduled()) {
|
if (command.IsScheduled()) {
|
||||||
command.Cancel();
|
command.Cancel();
|
||||||
@@ -193,17 +146,12 @@ Trigger Trigger::ToggleOnTrue(CommandPtr&& command) {
|
|||||||
command.Schedule();
|
command.Schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::ToggleOnFalse(Command* command) {
|
Trigger Trigger::ToggleOnFalse(Command* command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command](bool previous, bool current) {
|
||||||
command = command]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (previous && !current) {
|
if (previous && !current) {
|
||||||
if (command->IsScheduled()) {
|
if (command->IsScheduled()) {
|
||||||
command->Cancel();
|
command->Cancel();
|
||||||
@@ -211,17 +159,12 @@ Trigger Trigger::ToggleOnFalse(Command* command) {
|
|||||||
command->Schedule();
|
command->Schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trigger Trigger::ToggleOnFalse(CommandPtr&& command) {
|
Trigger Trigger::ToggleOnFalse(CommandPtr&& command) {
|
||||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||||
command = std::move(command)]() mutable {
|
|
||||||
bool current = condition();
|
|
||||||
|
|
||||||
if (previous && !current) {
|
if (previous && !current) {
|
||||||
if (command.IsScheduled()) {
|
if (command.IsScheduled()) {
|
||||||
command.Cancel();
|
command.Cancel();
|
||||||
@@ -229,8 +172,6 @@ Trigger Trigger::ToggleOnFalse(CommandPtr&& command) {
|
|||||||
command.Schedule();
|
command.Schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = current;
|
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <frc/event/EventLoop.h>
|
#include <frc/event/EventLoop.h>
|
||||||
#include <frc/filter/Debouncer.h>
|
#include <frc/filter/Debouncer.h>
|
||||||
#include <units/time.h>
|
#include <units/time.h>
|
||||||
|
#include <wpi/FunctionExtras.h>
|
||||||
|
|
||||||
#include "frc2/command/Command.h"
|
#include "frc2/command/Command.h"
|
||||||
#include "frc2/command/CommandScheduler.h"
|
#include "frc2/command/CommandScheduler.h"
|
||||||
@@ -291,6 +292,13 @@ class Trigger {
|
|||||||
bool Get() const;
|
bool Get() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* Adds a binding to the EventLoop.
|
||||||
|
*
|
||||||
|
* @param body The body of the binding to add.
|
||||||
|
*/
|
||||||
|
void AddBinding(wpi::unique_function<void(bool, bool)>&& body);
|
||||||
|
|
||||||
frc::EventLoop* m_loop;
|
frc::EventLoop* m_loop;
|
||||||
std::function<bool()> m_condition;
|
std::function<bool()> m_condition;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user