182 строки
4.9 KiB
C++
182 строки
4.9 KiB
C++
#include "pxt.h"
|
|
|
|
/*
|
|
|
|
These button events need CODAL work.
|
|
|
|
// % block="double click"
|
|
DoubleClick = DEVICE_BUTTON_EVT_DOUBLE_CLICK,
|
|
|
|
// % block="hold"
|
|
Hold = DEVICE_BUTTON_EVT_HOLD
|
|
|
|
*/
|
|
|
|
/**
|
|
* User interaction on buttons
|
|
*/
|
|
enum class ButtonEvent {
|
|
//% block="click"
|
|
Click = DEVICE_BUTTON_EVT_CLICK,
|
|
//% block="long click"
|
|
LongClick = DEVICE_BUTTON_EVT_LONG_CLICK,
|
|
//% block="up"
|
|
Up = DEVICE_BUTTON_EVT_UP,
|
|
//% block="down"
|
|
Down = DEVICE_BUTTON_EVT_DOWN
|
|
};
|
|
|
|
namespace pxt {
|
|
//%
|
|
Button *getButtonByPin(int pin, int flags) {
|
|
unsigned highflags = (unsigned)pin >> 16;
|
|
if (highflags & 0xff)
|
|
flags = highflags & 0xff;
|
|
|
|
pin &= 0xffff;
|
|
|
|
auto cpid = DEVICE_ID_FIRST_BUTTON + pin;
|
|
auto btn = (Button *)lookupComponent(cpid);
|
|
if (btn == NULL) {
|
|
auto pull = PullMode::None;
|
|
if ((flags & 0xf0) == 0x10)
|
|
pull = PullMode::Down;
|
|
else if ((flags & 0xf0) == 0x20)
|
|
pull = PullMode::Up;
|
|
else if ((flags & 0xf0) == 0x30)
|
|
pull = PullMode::None;
|
|
else
|
|
oops(3);
|
|
// GCTODO
|
|
btn = new Button(*lookupPin(pin), cpid, DEVICE_BUTTON_ALL_EVENTS,
|
|
(ButtonPolarity)(flags & 0xf), pull);
|
|
}
|
|
return btn;
|
|
}
|
|
|
|
//%
|
|
Button *getButtonByPinCfg(int key, int flags) {
|
|
int pin = getConfig(key);
|
|
if (pin == -1)
|
|
soft_panic(PANIC_NO_SUCH_CONFIG);
|
|
return getButtonByPin(pin, flags);
|
|
}
|
|
|
|
MultiButton *getMultiButton(int id, int pinA, int pinB, int flags) {
|
|
auto btn = (MultiButton *)lookupComponent(id);
|
|
if (btn == NULL) {
|
|
auto bA = getButtonByPin(pinA, flags);
|
|
auto bB = getButtonByPin(pinB, flags);
|
|
// GCTODO
|
|
btn = new MultiButton(bA->id, bB->id, id);
|
|
|
|
// A user has registered to receive events from the buttonAB multibutton.
|
|
// Disable click events from being generated by ButtonA and ButtonB, and defer the
|
|
// control of this to the multibutton handler.
|
|
//
|
|
// This way, buttons look independent unless a buttonAB is requested, at which
|
|
// point button A+B clicks can be correclty handled without breaking
|
|
// causal ordering.
|
|
bA->setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS);
|
|
bB->setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS);
|
|
btn->setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS);
|
|
}
|
|
return btn;
|
|
}
|
|
|
|
// This is for A, B, and AB
|
|
//%
|
|
AbstractButton *getButton(int id) {
|
|
int pa = getConfig(CFG_PIN_BTN_A);
|
|
int pb = getConfig(CFG_PIN_BTN_B);
|
|
int flags = getConfig(CFG_DEFAULT_BUTTON_MODE, BUTTON_ACTIVE_LOW_PULL_UP);
|
|
if (id == 0)
|
|
return getButtonByPin(pa, flags);
|
|
else if (id == 1)
|
|
return getButtonByPin(pb, flags);
|
|
else if (id == 2)
|
|
return getMultiButton(DEVICE_ID_BUTTON_AB, pa, pb, flags);
|
|
else {
|
|
soft_panic(PANIC_INVALID_ARGUMENT);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
} // namespace pxt
|
|
|
|
namespace DigitalInOutPinMethods {
|
|
|
|
/**
|
|
* Get the push button (connected to GND) for given pin
|
|
*/
|
|
//%
|
|
Button_ pushButton(DigitalInOutPin pin) {
|
|
return pxt::getButtonByPin(pin->name, BUTTON_ACTIVE_LOW_PULL_UP);
|
|
}
|
|
|
|
} // namespace DigitalInOutPinMethods
|
|
|
|
//% noRefCounting fixedInstances
|
|
namespace ButtonMethods {
|
|
/**
|
|
* Do something when a button (`A`, `B` or both `A` + `B`) is clicked, double clicked, etc...
|
|
* @param button the button that needs to be clicked or used
|
|
* @param event the kind of button gesture that needs to be detected
|
|
* @param body code to run when the event is raised
|
|
*/
|
|
//% help=input/button/on-event
|
|
//% blockId=buttonEvent block="on %button|%event"
|
|
//% blockNamespace=input
|
|
//% button.fieldEditor="gridpicker"
|
|
//% button.fieldOptions.width=220
|
|
//% button.fieldOptions.columns=3
|
|
//% weight=96 blockGap=12
|
|
//% trackArgs=0
|
|
void onEvent(Button_ button, ButtonEvent ev, Action body) {
|
|
registerWithDal(button->id, (int)ev, body);
|
|
}
|
|
|
|
/**
|
|
* Check if a button is pressed or not.
|
|
* @param button the button to query the request
|
|
*/
|
|
//% help=input/button/is-pressed
|
|
//% block="%button|is pressed"
|
|
//% blockId=buttonIsPressed
|
|
//% blockNamespace=input
|
|
//% button.fieldEditor="gridpicker"
|
|
//% button.fieldOptions.width=220
|
|
//% button.fieldOptions.columns=3
|
|
//% weight=50 blockGap=8
|
|
//% trackArgs=0
|
|
bool isPressed(Button_ button) {
|
|
return button->isPressed();
|
|
}
|
|
|
|
/**
|
|
* See if the button was pressed again since the last time you checked.
|
|
* @param button the button to query the request
|
|
*/
|
|
//% help=input/button/was-pressed
|
|
//% block="%button|was pressed"
|
|
//% blockId=buttonWasPressed
|
|
//% blockNamespace=input
|
|
//% button.fieldEditor="gridpicker"
|
|
//% button.fieldOptions.width=220
|
|
//% button.fieldOptions.columns=3
|
|
//% group="More" weight=46 blockGap=8
|
|
//% trackArgs=0
|
|
bool wasPressed(Button_ button) {
|
|
return button->wasPressed();
|
|
}
|
|
|
|
/**
|
|
* Gets the component identifier for the button
|
|
*/
|
|
//%
|
|
int id(Button_ button) {
|
|
return button->id;
|
|
}
|
|
|
|
} // namespace ButtonMethods
|