mouse_and_screen_resolution.py (6354B)
1 #! /usr/bin/env python 2 # This Source Code Form is subject to the terms of the Mozilla Public 3 # License, v. 2.0. If a copy of the MPL was not distributed with this 4 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 # 6 # Script name: mouse_and_screen_resolution.py 7 # Purpose: Sets mouse position and screen resolution for Windows 7 32-bit slaves 8 # Author(s): Zambrano Gasparnian, Armen <armenzg@mozilla.com> 9 # Target: Python 2.7 or newer 10 # 11 12 import os 13 import platform 14 import socket 15 import sys 16 import time 17 from ctypes import Structure, byref, c_ulong, windll 18 from optparse import OptionParser 19 20 try: 21 from urllib2 import urlopen, URLError, HTTPError 22 except ImportError: 23 from urllib.request import urlopen 24 from urllib.error import URLError, HTTPError 25 try: 26 import json 27 except: 28 import simplejson as json 29 30 default_screen_resolution = {"x": 1024, "y": 768} 31 default_mouse_position = {"x": 1010, "y": 10} 32 33 34 def wfetch(url, retries=5): 35 while True: 36 try: 37 return urlopen(url, timeout=30).read() 38 except HTTPError as e: 39 print("Failed to fetch '%s': %s" % (url, str(e))) 40 except URLError as e: 41 print("Failed to fetch '%s': %s" % (url, str(e))) 42 except socket.timeout as e: 43 print("Time out accessing %s: %s" % (url, str(e))) 44 except socket.error as e: 45 print("Socket error when accessing %s: %s" % (url, str(e))) 46 if retries < 0: 47 raise Exception("Could not fetch url '%s'" % url) 48 retries -= 1 49 print("Retrying") 50 time.sleep(60) 51 52 53 def main(): 54 # NOTE: this script was written for windows 7, but works well with windows 10 55 parser = OptionParser() 56 parser.add_option( 57 "--configuration-url", 58 dest="configuration_url", 59 type="string", 60 help="Specifies the url of the configuration file.", 61 ) 62 parser.add_option( 63 "--configuration-file", 64 dest="configuration_file", 65 type="string", 66 help="Specifies the path to the configuration file.", 67 ) 68 parser.add_option( 69 "--platform", 70 dest="platform", 71 type="string", 72 default="win7", 73 help="Specifies the platform to coose inside the configuratoin-file.", 74 ) 75 (options, args) = parser.parse_args() 76 77 if options.configuration_url == None and options.configuration_file == None: 78 print("You must specify --configuration-url or --configuration-file.") 79 return 1 80 81 if options.configuration_file: 82 with open(options.configuration_file) as f: 83 conf_dict = json.load(f) 84 new_screen_resolution = conf_dict[options.platform]["screen_resolution"] 85 new_mouse_position = conf_dict[options.platform]["mouse_position"] 86 else: 87 try: 88 conf_dict = json.loads(wfetch(options.configuration_url)) 89 new_screen_resolution = conf_dict[options.platform]["screen_resolution"] 90 new_mouse_position = conf_dict[options.platform]["mouse_position"] 91 except HTTPError as e: 92 print( 93 "This branch does not seem to have the configuration file %s" % str(e) 94 ) 95 print("Let's fail over to 1024x768.") 96 new_screen_resolution = default_screen_resolution 97 new_mouse_position = default_mouse_position 98 except URLError as e: 99 print("INFRA-ERROR: We couldn't reach hg.mozilla.org: %s" % str(e)) 100 return 1 101 except Exception as e: 102 print("ERROR: We were not expecting any more exceptions: %s" % str(e)) 103 return 1 104 105 current_screen_resolution = queryScreenResolution() 106 print("Screen resolution (current): (%(x)s, %(y)s)" % (current_screen_resolution)) 107 108 if current_screen_resolution == new_screen_resolution: 109 print("No need to change the screen resolution.") 110 else: 111 print("Changing the screen resolution...") 112 try: 113 changeScreenResolution( 114 new_screen_resolution["x"], new_screen_resolution["y"] 115 ) 116 except Exception as e: 117 print( 118 "INFRA-ERROR: We have attempted to change the screen resolution but ", 119 "something went wrong: %s" % str(e), 120 ) 121 return 1 122 time.sleep(3) # just in case 123 current_screen_resolution = queryScreenResolution() 124 print("Screen resolution (new): (%(x)s, %(y)s)" % current_screen_resolution) 125 126 print("Mouse position (current): (%(x)s, %(y)s)" % (queryMousePosition())) 127 setCursorPos(new_mouse_position["x"], new_mouse_position["y"]) 128 current_mouse_position = queryMousePosition() 129 print("Mouse position (new): (%(x)s, %(y)s)" % (current_mouse_position)) 130 131 if ( 132 current_screen_resolution != new_screen_resolution 133 or current_mouse_position != new_mouse_position 134 ): 135 print( 136 "INFRA-ERROR: The new screen resolution or mouse positions are not what we expected" 137 ) 138 return 1 139 else: 140 return 0 141 142 143 class POINT(Structure): 144 _fields_ = [("x", c_ulong), ("y", c_ulong)] 145 146 147 def queryMousePosition(): 148 pt = POINT() 149 windll.user32.GetCursorPos(byref(pt)) 150 return {"x": pt.x, "y": pt.y} 151 152 153 def setCursorPos(x, y): 154 windll.user32.SetCursorPos(x, y) 155 156 157 def queryScreenResolution(): 158 return { 159 "x": windll.user32.GetSystemMetrics(0), 160 "y": windll.user32.GetSystemMetrics(1), 161 } 162 163 164 def changeScreenResolution(xres=None, yres=None, BitsPerPixel=None): 165 import struct 166 167 DM_BITSPERPEL = 0x00040000 168 DM_PELSWIDTH = 0x00080000 169 DM_PELSHEIGHT = 0x00100000 170 CDS_FULLSCREEN = 0x00000004 171 SIZEOF_DEVMODE = 148 172 173 DevModeData = struct.calcsize("32BHH") * b"\x00" 174 DevModeData += struct.pack("H", SIZEOF_DEVMODE) 175 DevModeData += struct.calcsize("H") * b"\x00" 176 dwFields = ( 177 (xres and DM_PELSWIDTH or 0) 178 | (yres and DM_PELSHEIGHT or 0) 179 | (BitsPerPixel and DM_BITSPERPEL or 0) 180 ) 181 DevModeData += struct.pack("L", dwFields) 182 DevModeData += struct.calcsize("l9h32BHL") * b"\x00" 183 DevModeData += struct.pack("LLL", BitsPerPixel or 0, xres or 0, yres or 0) 184 DevModeData += struct.calcsize("8L") * b"\x00" 185 186 return windll.user32.ChangeDisplaySettingsA(DevModeData, 0) 187 188 189 if __name__ == "__main__": 190 sys.exit(main())