|
|
@@ -146,34 +146,110 @@ async function libreofficeWinId(): Promise<string> {
|
|
|
return run("xdotool", ["search", "--name", "LibreOffice Impress"]);
|
|
|
}
|
|
|
|
|
|
+// Navigate via UNO PresentationController (slideshow mode)
|
|
|
+// or fall back to xdotool if not in slideshow
|
|
|
+function pyUnoNav(direction: "next" | "prev" | "start" | "end"): Promise<string> {
|
|
|
+ const actions: Record<string, string> = {
|
|
|
+ next: `
|
|
|
+ if hasattr(controller, 'gotoNextSlide'):
|
|
|
+ controller.gotoNextSlide()
|
|
|
+ elif hasattr(controller, 'gotoNextEffect'):
|
|
|
+ controller.gotoNextEffect()
|
|
|
+ else:
|
|
|
+ raise Exception("no next method on controller")
|
|
|
+ `,
|
|
|
+ prev: `
|
|
|
+ if hasattr(controller, 'gotoPreviousSlide'):
|
|
|
+ controller.gotoPreviousSlide()
|
|
|
+ elif hasattr(controller, 'gotoPreviousEffect'):
|
|
|
+ controller.gotoPreviousEffect()
|
|
|
+ else:
|
|
|
+ raise Exception("no prev method on controller")
|
|
|
+ `,
|
|
|
+ start: `
|
|
|
+ pres = comp.Presentation
|
|
|
+ pres.start()
|
|
|
+ import time; time.sleep(1.2)
|
|
|
+ # re-fetch controller after slideshow starts
|
|
|
+ controller = comp.getCurrentController()
|
|
|
+ `,
|
|
|
+ end: `
|
|
|
+ if hasattr(controller, 'deactivate'):
|
|
|
+ controller.deactivate()
|
|
|
+ else:
|
|
|
+ pres = comp.Presentation
|
|
|
+ pres.end()
|
|
|
+ `,
|
|
|
+ };
|
|
|
+
|
|
|
+ return pyUno(`
|
|
|
+import sys, time
|
|
|
+try:
|
|
|
+ import uno
|
|
|
+ from com.sun.star.beans import PropertyValue
|
|
|
+ localCtx = uno.getComponentContext()
|
|
|
+ resolver = localCtx.ServiceManager.createInstanceWithContext(
|
|
|
+ "com.sun.star.bridge.UnoUrlResolver", localCtx)
|
|
|
+ ctx = resolver.resolve(
|
|
|
+ "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
|
|
|
+ smgr = ctx.ServiceManager
|
|
|
+ desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
|
|
|
+ comp = desktop.getCurrentComponent()
|
|
|
+ controller = comp.getCurrentController()
|
|
|
+ print(f"[nav] controller type: {type(controller).__name__}", file=sys.stderr)
|
|
|
+ ${actions[direction]}
|
|
|
+ time.sleep(0.3)
|
|
|
+ # read position after nav
|
|
|
+ controller = comp.getCurrentController()
|
|
|
+ draw = comp.DrawPages
|
|
|
+ total = draw.Count
|
|
|
+ current = 0
|
|
|
+ if hasattr(controller, 'getCurrentSlideIndex'):
|
|
|
+ current = controller.getCurrentSlideIndex() + 1
|
|
|
+ print(f"[nav] slideshow mode after ${direction}, index={current}", file=sys.stderr)
|
|
|
+ elif hasattr(controller, 'getCurrentPage'):
|
|
|
+ page = controller.getCurrentPage()
|
|
|
+ for i in range(draw.Count):
|
|
|
+ if draw.getByIndex(i) == page:
|
|
|
+ current = i + 1
|
|
|
+ break
|
|
|
+ print(f"[nav] editor mode after ${direction}, index={current}", file=sys.stderr)
|
|
|
+ print(f"{current}/{total}")
|
|
|
+except Exception as e:
|
|
|
+ import traceback
|
|
|
+ print(f"[nav] error: {e}", file=sys.stderr)
|
|
|
+ traceback.print_exc(file=sys.stderr)
|
|
|
+ print("0/0")
|
|
|
+`);
|
|
|
+}
|
|
|
+
|
|
|
const LinuxDriver: Driver = {
|
|
|
async next() {
|
|
|
- const wid = (await libreofficeWinId()).split("\n")[0].trim();
|
|
|
- await run("xdotool", ["key", "--window", wid, "Right"]);
|
|
|
- await Bun.sleep(300);
|
|
|
- return LinuxDriver.status();
|
|
|
+ console.log("[linux] next: navigating via UNO");
|
|
|
+ const raw = await pyUnoNav("next");
|
|
|
+ console.log(`[linux] next raw: "${raw}"`);
|
|
|
+ return parseSlide(raw);
|
|
|
},
|
|
|
|
|
|
async prev() {
|
|
|
- const wid = (await libreofficeWinId()).split("\n")[0].trim();
|
|
|
- await run("xdotool", ["key", "--window", wid, "Left"]);
|
|
|
- await Bun.sleep(300);
|
|
|
- return LinuxDriver.status();
|
|
|
+ console.log("[linux] prev: navigating via UNO");
|
|
|
+ const raw = await pyUnoNav("prev");
|
|
|
+ console.log(`[linux] prev raw: "${raw}"`);
|
|
|
+ return parseSlide(raw);
|
|
|
},
|
|
|
|
|
|
async start() {
|
|
|
- // F5 starts the slideshow from the beginning; Shift+F5 from current slide
|
|
|
- const wid = (await libreofficeWinId()).split("\n")[0].trim();
|
|
|
- await run("xdotool", ["key", "--window", wid, "shift+F5"]);
|
|
|
- await Bun.sleep(1000);
|
|
|
- return LinuxDriver.status();
|
|
|
+ console.log("[linux] start: starting presentation via UNO");
|
|
|
+ const raw = await pyUnoNav("start");
|
|
|
+ console.log(`[linux] start raw: "${raw}"`);
|
|
|
+ return parseSlide(raw);
|
|
|
},
|
|
|
|
|
|
async end() {
|
|
|
- const wid = (await libreofficeWinId()).split("\n")[0].trim();
|
|
|
- await run("xdotool", ["key", "--window", wid, "Escape"]);
|
|
|
- await Bun.sleep(300);
|
|
|
- const { total } = await LinuxDriver.status();
|
|
|
+ console.log("[linux] end: ending presentation via UNO");
|
|
|
+ const raw = await pyUnoNav("end");
|
|
|
+ console.log(`[linux] end raw: "${raw}"`);
|
|
|
+ const { total } = parseSlide(raw);
|
|
|
return { current: 0, total };
|
|
|
},
|
|
|
|