@@ -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