From d640dc5eedf0af144362a10ff8714c1a4e34fbe8 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Thu, 21 Mar 2019 07:40:23 -0700 Subject: [PATCH] support for is-gesture (#1873) * support for is-gesture * updated shims * activate shake button * refactor * refactor shake button --- docs/reference/input.md | 5 ++- docs/reference/input/is-gesture.md | 28 +++++++++++++++ docs/reference/input/on-gesture.md | 3 ++ libs/core/_locales/core-jsdoc-strings.json | 2 ++ libs/core/_locales/core-strings.json | 1 + libs/core/input.cpp | 13 +++++++ libs/core/shims.d.ts | 10 ++++++ sim/state/accelerometer.ts | 41 +++++++++++++++++----- sim/visuals/microbit.ts | 4 +-- 9 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 docs/reference/input/is-gesture.md diff --git a/docs/reference/input.md b/docs/reference/input.md index cc067255..80920799 100644 --- a/docs/reference/input.md +++ b/docs/reference/input.md @@ -13,6 +13,7 @@ input.onPinPressed(TouchPin.P0, () => { }); input.buttonIsPressed(Button.A); +input.isGesture(Gesture.Shake); input.compassHeading(); input.pinIsPressed(TouchPin.P0); input.temperature(); @@ -27,4 +28,6 @@ input.setAccelerometerRange(AcceleratorRange.OneG); ## See also -[onButtonPressed](/reference/input/on-button-pressed), [onGesture](/reference/input/on-gesture), [onPinPressed](/reference/input/on-pin-pressed), [buttonIsPressed](/reference/input/button-is-pressed), [compassHeading](/reference/input/compass-heading), [pinIsPressed](/reference/input/pin-is-pressed), [temperature](/reference/input/temperature), [acceleration](/reference/input/acceleration), [lightLevel](/reference/input/light-level), [rotation](/reference/input/rotation), [magneticForce](/reference/input/magnetic-force), [runningTime](/reference/input/running-time), [setAccelerometerRange](/reference/input/set-accelerometer-range), [calibrate-compass](/reference/input/calibrate-compass) +[onButtonPressed](/reference/input/on-button-pressed), [onGesture](/reference/input/on-gesture), [onPinPressed](/reference/input/on-pin-pressed), [buttonIsPressed](/reference/input/button-is-pressed), +[is gesture](/reference/input/is-gesture), +[compassHeading](/reference/input/compass-heading), [pinIsPressed](/reference/input/pin-is-pressed), [temperature](/reference/input/temperature), [acceleration](/reference/input/acceleration), [lightLevel](/reference/input/light-level), [rotation](/reference/input/rotation), [magneticForce](/reference/input/magnetic-force), [runningTime](/reference/input/running-time), [setAccelerometerRange](/reference/input/set-accelerometer-range), [calibrate-compass](/reference/input/calibrate-compass) diff --git a/docs/reference/input/is-gesture.md b/docs/reference/input/is-gesture.md new file mode 100644 index 00000000..3becc968 --- /dev/null +++ b/docs/reference/input/is-gesture.md @@ -0,0 +1,28 @@ +# Is Gesture + +Tests if a gesture is currently detected. + +```sig +input.isGesture(Gesture.Shake) +``` + +## Parameters + +* ``gesture`` means the way you hold or move the @boardname@. This can be `shake`, `logo up`, `logo down`, `screen up`, `screen down`, `tilt left`, `tilt right`, `free fall`, `3g`, or `6g`. + +## Example: random number + +This program shows a number from `2` to `9` when you shake the @boardname@. + +```blocks +forever(function() { + if (input.isGesture(Gesture.Shake)) { + let x = Math.randomRange(2, 9) + basic.showNumber(x) + } +}) +``` + +## See Also + +[on gesture](/reference/input/on-gesture) diff --git a/docs/reference/input/on-gesture.md b/docs/reference/input/on-gesture.md index 49cc4ed9..29e98e5a 100644 --- a/docs/reference/input/on-gesture.md +++ b/docs/reference/input/on-gesture.md @@ -24,3 +24,6 @@ input.onGesture(Gesture.Shake,() => { }) ``` +## See Also + +[is gesture](/reference/input/is-gesture) \ No newline at end of file diff --git a/libs/core/_locales/core-jsdoc-strings.json b/libs/core/_locales/core-jsdoc-strings.json index d06a86d8..884109f1 100644 --- a/libs/core/_locales/core-jsdoc-strings.json +++ b/libs/core/_locales/core-jsdoc-strings.json @@ -340,6 +340,8 @@ "input.calibrate": "Obsolete, use input.calibrateCompass instead.", "input.calibrateCompass": "Obsolete, compass calibration is automatic.", "input.compassHeading": "Get the current compass heading in degrees.", + "input.isGesture": "Tests if a gesture is currently detected.", + "input.isGesture|param|gesture": "the type of gesture to detect, eg: Gesture.Shake", "input.lightLevel": "Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.", "input.magneticForce": "Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.", "input.magneticForce|param|dimension": "TODO", diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index 2bfbe292..8caf6d76 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -291,6 +291,7 @@ "input.buttonIsPressed|block": "button|%NAME|is pressed", "input.calibrateCompass|block": "calibrate compass", "input.compassHeading|block": "compass heading (°)", + "input.isGesture|block": "is %gesture gesture", "input.lightLevel|block": "light level", "input.magneticForce|block": "magnetic force (µT)|%NAME", "input.onButtonPressed|block": "on button|%NAME|pressed", diff --git a/libs/core/input.cpp b/libs/core/input.cpp index 5a971ac4..4f8bc21e 100644 --- a/libs/core/input.cpp +++ b/libs/core/input.cpp @@ -190,6 +190,19 @@ namespace input { registerWithDal(MICROBIT_ID_GESTURE, gi, body); } + /** + * Tests if a gesture is currently detected. + * @param gesture the type of gesture to detect, eg: Gesture.Shake + */ + //% help=input/is-gesture weight=10 blockGap=8 + //% blockId=deviceisgesture block="is %gesture gesture" + //% parts="accelerometer" + //% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4 + bool isGesture(Gesture gesture) { + int gi = (int)gesture; + return uBit.accelerometer.getGesture() == gi; + } + /** * Do something when a pin is touched and released again (while also touching the GND pin). * @param name the pin that needs to be pressed, eg: TouchPin.P0 diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index a1ab5f28..52ef2990 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -228,6 +228,16 @@ declare namespace input { //% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4 shim=input::onGesture function onGesture(gesture: Gesture, body: () => void): void; + /** + * Tests if a gesture is currently detected. + * @param gesture the type of gesture to detect, eg: Gesture.Shake + */ + //% help=input/is-gesture weight=10 blockGap=8 + //% blockId=deviceisgesture block="is %gesture gesture" + //% parts="accelerometer" + //% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4 shim=input::isGesture + function isGesture(gesture: Gesture): boolean; + /** * Do something when a pin is touched and released again (while also touching the GND pin). * @param name the pin that needs to be pressed, eg: TouchPin.P0 diff --git a/sim/state/accelerometer.ts b/sim/state/accelerometer.ts index 0aca8166..0b064c58 100644 --- a/sim/state/accelerometer.ts +++ b/sim/state/accelerometer.ts @@ -1,30 +1,39 @@ namespace pxsim.input { - export function onGesture(gesture: number, handler: RefAction) { + function accForGesture(gesture: number) { let b = board().accelerometerState; b.accelerometer.activate(); - - if (gesture == 11 && !b.useShake) { // SAKE + if (gesture == 11 && !b.useShake) { // SHAKE b.useShake = true; runtime.queueDisplayUpdate(); } + return b; + } + + export function onGesture(gesture: number, handler: RefAction) { + const b = accForGesture(gesture); pxtcore.registerWithDal(DAL.MICROBIT_ID_GESTURE, gesture, handler); } + export function isGesture(gesture: number): boolean { + const b = accForGesture(gesture); + return b.accelerometer.getGesture() == gesture; + } + export function acceleration(dimension: number): number { let b = board().accelerometerState; let acc = b.accelerometer; switch (dimension) { - case 0: + case 0: acc.activate(AccelerometerFlag.X); return acc.getX(); - case 1: + case 1: acc.activate(AccelerometerFlag.Y); return acc.getY(); - case 2: + case 2: acc.activate(AccelerometerFlag.Z); return acc.getZ(); - default: - acc.activate(); + default: + acc.activate(); return Math.floor(Math.sqrt(acc.instantaneousAccelerationSquared())); } } @@ -249,7 +258,10 @@ namespace pxsim { updateGesture() { // Determine what it looks like we're doing based on the latest sample... let g = this.instantaneousPosture(); + this.setGesture(g); + } + private setGesture(g: number) { // Perform some low pass filtering to reduce jitter from any detected effects if (g == this.currentGesture) { if (this.sigma < DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING) @@ -267,6 +279,11 @@ namespace pxsim { } } + forceGesture(g: number) { + this.sigma = DAL.MICROBIT_ACCELEROMETER_GESTURE_DAMPING + 1; + this.setGesture(g); + } + /** * Reads the X axis value of the latest update from the accelerometer. * @param system The coordinate system to use. By default, a simple cartesian system is provided. @@ -378,6 +395,10 @@ namespace pxsim { return this.roll; } + getGesture(): number { + return this.lastGesture; + } + /** * Recalculate roll and pitch values for the current sample. * We only do this at most once per sample, as the necessary trigonemteric functions are rather @@ -401,5 +422,9 @@ namespace pxsim { constructor(runtime: Runtime) { this.accelerometer = new Accelerometer(runtime); } + + shake() { + this.accelerometer.forceGesture(DAL.MICROBIT_ACCELEROMETER_EVT_SHAKE); // SHAKE == 11 + } } } \ No newline at end of file diff --git a/sim/visuals/microbit.ts b/sim/visuals/microbit.ts index 4c67f4c7..4c1cd5ac 100644 --- a/sim/visuals/microbit.ts +++ b/sim/visuals/microbit.ts @@ -433,10 +433,10 @@ path.sim-board { this.shakeButton.addEventListener(pointerEvents.up, ev => { let state = this.board; svg.fill(this.shakeButton, this.props.theme.virtualButtonUp); - this.board.bus.queue(DAL.MICROBIT_ID_GESTURE, 11); // GESTURE_SHAKE + this.board.accelerometerState.shake(); }) accessibility.enableKeyboardInteraction(this.shakeButton, undefined, () => { - this.board.bus.queue(DAL.MICROBIT_ID_GESTURE, 11); + this.board.accelerometerState.shake(); }); accessibility.setAria(this.shakeButton, "button", "Shake the board"); this.shakeText = svg.child(this.g, "text", { x: 400, y: 110, class: "sim-text" }) as SVGTextElement;