Skip to content

Commit fa7942a

Browse files
authored
Merge pull request #90 from smalruby/fix/issue-20-moved-event-improvements
fix: improve 'moved' gesture event behavior in MicrobitMore
2 parents 6e57d0d + 1f531a7 commit fa7942a

1 file changed

Lines changed: 82 additions & 13 deletions

File tree

src/extensions/microbitMore/index.js

Lines changed: 82 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,14 @@ class MbitMoreBlocks {
16061606
*/
16071607
get GESTURES_MENU () {
16081608
return [
1609+
{
1610+
text: formatMessage({
1611+
id: 'mbitMore.gesturesMenu.moved',
1612+
default: 'moved',
1613+
description: 'label for moved gesture in gesture picker for microbit more extension'
1614+
}),
1615+
value: 'MOVED'
1616+
},
16091617
{
16101618
text: formatMessage({
16111619
id: 'mbitMore.gesturesMenu.tiltUp',
@@ -1693,14 +1701,6 @@ class MbitMoreBlocks {
16931701
description: 'label for shaken gesture in gesture picker for microbit more extension'
16941702
}),
16951703
value: MbitMoreGestureName.SHAKE
1696-
},
1697-
{
1698-
text: formatMessage({
1699-
id: 'mbitMore.gesturesMenu.moved',
1700-
default: 'moved',
1701-
description: 'label for moved gesture in gesture picker for microbit more extension'
1702-
}),
1703-
value: 'MOVED'
17041704
}
17051705
];
17061706
}
@@ -2149,6 +2149,30 @@ class MbitMoreBlocks {
21492149
*/
21502150
this.prevGestureEvents = {};
21512151

2152+
/**
2153+
* The last time the "moved" event was fired.
2154+
* @type {number}
2155+
*/
2156+
this.lastMovedEventTime = null;
2157+
2158+
/**
2159+
* The last time any gesture event was detected.
2160+
* @type {number}
2161+
*/
2162+
this.lastGestureOccurredTime = null;
2163+
2164+
/**
2165+
* Whether the extension is waiting for a gap in movement before firing again.
2166+
* @type {boolean}
2167+
*/
2168+
this.isWaitingForGap = false;
2169+
2170+
/**
2171+
* The timer of updateLastGestureEvent.
2172+
* @type {number}
2173+
*/
2174+
this.updateLastGestureEventTimer = null;
2175+
21522176
/**
21532177
* The previous timestamps of pin events.
21542178
* @type {Object.<number, Object.<number, number>>}
@@ -2278,7 +2302,7 @@ class MbitMoreBlocks {
22782302
GESTURE: {
22792303
type: ArgumentType.STRING,
22802304
menu: 'gestures',
2281-
defaultValue: MbitMoreGestureName.SHAKE
2305+
defaultValue: 'MOVED'
22822306
}
22832307
}
22842308
},
@@ -2865,18 +2889,63 @@ class MbitMoreBlocks {
28652889
* @return {boolean} - true if the event raised.
28662890
*/
28672891
whenGesture (args) {
2868-
if (!this.updateLastGestureEventTimer) {
2892+
if (this.updateLastGestureEventTimer === null) {
28692893
this.updateLastGestureEventTimer = setTimeout(() => {
28702894
this.updatePrevGestureEvents();
28712895
this.updateLastGestureEventTimer = null;
28722896
}, this.runtime.currentStepTime);
28732897
}
28742898
const gestureName = args.GESTURE;
28752899
if (gestureName === 'MOVED') {
2876-
return Object.entries(this._peripheral.gestureEvents).some(([name, timestamp]) => {
2877-
if (!this.prevGestureEvents[name]) return true;
2878-
return timestamp !== this.prevGestureEvents[name];
2900+
const now = Date.now();
2901+
const stepTime = this.runtime.currentStepTime;
2902+
const gapThreshold = stepTime * 5; // 5フレームの空白
2903+
const timeoutThreshold = stepTime * 30; // 30フレームで強制発火
2904+
2905+
const changedGestures = [];
2906+
Object.entries(this._peripheral.gestureEvents).forEach(([name, timestamp]) => {
2907+
if (this.prevGestureEvents[name]) {
2908+
if (timestamp !== this.prevGestureEvents[name]) {
2909+
changedGestures.push(`${name}(${this.prevGestureEvents[name]}->${timestamp})`);
2910+
}
2911+
} else {
2912+
changedGestures.push(`${name}(new->${timestamp})`);
2913+
}
28792914
});
2915+
2916+
const eventDetected = changedGestures.length > 0;
2917+
if (eventDetected) {
2918+
this.lastGestureOccurredTime = now;
2919+
}
2920+
2921+
// 静止判定(隙間ができたか)
2922+
const timeSinceLastOccurred = this.lastGestureOccurredTime === null ?
2923+
Infinity : (now - this.lastGestureOccurredTime);
2924+
if (timeSinceLastOccurred >= gapThreshold) {
2925+
this.isWaitingForGap = false;
2926+
}
2927+
2928+
let shouldFire = false;
2929+
2930+
if (eventDetected) {
2931+
if (this.isWaitingForGap) {
2932+
// 動き続けている場合の強制発火判定
2933+
const timeSinceLastFired = this.lastMovedEventTime === null ?
2934+
Infinity : (now - this.lastMovedEventTime);
2935+
if (timeSinceLastFired >= timeoutThreshold) {
2936+
shouldFire = true;
2937+
}
2938+
} else {
2939+
shouldFire = true;
2940+
}
2941+
}
2942+
2943+
if (shouldFire) {
2944+
this.lastMovedEventTime = now;
2945+
this.isWaitingForGap = true;
2946+
}
2947+
2948+
return shouldFire;
28802949
}
28812950
const lastTimestamp =
28822951
this._peripheral.getGestureEventTimestamp(gestureName);

0 commit comments

Comments
 (0)