diff --git a/tutorials/cursor.py b/tutorials/cursor.py new file mode 100644 index 000000000..93b563f28 --- /dev/null +++ b/tutorials/cursor.py @@ -0,0 +1,161 @@ +""" + mss.tutorials.cursor + ~~~~~~~~~~~~~~~~~~~ + + This python script generates the png image of the cursor for linux systems and store it in + 'tutorials/cursor_image.png.' Then, this image is used inside screenrecorder.py file. This displays + the cursor movement in screen recordings while running automated tutorials. + + This file is part of mss. + + :copyright: Copyright 2021 Hrithik Kumar Verma + :copyright: Copyright 2021 by the mss team, see AUTHORS. + :license: APACHE-2.0, see LICENSE for details. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import os +import ctypes +import ctypes.util +import numpy as np + +# A helper function to convert data from Xlib to byte array. +import struct +import array + +# Define ctypes version of XFixesCursorImage structure. +PIXEL_DATA_PTR = ctypes.POINTER(ctypes.c_ulong) +Atom = ctypes.c_ulong + + +class XFixesCursorImage(ctypes.Structure): + """ + See /usr/include/X11/extensions/Xfixes.h + typedef struct { + short x, y; + unsigned short width, height; + unsigned short xhot, yhot; + unsigned long cursor_serial; + unsigned long *pixels; + if XFIXES_MAJOR >= 2 + Atom atom; /* Version >= 2 only */ + const char *name; /* Version >= 2 only */ + endif + } XFixesCursorImage; + """ + _fields_ = [('x', ctypes.c_short), + ('y', ctypes.c_short), + ('width', ctypes.c_ushort), + ('height', ctypes.c_ushort), + ('xhot', ctypes.c_ushort), + ('yhot', ctypes.c_ushort), + ('cursor_serial', ctypes.c_ulong), + ('pixels', PIXEL_DATA_PTR), + ('atom', Atom), + ('name', ctypes.c_char_p)] + + +class Display(ctypes.Structure): + pass + + +class Xcursor: + display = None + + def __init__(self, display=None): + if not display: + try: + display = os.environ["DISPLAY"].encode('utf-8') + except KeyError: + raise Exception("$DISPLAY not set.") + + # XFixeslib = ctypes.CDLL('libXfixes.so') + XFixes = ctypes.util.find_library("Xfixes") + if not XFixes: + raise Exception("No XFixes library found.") + self.XFixeslib = ctypes.cdll.LoadLibrary(XFixes) + + # xlib = ctypes.CDLL('libX11.so.6') + x11 = ctypes.util.find_library("X11") + if not x11: + raise Exception("No X11 library found.") + self.xlib = ctypes.cdll.LoadLibrary(x11) + + # Define ctypes' version of XFixesGetCursorImage function + XFixesGetCursorImage = self.XFixeslib.XFixesGetCursorImage + XFixesGetCursorImage.restype = ctypes.POINTER(XFixesCursorImage) + XFixesGetCursorImage.argtypes = [ctypes.POINTER(Display)] + self.XFixesGetCursorImage = XFixesGetCursorImage + + XOpenDisplay = self.xlib.XOpenDisplay + XOpenDisplay.restype = ctypes.POINTER(Display) + XOpenDisplay.argtypes = [ctypes.c_char_p] + + if not self.display: + self.display = self.xlib.XOpenDisplay(display) # (display) or (None) + + def argbdata_to_pixdata(self, data, len): + if data is None or len < 1: + return None + + # Create byte array + b = array.array('b', b'\x00' * 4 * len) + + offset, i = 0, 0 + while i < len: + argb = data[i] & 0xffffffff + rgba = (argb << 8) | (argb >> 24) + b1 = (rgba >> 24) & 0xff + b2 = (rgba >> 16) & 0xff + b3 = (rgba >> 8) & 0xff + b4 = rgba & 0xff + + struct.pack_into("=BBBB", b, offset, b1, b2, b3, b4) + offset = offset + 4 + i = i + 1 + + return b + + def getCursorImageData(self): + # Call the function. Read data of cursor/mouse-pointer. + cursor_data = self.XFixesGetCursorImage(self.display) + + if not (cursor_data and cursor_data[0]): + raise Exception("Cannot read XFixesGetCursorImage()") + + # Note: cursor_data is a pointer, take cursor_data[0] + return cursor_data[0] + + def getCursorImageArray(self): + data = self.getCursorImageData() + # x, y = data.x, data.y + height, width = data.height, data.width + + bytearr = ctypes.cast(data.pixels, ctypes.POINTER(ctypes.c_ulong * height * width))[0] + imgarray = np.array(bytearray(bytearr)) + imgarray = imgarray.reshape(height, width, 8)[:, :, (0, 1, 2, 3)] + del bytearr + + return imgarray + + def saveImage(self, imgarray, text): + from PIL import Image + img = Image.fromarray(imgarray) + img.save(text) + + +if __name__ == "__main__": + cursor = Xcursor() + imgarray = cursor.getCursorImageArray() + cursor.saveImage(imgarray, 'cursor_image.png') diff --git a/tutorials/pictures/cursor_image.png b/tutorials/pictures/cursor_image.png new file mode 100644 index 000000000..c4b15bd91 Binary files /dev/null and b/tutorials/pictures/cursor_image.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/auto_update.png b/tutorials/pictures/tutorial_wms/linux/auto_update.png new file mode 100644 index 000000000..2a206bacd Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/auto_update.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/clear_cache.png b/tutorials/pictures/tutorial_wms/linux/clear_cache.png new file mode 100644 index 000000000..e1ef5b1a0 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/clear_cache.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/clear_filter.png b/tutorials/pictures/tutorial_wms/linux/clear_filter.png new file mode 100644 index 000000000..622ded99d Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/clear_filter.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/delete_layers.png b/tutorials/pictures/tutorial_wms/linux/delete_layers.png new file mode 100644 index 000000000..05878742e Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/delete_layers.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/divergence_layer.png b/tutorials/pictures/tutorial_wms/linux/divergence_layer.png new file mode 100644 index 000000000..e98b5e69e Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/divergence_layer.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/get_capabilities.png b/tutorials/pictures/tutorial_wms/linux/get_capabilities.png new file mode 100644 index 000000000..ffda0fc0e Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/get_capabilities.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/initialization.png b/tutorials/pictures/tutorial_wms/linux/initialization.png new file mode 100644 index 000000000..70f4743f2 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/initialization.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/layer_filter.png b/tutorials/pictures/tutorial_wms/linux/layer_filter.png new file mode 100644 index 000000000..f0a59b0df Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/layer_filter.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/layers.png b/tutorials/pictures/tutorial_wms/linux/layers.png new file mode 100644 index 000000000..7310f1f1b Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/layers.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/level.png b/tutorials/pictures/tutorial_wms/linux/level.png new file mode 100644 index 000000000..87255df14 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/level.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/multilayering.png b/tutorials/pictures/tutorial_wms/linux/multilayering.png new file mode 100644 index 000000000..8bdc5ac1f Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/multilayering.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/remove.png b/tutorials/pictures/tutorial_wms/linux/remove.png new file mode 100644 index 000000000..fee113d53 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/remove.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/retrieve.png b/tutorials/pictures/tutorial_wms/linux/retrieve.png new file mode 100644 index 000000000..05e503cb6 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/retrieve.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/selecttoopencontrol.png b/tutorials/pictures/tutorial_wms/linux/selecttoopencontrol.png new file mode 100644 index 000000000..45525c4b3 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/selecttoopencontrol.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/star_filter.png b/tutorials/pictures/tutorial_wms/linux/star_filter.png new file mode 100644 index 000000000..fe8d7541a Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/star_filter.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/transparent.png b/tutorials/pictures/tutorial_wms/linux/transparent.png new file mode 100644 index 000000000..4b6003e41 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/transparent.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/use_cache.png b/tutorials/pictures/tutorial_wms/linux/use_cache.png new file mode 100644 index 000000000..3df370c5c Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/use_cache.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/valid.png b/tutorials/pictures/tutorial_wms/linux/valid.png new file mode 100644 index 000000000..f21da4d8c Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/valid.png differ diff --git a/tutorials/pictures/tutorial_wms/linux/wms_url.png b/tutorials/pictures/tutorial_wms/linux/wms_url.png new file mode 100644 index 000000000..85fc46aee Binary files /dev/null and b/tutorials/pictures/tutorial_wms/linux/wms_url.png differ diff --git a/tutorials/pictures/tutorial_wms/win/auto_update.png b/tutorials/pictures/tutorial_wms/win/auto_update.png new file mode 100644 index 000000000..969aa1a77 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/auto_update.png differ diff --git a/tutorials/pictures/tutorial_wms/win/clear_cache.png b/tutorials/pictures/tutorial_wms/win/clear_cache.png new file mode 100644 index 000000000..1450d069f Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/clear_cache.png differ diff --git a/tutorials/pictures/tutorial_wms/win/delete_layers.png b/tutorials/pictures/tutorial_wms/win/delete_layers.png new file mode 100644 index 000000000..ec1d45aa2 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/delete_layers.png differ diff --git a/tutorials/pictures/tutorial_wms/win/divergence_layer.png b/tutorials/pictures/tutorial_wms/win/divergence_layer.png new file mode 100644 index 000000000..283cde2d0 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/divergence_layer.png differ diff --git a/tutorials/pictures/tutorial_wms/win/equivalent_potential_layer.png b/tutorials/pictures/tutorial_wms/win/equivalent_potential_layer.png new file mode 100644 index 000000000..dc8bcec56 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/equivalent_potential_layer.png differ diff --git a/tutorials/pictures/tutorial_wms/win/get_capabilities.png b/tutorials/pictures/tutorial_wms/win/get_capabilities.png new file mode 100644 index 000000000..403f79b3f Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/get_capabilities.png differ diff --git a/tutorials/pictures/tutorial_wms/win/initialization.png b/tutorials/pictures/tutorial_wms/win/initialization.png new file mode 100644 index 000000000..8fe2d595e Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/initialization.png differ diff --git a/tutorials/pictures/tutorial_wms/win/layer_filter.png b/tutorials/pictures/tutorial_wms/win/layer_filter.png new file mode 100644 index 000000000..e3b751b16 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/layer_filter.png differ diff --git a/tutorials/pictures/tutorial_wms/win/layers.png b/tutorials/pictures/tutorial_wms/win/layers.png new file mode 100644 index 000000000..753ea7168 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/layers.png differ diff --git a/tutorials/pictures/tutorial_wms/win/level.png b/tutorials/pictures/tutorial_wms/win/level.png new file mode 100644 index 000000000..559a28bfb Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/level.png differ diff --git a/tutorials/pictures/tutorial_wms/win/multilayering.png b/tutorials/pictures/tutorial_wms/win/multilayering.png new file mode 100644 index 000000000..696f727bf Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/multilayering.png differ diff --git a/tutorials/pictures/tutorial_wms/win/remove.png b/tutorials/pictures/tutorial_wms/win/remove.png new file mode 100644 index 000000000..7763a6864 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/remove.png differ diff --git a/tutorials/pictures/tutorial_wms/win/retrieve.png b/tutorials/pictures/tutorial_wms/win/retrieve.png new file mode 100644 index 000000000..c53518157 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/retrieve.png differ diff --git a/tutorials/pictures/selecttoopencontrol.PNG b/tutorials/pictures/tutorial_wms/win/selecttoopencontrol.png similarity index 100% rename from tutorials/pictures/selecttoopencontrol.PNG rename to tutorials/pictures/tutorial_wms/win/selecttoopencontrol.png diff --git a/tutorials/pictures/tutorial_wms/win/star_filter.png b/tutorials/pictures/tutorial_wms/win/star_filter.png new file mode 100644 index 000000000..e7b9cebb1 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/star_filter.png differ diff --git a/tutorials/pictures/tutorial_wms/win/star_layer.png b/tutorials/pictures/tutorial_wms/win/star_layer.png new file mode 100644 index 000000000..538b345e7 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/star_layer.png differ diff --git a/tutorials/pictures/tutorial_wms/win/transparent.png b/tutorials/pictures/tutorial_wms/win/transparent.png new file mode 100644 index 000000000..e8c439038 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/transparent.png differ diff --git a/tutorials/pictures/tutorial_wms/win/use_cache.png b/tutorials/pictures/tutorial_wms/win/use_cache.png new file mode 100644 index 000000000..faf40f865 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/use_cache.png differ diff --git a/tutorials/pictures/tutorial_wms/win/valid.png b/tutorials/pictures/tutorial_wms/win/valid.png new file mode 100644 index 000000000..9b205ae49 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/valid.png differ diff --git a/tutorials/pictures/tutorial_wms/win/view.png b/tutorials/pictures/tutorial_wms/win/view.png new file mode 100644 index 000000000..81145b321 Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/view.png differ diff --git a/tutorials/pictures/tutorial_wms/win/wms_url.png b/tutorials/pictures/tutorial_wms/win/wms_url.png new file mode 100644 index 000000000..ac0c6b65d Binary files /dev/null and b/tutorials/pictures/tutorial_wms/win/wms_url.png differ diff --git a/tutorials/screenrecorder.py b/tutorials/screenrecorder.py index db07f66a2..4275b71a4 100644 --- a/tutorials/screenrecorder.py +++ b/tutorials/screenrecorder.py @@ -1,5 +1,5 @@ """ - mslib.msui.screenrecorder + mss.tutorials.screenrecorder ~~~~~~~~~~~~~~~~~~~ This python script is meant for recording the screens while automated tutorials are running. @@ -29,7 +29,11 @@ import sys import time import mss +import pyautogui from PyQt5 import QtWidgets +from cursor import Xcursor +from sys import platform +from PIL import Image class ScreenRecorder: @@ -83,6 +87,59 @@ def get_fps(self): return fps def capture(self): + """ + Captures the frames of the screen at the rate of fps frames/second and writes into the + video writer object with the defined fourcc, codec and colour format. + """ + if platform == 'linux' or platform == 'linux2': + cursor = Xcursor() + cursor_imgarray = cursor.getCursorImageArray() + cursor.saveImage(cursor_imgarray, 'cursor_image.png') + mouse_pointer = Image.open('cursor_image.png') + width, height = mouse_pointer.size + elif platform == 'win32' or platform == 'darwin': + mouse_pointer = Image.open('pictures/cursor_image.png') + width, height = mouse_pointer.size + else: + print('Not supported in this platform') + mouse_pointer = None + width, height = None, None + with mss.mss() as sct: + bbox = {"top": 0, "left": 0, "width": self.width, "height": self.height} + self.start_rec_time = time.time() + frame_time_ms = 1000 / self.fps + frames = 0 + print(f"Starting to record with FPS value {self.fps} ...") + while self.record: + if platform == 'win32' or platform == 'darwin': + x, y = pyautogui.position() + elif platform == 'linux': + x, y = 1000, 500 # Fixed mouse pointer in linux at this coordinate. Throwing error of some kind. + # Hence, the mouse pointer is not visible in the recordings but is at a fixed place. + # Alternatively if you just record anything running screenrecorder.py directly this + # pyautogui.position() works perfectly in any operating system.(ofcourse you need to change the + # code by removing this platform thing). But when tutorials are called, it + # is throwing some untraceable error in Linux. + img = Image.frombytes("RGBA", sct.grab(bbox).size, sct.grab(bbox).bgra, "raw", "RGBA") + img.paste(mouse_pointer, (x, y, x + width, y + height), mask=mouse_pointer) + img_np = np.array(img) + img_final = cv2.cvtColor(img_np, cv2.COLOR_RGBA2RGB) + cv2.imshow(self.window_name, img_final) + self.recorded_video.write(img_final) + frames += 1 + expected_frames = ((time.time() - self.start_rec_time) * 1000) / frame_time_ms + surplus = frames - expected_frames + + # Duplicate previous frame to meet FPS quota. Consider lowering the FPS instead! + if int(surplus) <= -1: + frames -= int(surplus) + for i in range(int(-surplus)): + self.recorded_video.write(img_final) + # Exits the screen capturing when user press 'q' + if cv2.waitKey(max(int(surplus * frame_time_ms), 1)) & 0xFF == ord('q'): + break + + def capture2(self): """ Captures the frames of the screen at the rate of fps frames/second and writes into the video writer object with the defined fourcc, codec and colour format. diff --git a/tutorials/tutorial_waypoints.py b/tutorials/tutorial_waypoints.py index 0a248b671..ab16ae77b 100644 --- a/tutorials/tutorial_waypoints.py +++ b/tutorials/tutorial_waypoints.py @@ -1,5 +1,5 @@ """ - mslib.msui.tutorial_waypoints + mss.tutorials.tutorial_waypoints ~~~~~~~~~~~~~~~~~~~ This python script generates an automatic demonstration of how to play with and use waypoints @@ -220,7 +220,7 @@ def automate_waypoints(): pag.write(fig_filename, interval=0.25) pag.press('enter', interval=1) if platform == 'linux' or platform == 'linux2': - # pag.hotkey('altleft', 'tab') if the save file system window is not in the forefront, use this statement. + pag.hotkey('altleft', 'tab') # if the save file system window is not in the forefront, use this statement. # This can happen sometimes. At that time, you just need to uncomment it. pag.write(fig_filename, interval=0.25) pag.press('enter', interval=1) diff --git a/tutorials/tutorial_wms.py b/tutorials/tutorial_wms.py new file mode 100644 index 000000000..1b79d8262 --- /dev/null +++ b/tutorials/tutorial_wms.py @@ -0,0 +1,500 @@ +""" + mss.tutorials.tutorial_wms + ~~~~~~~~~~~~~~~~~~~ + + This python script generates an automatic demonstration of how to use the web map service section of Mission + Support System and plan flighttracks accordingly. + + This file is part of mss. + + :copyright: Copyright 2021 Hrithik Kumar Verma + :copyright: Copyright 2021 by the mss team, see AUTHORS. + :license: APACHE-2.0, see LICENSE for details. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import pyautogui as pag +import multiprocessing +import sys +from sys import platform +from pyscreeze import ImageNotFoundException +from tutorials import screenrecorder as sr +from mslib.msui import mss_pyui + + +def initial_ops(): + """ + Executes the initial operations such as closing all opened windows and showing the desktop. + """ + pag.sleep(5) + if platform == "linux" or platform == "linux2": + pag.hotkey('winleft', 'd') + print("\n INFO : Automation is running on Linux system..\n") + elif platform == "darwin": + pag.hotkey('option', 'command', 'm') + print("\n INFO : Automation is running on Mac OS..\n") + elif platform == "win32": + pag.hotkey('win', 'd') + print("\n INFO : Automation is running on Windows OS..\n") + else: + pag.alert(text="Sorry, no support on this platform!", title="Platform Exception", button='OK') + + +def call_recorder(): + """ + Calls the screen recorder class to start the recording of the automation. + """ + sr.main() + + +def call_mss(): + """ + Calls the main MSS GUI window since operations are to be performed on it only. + """ + mss_pyui.main() + + +def automate_waypoints(): + """ + This is the main automating script of the MSS waypoints tutorial which will be recorded and saved + to a file having dateframe nomenclature with a .mp4 extension(codec). + """ + # Giving time for loading of the MSS GUI. + pag.sleep(5) + + if platform == 'linux' or platform == 'linux2' or platform == 'darwin': + dir_path = 'pictures/tutorial_wms/linux/' + elif platform == 'win32': + dir_path = 'pictures/tutorial_wms/win/' + + # Maximizing the window + try: + if platform == 'linux' or platform == 'linux2': + pag.hotkey('winleft', 'up') + elif platform == 'darwin': + pag.hotkey('ctrl', 'command', 'f') + elif platform == 'win32': + pag.hotkey('win', 'up') + except Exception: + print("\nException : Enable Shortcuts for your system or try again!") + pag.sleep(2) + pag.hotkey('ctrl', 'h') + pag.sleep(1) + + # Opening web map service + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}selecttoopencontrol.png') + pag.click(x, y, interval=2) + pag.press('down', interval=1) + if platform == 'linux' or platform == 'linux2' or platform == 'win32': + pag.press('enter', interval=1) + elif platform == 'darwin': + pag.press('return', interval=1) + pag.move(None, -777, duration=1) + if platform == 'win32': + pag.dragRel(400, None, duration=2) + elif platform == 'linux' or platform == 'linux2' or platform == 'darwin': + pag.dragRel(800, None, duration=2) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\'select to open control\' button/option not found on the screen.") + + # Locating Server Layer + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}layers.png') + pag.click(x, y, interval=2) + if platform == 'win32': + pag.move(35, -485, duration=1) + pag.dragRel(-800, -60, duration=2) + elif platform == 'linux' or platform == 'linux2' or platform == 'darwin': + pag.move(35, -522, duration=1) + pag.dragRel(-800, -30, duration=2) + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Server\\Layers\' button/option not found on the screen.") + + # Entering wms URL + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}wms_url.png') + pag.click(x + 220, y, interval=2) + pag.hotkey('ctrl', 'a', interval=1) + pag.write('http://open-mss.org/', interval=0.25) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'WMS URL\' editbox button/option not found on the screen.") + + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}get_capabilities.png') + pag.click(x, y, interval=2) + pag.sleep(3) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Get capabilities\' button/option not found on the screen.") + + # Selecting some layers + if platform == 'win32': + gap = 22 + elif platform == 'linux' or platform == 'linux2' or platform == 'darwin': + gap = 18 + + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}divergence_layer.png') + temp1, temp2 = x, y + pag.click(x, y, interval=2) + pag.sleep(1) + pag.move(None, gap, duration=1) + pag.click(interval=1) + pag.sleep(1) + pag.move(None, gap * 2, duration=1) + pag.click(interval=1) + pag.sleep(1) + pag.move(None, gap, duration=1) + pag.click(interval=1) + pag.sleep(1) + pag.move(None, -gap * 4, duration=1) + pag.click(interval=1) + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Divergence Layer\' option not found on the screen.") + + # Filter layer + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}layer_filter.png') + pag.click(x + 150, y, interval=2) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Layer filter editbox\' button/option not found on the screen.") + if x is not None and y is not None: + pag.write('temperature', interval=0.25) + pag.moveTo(temp1, temp2, duration=1) + pag.click(interval=2) + pag.sleep(1) + pag.move(None, gap, duration=1) + pag.click(interval=2) + pag.sleep(1) + + # Clearing filter + pag.moveTo(x + 150, y, duration=1) + pag.click(interval=1) + if platform == 'linux' or platform == 'linux2' or platform == 'win32': + pag.press('backspace', presses=11, interval=0.25) + elif platform == 'darwin': + pag.press('delete', presses=11, interval=0.25) + pag.sleep(1) + + # Multilayering + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}multilayering.png') + pag.moveTo(x, y, duration=2) + pag.move(-48, None) + pag.click() + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Multilayering Checkbox\' button/option not found on the screen.") + + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}divergence_layer.png') + if platform == 'win32': + pag.moveTo(x - 268, y, duration=2) + elif platform == 'linux' or platform == 'linux2' or platform == 'darwin': + pag.moveTo(x - 248, y, duration=2) + pag.click(interval=1) + pag.sleep(2) + pag.move(None, gap * 4, duration=1) + pag.click(interval=1) + pag.sleep(2) + pag.move(None, -gap * 4, duration=1) + pag.click(interval=1) + pag.sleep(2) + pag.move(None, gap * 4, duration=1) + pag.click(interval=1) + pag.sleep(2) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Divergence layer multilayering checkbox\' option not found on the screen.") + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}multilayering.png') + pag.moveTo(x, y, duration=2) + pag.move(-48, None) + pag.click() + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Multilayering Checkbox\' button/option not found on the screen.") + + # Starring the layers + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}divergence_layer.png') + if platform == 'win32': + pag.moveTo(x - 255, y, duration=2) + elif platform == 'linux' or platform == 'linux2' or platform == 'darwin': + pag.moveTo(x - 231, y, duration=2) + pag.click(interval=1) + pag.sleep(1) + pag.move(None, gap * 4, duration=1) + pag.click(interval=1) + pag.sleep(1) + pag.move(None, -gap, duration=1) + pag.click(interval=1) + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Divergence layer star\' button/option not found on the screen.") + + # Filtering starred layers. + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}star_filter.png') + pag.click(x, y, interval=2) + pag.click(temp1, temp2, duration=1) + pag.sleep(1) + pag.move(None, gap, duration=1) + pag.click(interval=1) + pag.sleep(1) + pag.move(None, gap, duration=1) + pag.click(interval=1) + pag.sleep(1) + pag.moveTo(x - 20, y, duration=1) + pag.click(interval=1) + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Starred filter\' button/option not found on the screen.") + + # Setting different levels and valid time + if temp1 is not None and temp2 is not None: + pag.click(temp1, temp2 + (gap * 4), interval=2) + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}level.png') + pag.click(x + 200, y, interval=2) + pag.move(None, 20, duration=1) + pag.click(interval=1) + pag.sleep(3) + pag.click(x + 200, y, interval=1) + pag.move(None, 100, duration=1) + pag.click(interval=1) + pag.sleep(3) + pag.click(x + 200, y, interval=1) + pag.move(None, 140, duration=1) + pag.click(interval=1) + pag.sleep(3) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Pressure level\' button/option not found on the screen.") + + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}initialization.png') + initx, inity = x, y + pag.click(x + 200, y, interval=1) + pag.sleep(1) + pag.click(x + 200, y, interval=1) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Initialization\' button/option not found on the screen.") + + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}valid.png') + validx, validy = x, y + pag.click(x + 200, y, interval=2) + pag.move(None, 20, duration=1) + pag.click(interval=1) + pag.sleep(3) + pag.click(x + 200, y, interval=1) + pag.move(None, 80, duration=1) + pag.click(interval=1) + pag.sleep(3) + except (ImageNotFoundException, OSError, Exception): + print("\nException : \'Valid till\' button/option not found on the screen.") + + # Time gap for initialization and valid + if initx is not None and inity is not None and validx is not None and validy is not None: + pag.click(initx + 818, inity, interval=2) + pag.press('up', presses=5, interval=0.25) + pag.press('down', presses=3, interval=0.25) + if platform == 'linux' or platform == 'linux2' or platform == 'win32': + pag.press('enter') + elif platform == 'darwin': + pag.press('return') + + pag.click(validx + 833, validy, interval=2) + pag.press('up', presses=5, interval=0.20) + pag.press('down', presses=6, interval=0.20) + if platform == 'linux' or platform == 'linux2' or platform == 'win32': + pag.press('enter') + elif platform == 'darwin': + pag.press('return') + + # Previous and Next of Initial(Initialization) values + pag.click(initx + 753, inity, clicks=2, interval=2) + pag.click(initx + 882, inity, clicks=2, interval=2) + + # Previous and Next of Valid values + pag.click(validx + 760, validy, clicks=4, interval=4) + pag.click(validx + 887, validy, clicks=4, interval=4) + + # Auto-update feature of wms + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}auto_update.png') + pag.click(x - 53, y, interval=2) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\' auto update checkbox\' button/option not found on the screen.") + if temp1 is not None and temp2 is not None: + pag.click(temp1, temp2, interval=1) + try: + retx, rety = pag.locateCenterOnScreen(f'{dir_path}retrieve.png') + pag.click(retx, rety, interval=2) + pag.sleep(3) + pag.click(temp1, temp2 + (gap * 4), interval=2) + pag.click(retx, rety, interval=2) + pag.sleep(3) + pag.click(x - 53, y, interval=2) + pag.click(temp1, temp2, interval=2) + pag.sleep(2) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\' retrieve\' button/option not found on the screen.") + + # Using and not using Cache + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}use_cache.png') + pag.click(x - 46, y, interval=2) + pag.click(temp1, temp2, interval=2) + pag.sleep(4) + pag.click(temp1, temp2 + (gap * 4), interval=2) + pag.sleep(4) + pag.click(x - 46, y, interval=2) + pag.click(temp1, temp2 + (gap * 2), interval=2) + pag.sleep(2) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\'Use Cache checkbox\' button/option not found on the screen.") + + # Clearing cache. The layers load slower + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}clear_cache.png') + pag.click(x, y, interval=2) + if platform == 'linux' or platform == 'linux2' or platform == 'win32': + pag.press('enter', interval=1) + elif platform == 'darwin': + pag.press('return', interval=1) + pag.click(temp1, temp2, interval=2) + pag.sleep(4) + pag.click(temp1, temp2 + (gap * 4), interval=2) + pag.sleep(4) + pag.click(temp1, temp2 + (gap * 2), interval=2) + pag.sleep(4) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\'Clear cache\' button/option not found on the screen.") + + # Transparent layer + if temp1 is not None and temp2 is not None: + pag.click(temp1, temp2, interval=2) + pag.sleep(1) + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}transparent.png') + pag.click(x - 53, y, interval=2) + if retx is not None and rety is not None: + pag.click(retx, rety, interval=2) + pag.sleep(1) + pag.click(x - 53, y, interval=2) + pag.click(temp1, temp2, interval=2) + pag.click(retx, rety, interval=2) + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\'Transparent Checkbox\' button/option not found on the screen.") + + # Removing a Layer from the map + if temp1 is not None and temp2 is not None: + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}remove.png') + pag.click(x, y, interval=2) + pag.sleep(1) + pag.click(temp1, temp2 + (gap * 4), interval=2) + pag.click(x, y, interval=2) + pag.sleep(1) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\'Transparent Checkbox\' button/option not found on the screen.") + + # Deleting All layers + try: + x, y = pag.locateCenterOnScreen(f'{dir_path}delete_layers.png') + if platform == 'win32': + pag.click(x - 74, y, interval=2) + elif platform == 'linux' or platform == 'linux2' or platform == 'darwin': + pag.click(x - 70, y, interval=2) + pag.sleep(1) + x1, y1 = pag.locateCenterOnScreen(f'{dir_path}get_capabilities.png') + pag.click(x1, y1, interval=2) + pag.sleep(3) + except (ImageNotFoundException, OSError, Exception): + print("\nException :\'Deleting all layers bin\' button/option not found on the screen.") + + print("\nAutomation is over for this tutorial. Watch next tutorial for other functions.") + + # Close Everything! + try: + if platform == 'linux' or platform == 'linux2': + pag.hotkey('altleft', 'f4', interval=1) + for _ in range(2): + pag.hotkey('altleft', 'f4') + pag.sleep(1) + pag.press('left') + pag.sleep(1) + pag.press('enter') + pag.sleep(1) + pag.keyDown('altleft') + pag.press('tab') + pag.press('left') + pag.keyUp('altleft') + pag.press('q') + if platform == 'win32': + pag.hotkey('alt', 'f4', interval=1) + for _ in range(2): + pag.hotkey('alt', 'f4') + pag.sleep(1) + pag.press('left') + pag.sleep(1) + pag.press('enter') + pag.sleep(1) + pag.hotkey('alt', 'tab') + pag.press('q') + elif platform == 'darwin': + pag.hotkey('command', 'w', interval=1) + for _ in range(2): + pag.hotkey('command', 'w') + pag.sleep(1) + pag.press('left') + pag.sleep(1) + pag.press('return') + pag.sleep(1) + pag.hotkey('command', 'tab') + pag.press('q') + except Exception: + print("Cannot automate : Enable Shortcuts for your system or try again") + # pag.press('q') # In some cases, recording windows does not closes. So it needs to ne there. + + +def main(): + """ + This function runs the above functions as different processes at the same time and can be + controlled from here. (This is the main process.) + """ + p1 = multiprocessing.Process(target=call_mss) + p2 = multiprocessing.Process(target=automate_waypoints) + p3 = multiprocessing.Process(target=call_recorder) + + print("\nINFO : Starting Automation.....\n") + p3.start() + pag.sleep(5) + initial_ops() + p1.start() + p2.start() + + p2.join() + p1.join() + p3.join() + print("\n\nINFO : Automation Completes Successfully!") + # pag.press('q') # In some cases, recording windows does not closes. So it needs to ne there. + sys.exit() + + +if __name__ == '__main__': + main()