001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */ 003/* Open Source Software - may be modified and shared by FRC teams. The code */ 004/* must be accompanied by the FIRST BSD license file in the root directory of */ 005/* the project. */ 006/*----------------------------------------------------------------------------*/ 007 008package edu.wpi.first.wpilibj.buttons; 009 010import edu.wpi.first.wpilibj.Sendable; 011import edu.wpi.first.wpilibj.command.Command; 012import edu.wpi.first.wpilibj.command.Scheduler; 013import edu.wpi.first.wpilibj.tables.ITable; 014 015/** 016 * This class provides an easy way to link commands to inputs. 017 * 018 * <p>It is very easy to link a button to a command. For instance, you could link the trigger 019 * button of a joystick to a "score" command. 020 * 021 * <p>It is encouraged that teams write a subclass of Trigger if they want to have something unusual 022 * (for instance, if they want to react to the user holding a button while the robot is reading a 023 * certain sensor input). For this, they only have to write the {@link Trigger#get()} method to get 024 * the full functionality of the Trigger class. 025 */ 026public abstract class Trigger implements Sendable { 027 028 /** 029 * Returns whether or not the trigger is active. 030 * 031 * <p>This method will be called repeatedly a command is linked to the Trigger. 032 * 033 * @return whether or not the trigger condition is active. 034 */ 035 public abstract boolean get(); 036 037 /** 038 * Returns whether get() return true or the internal table for SmartDashboard use is pressed. 039 * 040 * @return whether get() return true or the internal table for SmartDashboard use is pressed. 041 */ 042 @SuppressWarnings("PMD.UselessParentheses") 043 private boolean grab() { 044 return get() || (m_table != null && m_table.getBoolean("pressed", false)); 045 046 } 047 048 /** 049 * Starts the given command whenever the trigger just becomes active. 050 * 051 * @param command the command to start 052 */ 053 public void whenActive(final Command command) { 054 new ButtonScheduler() { 055 056 private boolean m_pressedLast = grab(); 057 058 @Override 059 public void execute() { 060 if (grab()) { 061 if (!m_pressedLast) { 062 m_pressedLast = true; 063 command.start(); 064 } 065 } else { 066 m_pressedLast = false; 067 } 068 } 069 }.start(); 070 } 071 072 /** 073 * Constantly starts the given command while the button is held. 074 * 075 * {@link Command#start()} will be called repeatedly while the trigger is active, and will be 076 * canceled when the trigger becomes inactive. 077 * 078 * @param command the command to start 079 */ 080 public void whileActive(final Command command) { 081 new ButtonScheduler() { 082 083 private boolean m_pressedLast = grab(); 084 085 @Override 086 public void execute() { 087 if (grab()) { 088 m_pressedLast = true; 089 command.start(); 090 } else { 091 if (m_pressedLast) { 092 m_pressedLast = false; 093 command.cancel(); 094 } 095 } 096 } 097 }.start(); 098 } 099 100 /** 101 * Starts the command when the trigger becomes inactive. 102 * 103 * @param command the command to start 104 */ 105 public void whenInactive(final Command command) { 106 new ButtonScheduler() { 107 108 private boolean m_pressedLast = grab(); 109 110 @Override 111 public void execute() { 112 if (grab()) { 113 m_pressedLast = true; 114 } else { 115 if (m_pressedLast) { 116 m_pressedLast = false; 117 command.start(); 118 } 119 } 120 } 121 }.start(); 122 } 123 124 /** 125 * Toggles a command when the trigger becomes active. 126 * 127 * @param command the command to toggle 128 */ 129 public void toggleWhenActive(final Command command) { 130 new ButtonScheduler() { 131 132 private boolean m_pressedLast = grab(); 133 134 @Override 135 public void execute() { 136 if (grab()) { 137 if (!m_pressedLast) { 138 m_pressedLast = true; 139 if (command.isRunning()) { 140 command.cancel(); 141 } else { 142 command.start(); 143 } 144 } 145 } else { 146 m_pressedLast = false; 147 } 148 } 149 }.start(); 150 } 151 152 /** 153 * Cancels a command when the trigger becomes active. 154 * 155 * @param command the command to cancel 156 */ 157 public void cancelWhenActive(final Command command) { 158 new ButtonScheduler() { 159 160 private boolean m_pressedLast = grab(); 161 162 @Override 163 public void execute() { 164 if (grab()) { 165 if (!m_pressedLast) { 166 m_pressedLast = true; 167 command.cancel(); 168 } 169 } else { 170 m_pressedLast = false; 171 } 172 } 173 }.start(); 174 } 175 176 /** 177 * An internal class of {@link Trigger}. The user should ignore this, it is only public to 178 * interface between packages. 179 */ 180 public abstract class ButtonScheduler { 181 public abstract void execute(); 182 183 protected void start() { 184 Scheduler.getInstance().addButton(this); 185 } 186 } 187 188 /** 189 * These methods continue to return the "Button" SmartDashboard type until we decided to create a 190 * Trigger widget type for the dashboard. 191 */ 192 @Override 193 public String getSmartDashboardType() { 194 return "Button"; 195 } 196 197 private ITable m_table; 198 199 @Override 200 public void initTable(ITable table) { 201 m_table = table; 202 if (table != null) { 203 table.putBoolean("pressed", get()); 204 } 205 } 206 207 @Override 208 public ITable getTable() { 209 return m_table; 210 } 211}