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