001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj;
006
007import edu.wpi.first.hal.FRCNetComm.tResourceType;
008import edu.wpi.first.hal.HAL;
009import edu.wpi.first.wpilibj.event.BooleanEvent;
010import edu.wpi.first.wpilibj.event.EventLoop;
011
012/**
013 * Handle input from Xbox 360 or Xbox One controllers connected to the Driver Station.
014 *
015 * <p>This class handles Xbox input that comes from the Driver Station. Each time a value is
016 * requested the most recent value is returned. There is a single class instance for each controller
017 * and the mapping of ports to hardware buttons depends on the code in the Driver Station.
018 */
019public class XboxController extends GenericHID {
020  /** Represents a digital button on an XboxController. */
021  public enum Button {
022    kLeftBumper(5),
023    kRightBumper(6),
024    kLeftStick(9),
025    kRightStick(10),
026    kA(1),
027    kB(2),
028    kX(3),
029    kY(4),
030    kBack(7),
031    kStart(8);
032
033    public final int value;
034
035    Button(int value) {
036      this.value = value;
037    }
038
039    /**
040     * Get the human-friendly name of the button, matching the relevant methods. This is done by
041     * stripping the leading `k`, and if not a Bumper button append `Button`.
042     *
043     * <p>Primarily used for automated unit tests.
044     *
045     * @return the human-friendly name of the button.
046     */
047    @Override
048    public String toString() {
049      var name = this.name().substring(1); // Remove leading `k`
050      if (name.endsWith("Bumper")) {
051        return name;
052      }
053      return name + "Button";
054    }
055  }
056
057  /** Represents an axis on an XboxController. */
058  public enum Axis {
059    kLeftX(0),
060    kRightX(4),
061    kLeftY(1),
062    kRightY(5),
063    kLeftTrigger(2),
064    kRightTrigger(3);
065
066    public final int value;
067
068    Axis(int value) {
069      this.value = value;
070    }
071
072    /**
073     * Get the human-friendly name of the axis, matching the relevant methods. This is done by
074     * stripping the leading `k`, and if a trigger axis append `Axis`.
075     *
076     * <p>Primarily used for automated unit tests.
077     *
078     * @return the human-friendly name of the axis.
079     */
080    @Override
081    public String toString() {
082      var name = this.name().substring(1); // Remove leading `k`
083      if (name.endsWith("Trigger")) {
084        return name + "Axis";
085      }
086      return name;
087    }
088  }
089
090  /**
091   * Construct an instance of a controller.
092   *
093   * @param port The port index on the Driver Station that the controller is plugged into.
094   */
095  public XboxController(final int port) {
096    super(port);
097
098    HAL.report(tResourceType.kResourceType_XboxController, port + 1);
099  }
100
101  /**
102   * Get the X axis value of left side of the controller.
103   *
104   * @return The axis value.
105   */
106  public double getLeftX() {
107    return getRawAxis(Axis.kLeftX.value);
108  }
109
110  /**
111   * Get the X axis value of right side of the controller.
112   *
113   * @return The axis value.
114   */
115  public double getRightX() {
116    return getRawAxis(Axis.kRightX.value);
117  }
118
119  /**
120   * Get the Y axis value of left side of the controller.
121   *
122   * @return The axis value.
123   */
124  public double getLeftY() {
125    return getRawAxis(Axis.kLeftY.value);
126  }
127
128  /**
129   * Get the Y axis value of right side of the controller.
130   *
131   * @return The axis value.
132   */
133  public double getRightY() {
134    return getRawAxis(Axis.kRightY.value);
135  }
136
137  /**
138   * Get the left trigger (LT) axis value of the controller. Note that this axis is bound to the
139   * range of [0, 1] as opposed to the usual [-1, 1].
140   *
141   * @return The axis value.
142   */
143  public double getLeftTriggerAxis() {
144    return getRawAxis(Axis.kLeftTrigger.value);
145  }
146
147  /**
148   * Get the right trigger (RT) axis value of the controller. Note that this axis is bound to the
149   * range of [0, 1] as opposed to the usual [-1, 1].
150   *
151   * @return The axis value.
152   */
153  public double getRightTriggerAxis() {
154    return getRawAxis(Axis.kRightTrigger.value);
155  }
156
157  /**
158   * Read the value of the left bumper (LB) button on the controller.
159   *
160   * @return The state of the button.
161   */
162  public boolean getLeftBumper() {
163    return getRawButton(Button.kLeftBumper.value);
164  }
165
166  /**
167   * Read the value of the right bumper (RB) button on the controller.
168   *
169   * @return The state of the button.
170   */
171  public boolean getRightBumper() {
172    return getRawButton(Button.kRightBumper.value);
173  }
174
175  /**
176   * Whether the left bumper (LB) was pressed since the last check.
177   *
178   * @return Whether the button was pressed since the last check.
179   */
180  public boolean getLeftBumperPressed() {
181    return getRawButtonPressed(Button.kLeftBumper.value);
182  }
183
184  /**
185   * Whether the right bumper (RB) was pressed since the last check.
186   *
187   * @return Whether the button was pressed since the last check.
188   */
189  public boolean getRightBumperPressed() {
190    return getRawButtonPressed(Button.kRightBumper.value);
191  }
192
193  /**
194   * Whether the left bumper (LB) was released since the last check.
195   *
196   * @return Whether the button was released since the last check.
197   */
198  public boolean getLeftBumperReleased() {
199    return getRawButtonReleased(Button.kLeftBumper.value);
200  }
201
202  /**
203   * Whether the right bumper (RB) was released since the last check.
204   *
205   * @return Whether the button was released since the last check.
206   */
207  public boolean getRightBumperReleased() {
208    return getRawButtonReleased(Button.kRightBumper.value);
209  }
210
211  /**
212   * Constructs an event instance around the right bumper's digital signal.
213   *
214   * @param loop the event loop instance to attach the event to.
215   * @return an event instance representing the right bumper's digital signal attached to the given
216   *     loop.
217   */
218  public BooleanEvent leftBumper(EventLoop loop) {
219    return new BooleanEvent(loop, this::getLeftBumper);
220  }
221
222  /**
223   * Constructs an event instance around the left bumper's digital signal.
224   *
225   * @param loop the event loop instance to attach the event to.
226   * @return an event instance representing the left bumper's digital signal attached to the given
227   *     loop.
228   */
229  public BooleanEvent rightBumper(EventLoop loop) {
230    return new BooleanEvent(loop, this::getRightBumper);
231  }
232
233  /**
234   * Read the value of the left stick button (LSB) on the controller.
235   *
236   * @return The state of the button.
237   */
238  public boolean getLeftStickButton() {
239    return getRawButton(Button.kLeftStick.value);
240  }
241
242  /**
243   * Read the value of the right stick button (RSB) on the controller.
244   *
245   * @return The state of the button.
246   */
247  public boolean getRightStickButton() {
248    return getRawButton(Button.kRightStick.value);
249  }
250
251  /**
252   * Whether the left stick button (LSB) was pressed since the last check.
253   *
254   * @return Whether the button was pressed since the last check.
255   */
256  public boolean getLeftStickButtonPressed() {
257    return getRawButtonPressed(Button.kLeftStick.value);
258  }
259
260  /**
261   * Whether the right stick button (RSB) was pressed since the last check.
262   *
263   * @return Whether the button was pressed since the last check.
264   */
265  public boolean getRightStickButtonPressed() {
266    return getRawButtonPressed(Button.kRightStick.value);
267  }
268
269  /**
270   * Whether the left stick button (LSB) was released since the last check.
271   *
272   * @return Whether the button was released since the last check.
273   */
274  public boolean getLeftStickButtonReleased() {
275    return getRawButtonReleased(Button.kLeftStick.value);
276  }
277
278  /**
279   * Whether the right stick (RSB) button was released since the last check.
280   *
281   * @return Whether the button was released since the last check.
282   */
283  public boolean getRightStickButtonReleased() {
284    return getRawButtonReleased(Button.kRightStick.value);
285  }
286
287  /**
288   * Constructs an event instance around the left stick button's digital signal.
289   *
290   * @param loop the event loop instance to attach the event to.
291   * @return an event instance representing the left stick button's digital signal attached to the
292   *     given loop.
293   */
294  public BooleanEvent leftStick(EventLoop loop) {
295    return new BooleanEvent(loop, this::getLeftStickButton);
296  }
297
298  /**
299   * Constructs an event instance around the right stick button's digital signal.
300   *
301   * @param loop the event loop instance to attach the event to.
302   * @return an event instance representing the right stick button's digital signal attached to the
303   *     given loop.
304   */
305  public BooleanEvent rightStick(EventLoop loop) {
306    return new BooleanEvent(loop, this::getRightStickButton);
307  }
308
309  /**
310   * Read the value of the A button on the controller.
311   *
312   * @return The state of the button.
313   */
314  public boolean getAButton() {
315    return getRawButton(Button.kA.value);
316  }
317
318  /**
319   * Whether the A button was pressed since the last check.
320   *
321   * @return Whether the button was pressed since the last check.
322   */
323  public boolean getAButtonPressed() {
324    return getRawButtonPressed(Button.kA.value);
325  }
326
327  /**
328   * Whether the A button was released since the last check.
329   *
330   * @return Whether the button was released since the last check.
331   */
332  public boolean getAButtonReleased() {
333    return getRawButtonReleased(Button.kA.value);
334  }
335
336  /**
337   * Constructs an event instance around the A button's digital signal.
338   *
339   * @param loop the event loop instance to attach the event to.
340   * @return an event instance representing the A button's digital signal attached to the given
341   *     loop.
342   */
343  @SuppressWarnings("MethodName")
344  public BooleanEvent a(EventLoop loop) {
345    return new BooleanEvent(loop, this::getAButton);
346  }
347
348  /**
349   * Read the value of the B button on the controller.
350   *
351   * @return The state of the button.
352   */
353  public boolean getBButton() {
354    return getRawButton(Button.kB.value);
355  }
356
357  /**
358   * Whether the B button was pressed since the last check.
359   *
360   * @return Whether the button was pressed since the last check.
361   */
362  public boolean getBButtonPressed() {
363    return getRawButtonPressed(Button.kB.value);
364  }
365
366  /**
367   * Whether the B button was released since the last check.
368   *
369   * @return Whether the button was released since the last check.
370   */
371  public boolean getBButtonReleased() {
372    return getRawButtonReleased(Button.kB.value);
373  }
374
375  /**
376   * Constructs an event instance around the B button's digital signal.
377   *
378   * @param loop the event loop instance to attach the event to.
379   * @return an event instance representing the B button's digital signal attached to the given
380   *     loop.
381   */
382  @SuppressWarnings("MethodName")
383  public BooleanEvent b(EventLoop loop) {
384    return new BooleanEvent(loop, this::getBButton);
385  }
386
387  /**
388   * Read the value of the X button on the controller.
389   *
390   * @return The state of the button.
391   */
392  public boolean getXButton() {
393    return getRawButton(Button.kX.value);
394  }
395
396  /**
397   * Whether the X button was pressed since the last check.
398   *
399   * @return Whether the button was pressed since the last check.
400   */
401  public boolean getXButtonPressed() {
402    return getRawButtonPressed(Button.kX.value);
403  }
404
405  /**
406   * Whether the X button was released since the last check.
407   *
408   * @return Whether the button was released since the last check.
409   */
410  public boolean getXButtonReleased() {
411    return getRawButtonReleased(Button.kX.value);
412  }
413
414  /**
415   * Constructs an event instance around the X button's digital signal.
416   *
417   * @param loop the event loop instance to attach the event to.
418   * @return an event instance representing the X button's digital signal attached to the given
419   *     loop.
420   */
421  @SuppressWarnings("MethodName")
422  public BooleanEvent x(EventLoop loop) {
423    return new BooleanEvent(loop, this::getXButton);
424  }
425
426  /**
427   * Read the value of the Y button on the controller.
428   *
429   * @return The state of the button.
430   */
431  public boolean getYButton() {
432    return getRawButton(Button.kY.value);
433  }
434
435  /**
436   * Whether the Y button was pressed since the last check.
437   *
438   * @return Whether the button was pressed since the last check.
439   */
440  public boolean getYButtonPressed() {
441    return getRawButtonPressed(Button.kY.value);
442  }
443
444  /**
445   * Whether the Y button was released since the last check.
446   *
447   * @return Whether the button was released since the last check.
448   */
449  public boolean getYButtonReleased() {
450    return getRawButtonReleased(Button.kY.value);
451  }
452
453  /**
454   * Constructs an event instance around the Y button's digital signal.
455   *
456   * @param loop the event loop instance to attach the event to.
457   * @return an event instance representing the Y button's digital signal attached to the given
458   *     loop.
459   */
460  @SuppressWarnings("MethodName")
461  public BooleanEvent y(EventLoop loop) {
462    return new BooleanEvent(loop, this::getYButton);
463  }
464
465  /**
466   * Read the value of the back button on the controller.
467   *
468   * @return The state of the button.
469   */
470  public boolean getBackButton() {
471    return getRawButton(Button.kBack.value);
472  }
473
474  /**
475   * Whether the back button was pressed since the last check.
476   *
477   * @return Whether the button was pressed since the last check.
478   */
479  public boolean getBackButtonPressed() {
480    return getRawButtonPressed(Button.kBack.value);
481  }
482
483  /**
484   * Whether the back button was released since the last check.
485   *
486   * @return Whether the button was released since the last check.
487   */
488  public boolean getBackButtonReleased() {
489    return getRawButtonReleased(Button.kBack.value);
490  }
491
492  /**
493   * Constructs an event instance around the back button's digital signal.
494   *
495   * @param loop the event loop instance to attach the event to.
496   * @return an event instance representing the back button's digital signal attached to the given
497   *     loop.
498   */
499  public BooleanEvent back(EventLoop loop) {
500    return new BooleanEvent(loop, this::getBackButton);
501  }
502
503  /**
504   * Read the value of the start button on the controller.
505   *
506   * @return The state of the button.
507   */
508  public boolean getStartButton() {
509    return getRawButton(Button.kStart.value);
510  }
511
512  /**
513   * Whether the start button was pressed since the last check.
514   *
515   * @return Whether the button was pressed since the last check.
516   */
517  public boolean getStartButtonPressed() {
518    return getRawButtonPressed(Button.kStart.value);
519  }
520
521  /**
522   * Whether the start button was released since the last check.
523   *
524   * @return Whether the button was released since the last check.
525   */
526  public boolean getStartButtonReleased() {
527    return getRawButtonReleased(Button.kStart.value);
528  }
529
530  /**
531   * Constructs an event instance around the start button's digital signal.
532   *
533   * @param loop the event loop instance to attach the event to.
534   * @return an event instance representing the start button's digital signal attached to the given
535   *     loop.
536   */
537  public BooleanEvent start(EventLoop loop) {
538    return new BooleanEvent(loop, this::getStartButton);
539  }
540
541  /**
542   * Constructs an event instance around the axis value of the left trigger. The returned trigger
543   * will be true when the axis value is greater than {@code threshold}.
544   *
545   * @param threshold the minimum axis value for the returned {@link BooleanEvent} to be true. This
546   *     value should be in the range [0, 1] where 0 is the unpressed state of the axis.
547   * @param loop the event loop instance to attach the event to.
548   * @return an event instance that is true when the left trigger's axis exceeds the provided
549   *     threshold, attached to the given event loop
550   */
551  public BooleanEvent leftTrigger(double threshold, EventLoop loop) {
552    return new BooleanEvent(loop, () -> getLeftTriggerAxis() > threshold);
553  }
554
555  /**
556   * Constructs an event instance around the axis value of the left trigger. The returned trigger
557   * will be true when the axis value is greater than 0.5.
558   *
559   * @param loop the event loop instance to attach the event to.
560   * @return an event instance that is true when the left trigger's axis exceeds the provided
561   *     threshold, attached to the given event loop
562   */
563  public BooleanEvent leftTrigger(EventLoop loop) {
564    return leftTrigger(0.5, loop);
565  }
566
567  /**
568   * Constructs an event instance around the axis value of the right trigger. The returned trigger
569   * will be true when the axis value is greater than {@code threshold}.
570   *
571   * @param threshold the minimum axis value for the returned {@link BooleanEvent} to be true. This
572   *     value should be in the range [0, 1] where 0 is the unpressed state of the axis.
573   * @param loop the event loop instance to attach the event to.
574   * @return an event instance that is true when the right trigger's axis exceeds the provided
575   *     threshold, attached to the given event loop
576   */
577  public BooleanEvent rightTrigger(double threshold, EventLoop loop) {
578    return new BooleanEvent(loop, () -> getRightTriggerAxis() > threshold);
579  }
580
581  /**
582   * Constructs an event instance around the axis value of the right trigger. The returned trigger
583   * will be true when the axis value is greater than 0.5.
584   *
585   * @param loop the event loop instance to attach the event to.
586   * @return an event instance that is true when the right trigger's axis exceeds the provided
587   *     threshold, attached to the given event loop
588   */
589  public BooleanEvent rightTrigger(EventLoop loop) {
590    return rightTrigger(0.5, loop);
591  }
592}