#!/usr/bin/env python3 import json, os, socket, struct, subprocess, tempfile, time from pathlib import Path stage=Path(os.environ.get('CUBE_TEST_STAGE', '/var/tmp/wayfire-cube-repeat')) runtime=Path(tempfile.mkdtemp(prefix='cube-repeat-')) env=os.environ.copy() for k in ('WAYLAND_DISPLAY','DISPLAY','WAYFIRE_SOCKET','_WAYFIRE_SOCKET','WAYFIRE_CONFIG_FILE','WAYFIRE_DEFAULT_CONFIG_BACKEND'): env.pop(k,None) env.update(XDG_RUNTIME_DIR=str(runtime),XDG_DATA_HOME=str(runtime/'data'),WLR_BACKENDS='headless',WLR_HEADLESS_OUTPUTS='3',WLR_RENDERER='gles2',WLR_RENDER_DRM_DEVICE='/dev/dri/renderD128',WAYFIRE_PLUGIN_PATH=str(stage/'plugins'),WAYFIRE_PLUGIN_XML_PATH=str(stage/'metadata')) config=runtime/'wayfire.ini' config.write_text('''[core] plugins = ipc ipc-rules stipc cube xwayland = false stitch_enabled = true stitch_outputs = HEADLESS-1 HEADLESS-2 HEADLESS-3 vwidth = 16 vheight = 1 [cube] rotate_left = KEY_LEFT | KEY_LEFT rotate_right = KEY_RIGHT | KEY_RIGHT [autostart] autostart_wf_shell = false [output:HEADLESS-1] mode = 320x240@60 position = 0,0 [output:HEADLESS-2] mode = 320x240@60 position = 320,0 [output:HEADLESS-3] mode = 320x240@60 position = 640,0 ''') log=(runtime/'wayfire.log').open('w') process=subprocess.Popen(['/usr/bin/wayfire','-c',str(config)],env=env,stdout=log,stderr=log) def ipc(method,data=None): with socket.socket(socket.AF_UNIX) as s: s.settimeout(5);s.connect(str(sock)) b=json.dumps({'method':method,'data':data or {}}).encode();s.sendall(struct.pack('8 and .50gaps[-1]*2 print('PASS slow-to-fast acceleration and arrow release',flush=True) press();watch(1.4);key('KEY_LEFTMETA',False);stable();key('KEY_RIGHT',False) print('PASS modifier release stops repeat',flush=True) press();assert not watch(.40);release();stable() print('PASS next hold starts with a fresh delay',flush=True) before=ws() for k in ['KEY_LEFTCTRL','KEY_LEFTALT','KEY_RIGHT']:key(k,True) assert ws()==(before+1)%16 assert watch(.8), 'alternate binding did not repeat' for k in ['KEY_RIGHT','KEY_LEFTALT','KEY_LEFTCTRL']:key(k,False) stable() print('PASS Ctrl+Alt alternate binding also repeats',flush=True) press();watch(.8);key('KEY_A',True);stable();key('KEY_A',False);release() print('PASS unrelated key stops the held shortcut',flush=True) options(**{'cube/repeat_acceleration':False,'cube/repeat_interval':300,'cube/repeat_delay':250}) press('KEY_LEFT');changes=watch(1.6);release('KEY_LEFT');stable() gaps=[changes[i+1][0]-changes[i][0] for i in range(len(changes)-1)] assert len(gaps)>=3 and all(.24