From 70f36cce7e97d9be00a8a9b552a0e549f2ed13ad Mon Sep 17 00:00:00 2001 From: Joseph Eng <91924258+KangarooKoala@users.noreply.github.com> Date: Sat, 14 Dec 2024 23:13:41 -0800 Subject: [PATCH] [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++. --- .../wpilibj2/command/button/Trigger.java | 168 +++++++----------- .../cpp/frc2/command/button/Trigger.cpp | 155 +++++----------- .../include/frc2/command/button/Trigger.h | 8 + 3 files changed, 125 insertions(+), 206 deletions(-) diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java index d7b1dd08937..8dc3ae52b3d 100644 --- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java +++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java @@ -24,6 +24,18 @@ *

This class is provided by the NewCommands VendorDep */ 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 EventLoop m_loop; @@ -50,26 +62,38 @@ public Trigger(BooleanSupplier condition) { } /** - * Starts the command when the condition changes. + * Adds a binding to the EventLoop. * - * @param command the command to start - * @return this trigger, so calls can be chained + * @param body The body of the binding to add. */ - public Trigger onChange(Command command) { - requireNonNullParam(command, "command", "onChange"); + private void addBinding(BindingBody body) { m_loop.bind( new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); + private boolean m_previous = m_condition.getAsBoolean(); @Override public void run() { - boolean pressed = m_condition.getAsBoolean(); + boolean current = m_condition.getAsBoolean(); - if (m_pressedLast != pressed) { - command.schedule(); - } + body.run(m_previous, current); - m_pressedLast = pressed; + m_previous = current; + } + }); + } + + /** + * Starts the command when the condition changes. + * + * @param command the command to start + * @return this trigger, so calls can be chained + */ + public Trigger onChange(Command command) { + requireNonNullParam(command, "command", "onChange"); + addBinding( + (previous, current) -> { + if (previous != current) { + command.schedule(); } }); return this; @@ -83,19 +107,10 @@ public void run() { */ public Trigger onTrue(Command command) { requireNonNullParam(command, "command", "onTrue"); - m_loop.bind( - new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); - - @Override - public void run() { - boolean pressed = m_condition.getAsBoolean(); - - if (!m_pressedLast && pressed) { - command.schedule(); - } - - m_pressedLast = pressed; + addBinding( + (previous, current) -> { + if (!previous && current) { + command.schedule(); } }); return this; @@ -109,19 +124,10 @@ public void run() { */ public Trigger onFalse(Command command) { requireNonNullParam(command, "command", "onFalse"); - m_loop.bind( - new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); - - @Override - public void run() { - boolean pressed = m_condition.getAsBoolean(); - - if (m_pressedLast && !pressed) { - command.schedule(); - } - - m_pressedLast = pressed; + addBinding( + (previous, current) -> { + if (previous && !current) { + command.schedule(); } }); return this; @@ -139,21 +145,12 @@ public void run() { */ public Trigger whileTrue(Command command) { requireNonNullParam(command, "command", "whileTrue"); - m_loop.bind( - new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); - - @Override - public void run() { - boolean pressed = m_condition.getAsBoolean(); - - if (!m_pressedLast && pressed) { - command.schedule(); - } else if (m_pressedLast && !pressed) { - command.cancel(); - } - - m_pressedLast = pressed; + addBinding( + (previous, current) -> { + if (!previous && current) { + command.schedule(); + } else if (previous && !current) { + command.cancel(); } }); return this; @@ -171,21 +168,12 @@ public void run() { */ public Trigger whileFalse(Command command) { requireNonNullParam(command, "command", "whileFalse"); - m_loop.bind( - new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); - - @Override - public void run() { - boolean pressed = m_condition.getAsBoolean(); - - if (m_pressedLast && !pressed) { - command.schedule(); - } else if (!m_pressedLast && pressed) { - command.cancel(); - } - - m_pressedLast = pressed; + addBinding( + (previous, current) -> { + if (previous && !current) { + command.schedule(); + } else if (!previous && current) { + command.cancel(); } }); return this; @@ -199,23 +187,14 @@ public void run() { */ public Trigger toggleOnTrue(Command command) { requireNonNullParam(command, "command", "toggleOnTrue"); - m_loop.bind( - new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); - - @Override - public void run() { - boolean pressed = m_condition.getAsBoolean(); - - if (!m_pressedLast && pressed) { - if (command.isScheduled()) { - command.cancel(); - } else { - command.schedule(); - } + addBinding( + (previous, current) -> { + if (!previous && current) { + if (command.isScheduled()) { + command.cancel(); + } else { + command.schedule(); } - - m_pressedLast = pressed; } }); return this; @@ -229,23 +208,14 @@ public void run() { */ public Trigger toggleOnFalse(Command command) { requireNonNullParam(command, "command", "toggleOnFalse"); - m_loop.bind( - new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); - - @Override - public void run() { - boolean pressed = m_condition.getAsBoolean(); - - if (m_pressedLast && !pressed) { - if (command.isScheduled()) { - command.cancel(); - } else { - command.schedule(); - } + addBinding( + (previous, current) -> { + if (previous && !current) { + if (command.isScheduled()) { + command.cancel(); + } else { + command.schedule(); } - - m_pressedLast = pressed; } }); return this; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp index a3b02d18f3a..00f179da084 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp @@ -15,159 +15,117 @@ using namespace frc2; Trigger::Trigger(const Trigger& other) = default; -Trigger Trigger::OnChange(Command* command) { - m_loop->Bind( - [condition = m_condition, previous = m_condition(), command]() mutable { - bool current = condition(); +void Trigger::AddBinding(wpi::unique_function&& body) { + m_loop->Bind([condition = m_condition, previous = m_condition(), + body = std::move(body)]() mutable { + bool current = condition(); - if (previous != current) { - command->Schedule(); - } + body(previous, current); + + previous = current; + }); +} - previous = current; - }); +Trigger Trigger::OnChange(Command* command) { + AddBinding([command](bool previous, bool current) { + if (previous != current) { + command->Schedule(); + } + }); return *this; } Trigger Trigger::OnChange(CommandPtr&& command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = std::move(command)]() mutable { - bool current = condition(); - + AddBinding([command = std::move(command)](bool previous, bool current) { if (previous != current) { command.Schedule(); } - - previous = current; }); return *this; } Trigger Trigger::OnTrue(Command* command) { - m_loop->Bind( - [condition = m_condition, previous = m_condition(), command]() mutable { - bool current = condition(); - - if (!previous && current) { - command->Schedule(); - } - - previous = current; - }); + AddBinding([command](bool previous, bool current) { + if (!previous && current) { + command->Schedule(); + } + }); return *this; } Trigger Trigger::OnTrue(CommandPtr&& command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = std::move(command)]() mutable { - bool current = condition(); - + AddBinding([command = std::move(command)](bool previous, bool current) { if (!previous && current) { command.Schedule(); } - - previous = current; }); return *this; } Trigger Trigger::OnFalse(Command* command) { - m_loop->Bind( - [condition = m_condition, previous = m_condition(), command]() mutable { - bool current = condition(); - - if (previous && !current) { - command->Schedule(); - } - - previous = current; - }); + AddBinding([command](bool previous, bool current) { + if (previous && !current) { + command->Schedule(); + } + }); return *this; } Trigger Trigger::OnFalse(CommandPtr&& command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = std::move(command)]() mutable { - bool current = condition(); - + AddBinding([command = std::move(command)](bool previous, bool current) { if (previous && !current) { command.Schedule(); } - - previous = current; }); return *this; } Trigger Trigger::WhileTrue(Command* command) { - m_loop->Bind( - [condition = m_condition, previous = m_condition(), command]() mutable { - bool current = condition(); - - if (!previous && current) { - command->Schedule(); - } else if (previous && !current) { - command->Cancel(); - } - - previous = current; - }); + AddBinding([command](bool previous, bool current) { + if (!previous && current) { + command->Schedule(); + } else if (previous && !current) { + command->Cancel(); + } + }); return *this; } Trigger Trigger::WhileTrue(CommandPtr&& command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = std::move(command)]() mutable { - bool current = condition(); - + AddBinding([command = std::move(command)](bool previous, bool current) { if (!previous && current) { command.Schedule(); } else if (previous && !current) { command.Cancel(); } - - previous = current; }); return *this; } Trigger Trigger::WhileFalse(Command* command) { - m_loop->Bind( - [condition = m_condition, previous = m_condition(), command]() mutable { - bool current = condition(); - - if (previous && !current) { - command->Schedule(); - } else if (!previous && current) { - command->Cancel(); - } - - previous = current; - }); + AddBinding([command](bool previous, bool current) { + if (previous && !current) { + command->Schedule(); + } else if (!previous && current) { + command->Cancel(); + } + }); return *this; } Trigger Trigger::WhileFalse(CommandPtr&& command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = std::move(command)]() mutable { - bool current = condition(); - + AddBinding([command = std::move(command)](bool previous, bool current) { if (!previous && current) { command.Schedule(); } else if (previous && !current) { command.Cancel(); } - - previous = current; }); return *this; } Trigger Trigger::ToggleOnTrue(Command* command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = command]() mutable { - bool current = condition(); - + AddBinding([command](bool previous, bool current) { if (!previous && current) { if (command->IsScheduled()) { command->Cancel(); @@ -175,17 +133,12 @@ Trigger Trigger::ToggleOnTrue(Command* command) { command->Schedule(); } } - - previous = current; }); return *this; } Trigger Trigger::ToggleOnTrue(CommandPtr&& command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = std::move(command)]() mutable { - bool current = condition(); - + AddBinding([command = std::move(command)](bool previous, bool current) { if (!previous && current) { if (command.IsScheduled()) { command.Cancel(); @@ -193,17 +146,12 @@ Trigger Trigger::ToggleOnTrue(CommandPtr&& command) { command.Schedule(); } } - - previous = current; }); return *this; } Trigger Trigger::ToggleOnFalse(Command* command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = command]() mutable { - bool current = condition(); - + AddBinding([command](bool previous, bool current) { if (previous && !current) { if (command->IsScheduled()) { command->Cancel(); @@ -211,17 +159,12 @@ Trigger Trigger::ToggleOnFalse(Command* command) { command->Schedule(); } } - - previous = current; }); return *this; } Trigger Trigger::ToggleOnFalse(CommandPtr&& command) { - m_loop->Bind([condition = m_condition, previous = m_condition(), - command = std::move(command)]() mutable { - bool current = condition(); - + AddBinding([command = std::move(command)](bool previous, bool current) { if (previous && !current) { if (command.IsScheduled()) { command.Cancel(); @@ -229,8 +172,6 @@ Trigger Trigger::ToggleOnFalse(CommandPtr&& command) { command.Schedule(); } } - - previous = current; }); return *this; } diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h index a2382631334..9e86b1b7004 100644 --- a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h +++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "frc2/command/Command.h" #include "frc2/command/CommandScheduler.h" @@ -291,6 +292,13 @@ class Trigger { bool Get() const; private: + /** + * Adds a binding to the EventLoop. + * + * @param body The body of the binding to add. + */ + void AddBinding(wpi::unique_function&& body); + frc::EventLoop* m_loop; std::function m_condition; };