11import adb , { DeviceClient , Utils , MotionEventMap , Scrcpy } from "../src/index.js" ;
22import Parser from "../src/adb/parser.js" ;
3+ import readline from "node:readline" ;
34
4- const NB_CLICK = 1000000 ;
5+ const NB_CLICK = 100000000 ;
56
67const Y_OFFSET = 0.02 ; //25;
78
8- async function * getCenterTaps ( width : number , height : number , count : number , asPercent = false ) {
9+ interface TapOptions {
10+ xRadius ?: number ;
11+ yRadius ?: number ;
12+ asPercent ?: boolean ;
13+ fromX ?: number ;
14+ fromY ?: number ;
15+ toX ?: number ;
16+ toY ?: number ;
17+ stepX ?: number ;
18+ stepY ?: number ;
19+ }
20+
21+ const MODES = [ "NONE" , "CENTER" , "MIX" , "ALL" , ] as const ;
22+ let MODE : ( typeof MODES ) [ number ] = "NONE" ;
23+ let currentModeIndex = 0 ;
24+ MODE = MODES [ currentModeIndex ] ;
25+
26+ async function * getCenterTaps ( width : number , height : number , options : TapOptions = { } ) {
27+ const { xRadius, yRadius, asPercent = false } = options ;
928 const centerX = asPercent ? width / 2 : Math . floor ( width / 2 ) ;
1029 const centerY = asPercent ? height / 2 - height * Y_OFFSET : Math . floor ( height / 2 - height * Y_OFFSET ) ; // Move up by 20%
11- const radius = Math . min ( width , height ) * 0.15 ; // 40% diameter = 20% radius
30+ const defaultRadius = Math . min ( width , height ) * 0.22 ; // 40% diameter = 20% radius
31+ const radiusX = xRadius ?? defaultRadius ;
32+ const radiusY = yRadius ?? defaultRadius ;
1233
13- console . log ( `Screen: ${ width } x${ height } , Center: ${ centerX } ,${ centerY } , Circle radius : ${ radius } ` ) ;
34+ console . log ( `Screen: ${ width } x${ height } , Center: ${ centerX } ,${ centerY } , Radius : ${ radiusX } x ${ radiusY } ` ) ;
1435 const STEPS = 16 ;
15- for ( let i = 0 ; i < count ; i ++ ) {
16- const angle = ( 2 * Math . PI * ( i % STEPS ) ) / STEPS ;
17- const x = asPercent ? centerX + radius * Math . cos ( angle ) : Math . floor ( centerX + radius * Math . cos ( angle ) ) ;
18- const y = asPercent ? centerY + radius * Math . sin ( angle ) : Math . floor ( centerY + radius * Math . sin ( angle ) ) ;
19- yield { x, y } ;
20- // await Utils.delay(100);
36+
37+ const fromX = options . fromX ?? 0.1 ;
38+ const fromY = options . fromY ?? 0.1 ;
39+
40+ const toX = options . toX ?? 0.9 ;
41+ const toY = options . toY ?? 0.9 ;
42+
43+ const selctionsCenter : Array < { x : number , y : number } > = [ ] ;
44+ const selctionsMix : Array < { x : number , y : number } > = [ ] ;
45+ const selctionsAll : Array < { x : number , y : number } > = [ ] ;
46+
47+ const shuffle = ( array : Array < { x : number , y : number } > ) => {
48+ for ( let i = array . length - 1 ; i > 0 ; i -- ) {
49+ const j = Math . floor ( Math . random ( ) * ( i + 1 ) ) ;
50+ [ array [ i ] , array [ j ] ] = [ array [ j ] , array [ i ] ] ;
51+ }
52+ } ;
53+
54+ // while (true)
55+ {
56+ for ( let i = 0 ; i < ( STEPS * 1 ) ; i ++ ) {
57+ const angle = ( 2 * Math . PI * ( i % STEPS ) ) / STEPS ;
58+ const x = asPercent ? centerX + radiusX * Math . cos ( angle ) : Math . floor ( centerX + radiusX * Math . cos ( angle ) ) ;
59+ const y = asPercent ? centerY + radiusY * Math . sin ( angle ) : Math . floor ( centerY + radiusY * Math . sin ( angle ) ) ;
60+ selctionsCenter . push ( { x, y } ) ;
61+ // yield { x, y };
62+ // await Utils.delay(100);
63+ }
64+ for ( let x = fromX ; x <= toX ; x += ( options . stepX ?? 0.1 ) ) {
65+ for ( let y = fromY ; y <= toY ; y += ( options . stepY ?? 0.1 ) ) {
66+ const posX = asPercent ? x : Math . floor ( x * width ) ;
67+ const posY = asPercent ? y : Math . floor ( y * height ) ;
68+ if ( posX < 0.4 && posY < 0.4 ) continue ;
69+ selctionsAll . push ( { x : posX , y : posY } ) ;
70+ // yield { x: posX, y: posY };
71+ // await Utils.delay(100);
72+ }
73+ }
74+ selctionsMix . push ( ...selctionsCenter ) ;
75+ selctionsMix . push ( ...selctionsCenter ) ;
76+ selctionsMix . push ( ...selctionsCenter ) ;
77+ selctionsMix . push ( ...selctionsCenter ) ;
78+ selctionsMix . push ( ...selctionsAll ) ;
79+ shuffle ( selctionsCenter ) ;
80+ shuffle ( selctionsAll ) ;
81+ shuffle ( selctionsMix ) ;
82+ while ( true ) {
83+ // console.log("Mode: ", MODE);
84+ await Utils . delay ( 100 ) ;
85+ if ( MODE === "CENTER" ) {
86+ for ( const selection of selctionsCenter ) {
87+ await Utils . delay ( 1 ) ;
88+ yield selection ;
89+ if ( MODE !== "CENTER" ) {
90+ break ;
91+ }
92+ }
93+ } else if ( MODE === "MIX" ) {
94+ for ( const selection of selctionsMix ) {
95+ await Utils . delay ( 1 ) ;
96+ yield selection ;
97+ if ( MODE !== "MIX" ) {
98+ break ;
99+ }
100+ }
101+ } else if ( MODE === "ALL" ) {
102+ for ( const selection of selctionsAll ) {
103+ await Utils . delay ( 1 ) ;
104+ yield selection ;
105+ if ( MODE !== "ALL" ) {
106+ break ;
107+ }
108+ }
109+ } else {
110+ await Utils . delay ( 100 ) ;
111+ }
112+ }
21113 }
22114}
23115
24-
25116async function * getGridPercent ( count : number ) {
26117 const XGap = 0.02 ;
27118 const YGap = 0.35 ;
@@ -45,10 +136,11 @@ async function* getGridPercent(count: number) {
45136
46137
47138
48- async function * getCenterTapsForDevice ( deviceClient : DeviceClient , count : number , asPercent = false ) {
139+ async function * getCenterTapsForDevice ( deviceClient : DeviceClient , options : TapOptions = { } ) {
140+ const { asPercent = false } = options ;
49141 if ( asPercent ) {
50142 // Use normalized coordinates (0-1) without retrieving actual screen size
51- for await ( const pos of getCenterTaps ( 1 , 1 , count , true ) ) {
143+ for await ( const pos of getCenterTaps ( 1 , 1 , options ) ) {
52144 yield pos ;
53145 }
54146 } else {
@@ -59,34 +151,15 @@ async function* getCenterTapsForDevice(deviceClient: DeviceClient, count: number
59151 }
60152 const width = parseInt ( match [ 1 ] ) ;
61153 const height = parseInt ( match [ 2 ] ) ;
62- for await ( const pos of getCenterTaps ( width , height , count , false ) ) {
154+ for await ( const pos of getCenterTaps ( width , height , options ) ) {
63155 yield pos ;
64156 }
65157 }
66158}
67159
68- // async function* getFixedCenterForDevice(deviceClient: DeviceClient, count: number) {
69- // const screenInfo = await deviceClient.execOut("wm size", "utf8");
70- // const match = screenInfo.match(/Physical size: (\d+)x(\d+)/);
71- // if (!match) {
72- // throw new Error("Could not parse screen dimensions");
73- // }
74- // const width = parseInt(match[1]);
75- // const height = parseInt(match[2]);
76- // const centerX = Math.floor(width / 2);
77- // const centerY = Math.floor(height / 2 - height * Y_OFFSET); // Move up by 20%
78- // // const centerY = Math.floor(height / 2);
79- //
80- // console.log(`Screen: ${width}x${height}, Fixed center: ${centerX},${centerY}`);
81- //
82- // for (let i = 0; i < count; i++) {
83- // yield { x: centerX, y: centerY };
84- // }
85- // }
86-
87160const testClickExec = async ( deviceClient : DeviceClient ) => {
88161 try {
89- for await ( const pos of getCenterTapsForDevice ( deviceClient , NB_CLICK ) ) {
162+ for await ( const pos of getCenterTapsForDevice ( deviceClient ) ) {
90163 await deviceClient . execOut ( `input tap ${ pos . x } ${ pos . y } ` , "utf8" ) ;
91164 }
92165 } catch ( e ) {
@@ -122,7 +195,7 @@ const testClickScrcpy = async (deviceClient: DeviceClient, coordinateGenerator:
122195 while ( ! scrcpy ) {
123196 try {
124197 scrcpy = deviceClient . scrcpy ( { } ) ;
125- await Utils . delay ( 1 ) ;
198+ await Utils . delay ( 2 ) ;
126199 await scrcpy . start ( ) ;
127200 await scrcpy . width ;
128201 } catch ( e ) {
@@ -131,10 +204,6 @@ const testClickScrcpy = async (deviceClient: DeviceClient, coordinateGenerator:
131204 scrcpy = undefined ;
132205 }
133206 }
134- // const scrcpy
135- // = deviceClient.scrcpy({});
136- // await Utils.delay(1);
137- // await scrcpy.start();
138207 await Utils . delay ( 1 ) ;
139208 const width = await scrcpy . width ;
140209 const height = await scrcpy . height ;
@@ -158,9 +227,18 @@ const testClickScrcpy = async (deviceClient: DeviceClient, coordinateGenerator:
158227 // Send ACTION_DOWN followed by ACTION_UP for each tap
159228 // MotionEvent.ACTION_DOWN
160229 await scrcpy . injectTouchEvent ( MotionEventMap . ACTION_DOWN , 0n , position , screenSize , undefined , 0 , MotionEventMap . BUTTON_PRIMARY ) ;
161- await Utils . delay ( 8 ) ;
162- //await scrcpy.injectTouchEvent(MotionEventMap.ACTION_UP, 0n, position, screenSize, undefined, 0, 0);
163- //await Utils.delay(1);
230+ // const c2 = await coordinateGenerator.next();
231+ // if (!c2.done) {
232+ // const tap2 = c2.value;
233+ // const position2 = {
234+ // x: tap2.x <= 1 ? Math.floor(tap2.x * width) : tap2.x,
235+ // y: tap2.y <= 1 ? Math.floor(tap2.y * height) : tap2.y
236+ // };
237+ // await scrcpy.injectTouchEvent(MotionEventMap.ACTION_DOWN, 0n, position, screenSize, undefined, 0, MotionEventMap.BUTTON_SECONDARY);
238+ // await scrcpy.injectTouchEvent(MotionEventMap.ACTION_UP, 0n, position, screenSize, undefined, 0, MotionEventMap.BUTTON_SECONDARY);
239+ // }
240+ await scrcpy . injectTouchEvent ( MotionEventMap . ACTION_UP , 0n , position , screenSize , undefined , 0 , 0 ) ;
241+ // await Utils.delay(1);
164242 }
165243 console . log ( 'All scrcpy taps completed' ) ;
166244 } catch ( e ) {
@@ -171,6 +249,64 @@ const testClickScrcpy = async (deviceClient: DeviceClient, coordinateGenerator:
171249 scrcpy . stop ( ) ;
172250} ;
173251
252+ const setupKeyboardInterface = ( ) => {
253+ console . log ( '\n=== MODE CONTROL ===' ) ;
254+ console . log ( 'Use ARROW KEYS (←/→) or SPACE to change mode' ) ;
255+ console . log ( 'Press ESC or Ctrl+C to continue' ) ;
256+ console . log ( `Current mode: ${ MODE } ` ) ;
257+
258+ readline . emitKeypressEvents ( process . stdin ) ;
259+ if ( process . stdin . isTTY ) {
260+ process . stdin . setRawMode ( true ) ;
261+ }
262+
263+ const keyListener = ( _chunk : any , key : any ) => {
264+ if ( key ) {
265+ if ( key . name === 'escape' || ( key . ctrl && key . name === 'c' ) ) {
266+ process . stdin . setRawMode ( false ) ;
267+ process . stdin . removeListener ( 'keypress' , keyListener ) ;
268+ console . log ( '\nContinuing with execution...\n' ) ;
269+ return ;
270+ }
271+
272+ if ( key . name === 'left' || key . name === 'right' || key . name === 'space' ) {
273+ if ( key . name === 'left' ) {
274+ currentModeIndex = ( currentModeIndex - 1 + MODES . length ) % MODES . length ;
275+ } else {
276+ currentModeIndex = ( currentModeIndex + 1 ) % MODES . length ;
277+ }
278+ MODE = MODES [ currentModeIndex ] ;
279+ let line = `\rCurrent mode` ;
280+ for ( const m of MODES ) {
281+ if ( m === MODE ) {
282+ line += ` [${ m } ]` ;
283+ } else {
284+ line += ` ${ m } ` ;
285+ }
286+ }
287+ process . stdout . write ( line + ' ' ) ;
288+ //
289+ //process.stdout.write(`\rCurrent mode: ${MODE} `);
290+ }
291+ }
292+ } ;
293+
294+ process . stdin . on ( 'keypress' , keyListener ) ;
295+
296+ return new Promise < void > ( ( resolve ) => {
297+ const originalListener = process . stdin . listeners ( 'keypress' ) . find ( l => l === keyListener ) ;
298+ if ( originalListener ) {
299+ const wrappedListener = ( _chunk : any , key : any ) => {
300+ keyListener ( _chunk , key ) ;
301+ if ( key && ( key . name === 'escape' || ( key . ctrl && key . name === 'c' ) ) ) {
302+ resolve ( ) ;
303+ }
304+ } ;
305+ process . stdin . removeListener ( 'keypress' , keyListener ) ;
306+ process . stdin . on ( 'keypress' , wrappedListener ) ;
307+ }
308+ } ) ;
309+ } ;
174310
175311const main = async ( ) => {
176312 // process.env.DEBUG = '*';
@@ -181,7 +317,8 @@ const main = async () => {
181317 return ;
182318 }
183319 const deviceClient = devices [ 0 ] . getClient ( ) ;
184-
320+ // await
321+ setupKeyboardInterface ( ) ;
185322 // {
186323 // let t1 = Date.now();
187324 // await testClickExec(deviceClient);
@@ -192,7 +329,7 @@ const main = async () => {
192329 if ( false ) {
193330 const promises : Promise < unknown > [ ] = [ ] ;
194331 let t2 = Date . now ( ) ;
195- promises . push ( testClickShell ( deviceClient , getCenterTapsForDevice ( deviceClient , NB_CLICK ) ) ) ;
332+ promises . push ( testClickShell ( deviceClient , getCenterTapsForDevice ( deviceClient ) ) ) ;
196333 //promises.push(testClickShell(deviceClient, getFixedCenterForDevice(deviceClient, NB_CLICK));
197334 await Promise . all ( promises ) ;
198335 t2 = Date . now ( ) - t2 ;
@@ -201,8 +338,21 @@ const main = async () => {
201338
202339 if ( true ) {
203340 let t3 = Date . now ( ) ;
204- // await testClickScrcpy(deviceClient, getCenterTapsForDevice(deviceClient, NB_CLICK, true));
205- await testClickScrcpy ( deviceClient , getGridPercent ( NB_CLICK ) ) ;
341+ const opts = {
342+ asPercent : true ,
343+ xRadius : 0.30 ,
344+ yRadius : 0.14 ,
345+ fromX : 0.08 ,
346+ fromY : 0.2 ,
347+ toX : 0.92 ,
348+ toY : 0.75 , // 0.75,
349+ stepX : 0.05 ,
350+ stepY : 0.025 ,
351+ } satisfies TapOptions ;
352+ opts . xRadius *= 0.8 ;
353+ opts . yRadius *= 0.8 ;
354+ await testClickScrcpy ( deviceClient , getCenterTapsForDevice ( deviceClient , opts ) ) ;
355+ // await testClickScrcpy(deviceClient, getGridPercent(NB_CLICK));
206356 t3 = Date . now ( ) - t3 ;
207357 console . log ( `scrcpy = ${ t3 / NB_CLICK } ` ) ;
208358 }
@@ -219,7 +369,10 @@ process.on(
219369 "exit" ,
220370 ( code ) => console . log ( "Processus is closing, exit code:" , code ) ,
221371) ;
222- process . on ( "SIGINT" , ( ) => console . log ( "SIGINT reçu" ) ) ;
372+ process . on ( "SIGINT" , ( ) => {
373+ console . log ( "SIGINT reçu" ) ;
374+ process . exit ( ) ;
375+ } ) ;
223376process . on ( "SIGTERM" , ( ) => console . log ( "SIGTERM reçu" ) ) ;
224377
225378main ( ) . catch ( ( e ) => console . error ( "ERROR" , e ) ) . finally ( ( ) => {
0 commit comments