commit f9c2f8f543719844056aff426d74144a5a8308a8 Author: Christopher Vagnetoft Date: Mon Dec 26 20:54:28 2016 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..61ead86 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..a1190f6 --- /dev/null +++ b/composer.json @@ -0,0 +1,17 @@ +{ + "name": "noccylabs/x11", + "description": "Interact with windows on Linux/X11", + "type": "library", + "license": "GPL-3.0", + "authors": [ + { + "name": "Christopher Vagnetoft", + "email": "cvagnetoft@gmail.com" + } + ], + "autoload": { + "psr-4": { + "NoccyLabs\\X11\\": "src/" + } + } +} \ No newline at end of file diff --git a/examples/find_windows.php b/examples/find_windows.php new file mode 100644 index 0000000..9dbd4cc --- /dev/null +++ b/examples/find_windows.php @@ -0,0 +1,20 @@ +dump(); + +// Select all the windows with a title matching *code* +$windows = $windows->visible()->find("*code*"); +$windows->dump(); + +// Grab the first window +$window = $windows->first(); +$window->dump(); + +// Focus the window and simulate F1 being pressed +$window->focus()->sendKeys("F1"); diff --git a/examples/select_window.php b/examples/select_window.php new file mode 100644 index 0000000..68a109a --- /dev/null +++ b/examples/select_window.php @@ -0,0 +1,11 @@ +select(); +$window->dump(); diff --git a/examples/self_keys.php b/examples/self_keys.php new file mode 100644 index 0000000..84dbc40 --- /dev/null +++ b/examples/self_keys.php @@ -0,0 +1,8 @@ +sendKeys("l s Return", true); diff --git a/src/Window.php b/src/Window.php new file mode 100644 index 0000000..2386d18 --- /dev/null +++ b/src/Window.php @@ -0,0 +1,97 @@ +windowId = $id; + $this->readWindowInfo(); + } + + private function readWindowInfo() + { + exec("xwininfo -id {$this->windowId} -all -children", $output, $status); + foreach ($output as $line) { + if (preg_match('/^(.+?): (.+?)$/', trim($line), $match)) { + switch ($match[1]) { + case 'xwininfo': + if (preg_match('/Window id: .+? "(.+?)"/', $match[2], $m)) { + $this->windowTitle = $m[1]; + } + break; + case 'Map State': + $this->isVisible = ($match[2]=='IsViewable'); + break; + default: + //printf("[%s]->'%s'\n", $match[1], $match[2]); + } + } + } + //printf("---\n"); + } + + public function getId() + { + return hexdec($this->windowId); + } + + public function isVisible() + { + return $this->isVisible; + } + + public function getWindowTitle() + { + return $this->windowTitle; + } + + public function sendKeys($keys, $forceFocus=false) + { + if ($forceFocus) { + $this->focus(); + $cmdl = sprintf("xdotool key %s", $keys); + } else { + $cmdl = sprintf("xdotool key --delay 100 --window %d %s", $this->windowId, $keys); + } + echo "$ {$cmdl}\n"; + exec($cmdl); + return $this; + } + + public function focus() + { + $cmdl = sprintf("xdotool windowfocus %d", $this->windowId); + echo "$ {$cmdl}\n"; + exec($cmdl); + return $this; + } + + public function activate() + { + $cmdl = sprintf("xdotool windowactivate %d", $this->windowId); + echo "$ {$cmdl}\n"; + exec($cmdl); + return $this; + } + + public function dump() + { + printf("Window: (id=0x%08x)\n Title: %s\n Visible: %s\n", + $this->windowId, + $this->windowTitle, + $this->isVisible?'true':'false' + ); + } +} diff --git a/src/WindowList.php b/src/WindowList.php new file mode 100644 index 0000000..a5ea0c8 --- /dev/null +++ b/src/WindowList.php @@ -0,0 +1,88 @@ +readRootWindowTree(); + } elseif (is_array($windows)) { + $this->windows = $windows; + } + } + + public function getIterator() + { + return new ArrayIterator($this->windows); + } + + public function count() + { + return count($this->windows); + } + + private function readRootWindowTree() + { + exec("xwininfo -root -tree", $output, $status); + $this->windows = []; + foreach ($output as $line) { + if (preg_match('/^\s+0x([0-9a-f]+?) (.+?)\: \((.+?)\)/', $line, $match)) { + $this->windows[] = new Window(hexdec($match[1])); + } + } + } + + public function find($title) + { + $found = []; + foreach ($this->windows as $window) { + if (fnmatch($title, $window->getWindowTitle(), FNM_CASEFOLD)) { + $found[] = $window; + } + } + return new WindowList($found); + } + + public function findByClass($class) + { + $found = []; + return new WindowList($found); + } + + public function getRootWindow() + { + + } + + public function visible() + { + $found = []; + foreach ($this->windows as $window) { + if ($window->isVisible()) + $found[] = $window; + } + return new WindowList($found); + } + + public function first() + { + return count($this->windows)?$this->windows[0]:null; + } + + public function dump() + { + printf("WindowList: (count=%d)\n", count($this)); + foreach ($this as $window) { + printf(" 0x%08x: %s %s\n", $window->getId(), $window->getWindowTitle(), $window->isVisible()?'(Visible)':''); + } + } +} diff --git a/src/WindowSelector.php b/src/WindowSelector.php new file mode 100644 index 0000000..f3a777b --- /dev/null +++ b/src/WindowSelector.php @@ -0,0 +1,17 @@ +