refactoring as gui application
:# Please enter the commit message for your changes. Lines starting
This commit is contained in:
		
							parent
							
								
									0b8f3ad9b6
								
							
						
					
					
						commit
						65f3a5c1da
					
				
							
								
								
									
										156
									
								
								__main__.py
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								__main__.py
									
									
									
									
									
								
							| @ -1,155 +1,5 @@ | ||||
| import asyncio | ||||
| DEBUG=False | ||||
| try: | ||||
|     from  winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager | ||||
| except: | ||||
|     print("DEBUG; winrt disabled") | ||||
|     DEBUG = True | ||||
| import win32com.client | ||||
| import time | ||||
| import pythoncom | ||||
| from gui import Gui | ||||
| 
 | ||||
| from resources import LineState, CLMgrMessage | ||||
| 
 | ||||
| import serial | ||||
| from serial import SerialException | ||||
| import session_event_listener as sel | ||||
| import ctypes | ||||
| 
 | ||||
| portName = 'COM3' | ||||
| 
 | ||||
| global_inactive = True | ||||
| 
 | ||||
| # Lock Screen detection | ||||
| user32 = ctypes.windll.User32 | ||||
| OpenDesktop = user32.OpenDesktopA | ||||
| SwitchDesktop = user32.SwitchDesktop | ||||
| DESKTOP_SWITCHDESKTOP = 0x0100 | ||||
| 
 | ||||
| global_screen_locked = False | ||||
| 
 | ||||
| def check_screen_locked(): | ||||
|     hDesktop = OpenDesktop ("default", 0, False, DESKTOP_SWITCHDESKTOP) | ||||
|     result = SwitchDesktop (hDesktop) | ||||
|     if result: | ||||
|        return True | ||||
|     else: | ||||
|        return False | ||||
| 
 | ||||
| def sendSerial(byte): | ||||
|     try: | ||||
|         ser = serial.Serial(port=portName, baudrate=115200) | ||||
|         ser.write(byte) | ||||
|     except SerialException: | ||||
|         print('port already open') | ||||
| 
 | ||||
| class PhoneLineEventHandler(): | ||||
|     phone_mgr = None | ||||
|     lines = [] | ||||
|     line_selected = None | ||||
|     connected = False | ||||
| 
 | ||||
|     def OnDispOnLineMgrNotification(self, msg, param, returns=""): | ||||
| 
 | ||||
|         global global_inactive, global_screen_locked | ||||
|         if not self.phone_mgr: | ||||
|             self.phone_mgr = win32com.client.Dispatch("CLMgr.ClientLineMgr") | ||||
|             if not self.phone_mgr: | ||||
|                 "Swyx not connected!" | ||||
|             else: | ||||
|                 print("Swyx connected!") | ||||
|         if self.phone_mgr: | ||||
|             if msg == CLMgrMessage.CLMgrLineStateChangedMessage: | ||||
|                 line = self.phone_mgr.DispGetLine(param) | ||||
|                 print("Line: {} {}".format( | ||||
|                     param, | ||||
|                     LineState.s[line.DispState]) | ||||
|                 ) | ||||
|                 if line.DispState != LineState.Inactive: | ||||
|                     if line.DispState == LineState.Ringing: | ||||
|                         sendSerial(b'shc000255000') | ||||
|                     else: | ||||
|                         sendSerial(b'shc255000000') | ||||
|                          | ||||
|                     if not global_screen_locked: | ||||
|                         asyncio.run(try_pause()) | ||||
|                     global_inactive = False | ||||
|                 for linenum in range(self.phone_mgr.DispNumberOfLines): | ||||
|                     line = self.phone_mgr.DispGetLine(linenum) | ||||
|                     if line.DispState != LineState.Inactive: | ||||
|                         return True | ||||
|                          | ||||
|                 if not global_screen_locked: | ||||
|                     asyncio.run(try_play()) | ||||
|                 global_inactive = True | ||||
|                 sendSerial(b'shc000000000') | ||||
|         return True | ||||
| 
 | ||||
| # async def get_media_info(): | ||||
| #     sessions = await MediaManager.request_async() | ||||
| 
 | ||||
| #     # This source_app_user_model_id check and if statement is optional | ||||
| #     # Use it if you want to only get a certain player/program's media | ||||
| #     # (e.g. only chrome.exe's media not any other program's). | ||||
| 
 | ||||
| #     # To get the ID, use a breakpoint() to run sessions.get_current_session() | ||||
| #     # while the media you want to get is playing. | ||||
| #     # Then set TARGET_ID to the string this call returns. | ||||
| 
 | ||||
| #     current_session = sessions.get_current_session() | ||||
| #     if current_session:  # there needs to be a media session running | ||||
| #         #if current_session.source_app_user_model_id == TARGET_ID: | ||||
| #         info = await current_session.try_get_media_properties_async() | ||||
| #         # song_attr[0] != '_' ignores system attributes | ||||
| #         info_dict = {song_attr: info.__getattribute__(song_attr) for song_attr in dir(info) if song_attr[0] != '_'} | ||||
| 
 | ||||
| #         # converts winrt vector to list | ||||
| #         info_dict['genres'] = list(info_dict['genres']) | ||||
| 
 | ||||
| #         return info_dict | ||||
| 
 | ||||
| #     # It could be possible to select a program from a list of current | ||||
| #     # available ones. I just haven't implemented this here for my use case. | ||||
| #     # See references for more information. | ||||
| #     raise Exception('TARGET_PROGRAM is not the current media session') | ||||
| 
 | ||||
| async def try_play(): | ||||
|     print("try_play") | ||||
|     if not DEBUG: | ||||
|         sessions = await MediaManager.request_async() | ||||
|         current_session = sessions.get_current_session() | ||||
|         if current_session: | ||||
|             await current_session.try_play_async() | ||||
| 
 | ||||
| async def try_pause(): | ||||
|     print("try_pause") | ||||
|     if not DEBUG: | ||||
|         sessions = await MediaManager.request_async() | ||||
|         current_session = sessions.get_current_session() | ||||
|         if current_session: | ||||
|             await current_session.try_pause_async() | ||||
| 
 | ||||
| def OnSessionEvent(event: sel.SessionEvent): | ||||
|     global global_inactive, global_screen_locked | ||||
|     if event == sel.SessionEvent.SESSION_LOCK: | ||||
|         global_screen_locked = True | ||||
|         print("locked, try_pause") | ||||
|         asyncio.run(try_pause()) | ||||
|      | ||||
|     if event == sel.SessionEvent.SESSION_UNLOCK: | ||||
|         global_screen_locked = False | ||||
|         if global_inactive: | ||||
|             print("unlocked, global inactive, tryplay") | ||||
|             asyncio.run(try_play()) | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     win32com.client.WithEvents("CLMgr.ClientLineMgr", PhoneLineEventHandler) | ||||
|     m = sel.WorkstationMonitor() | ||||
|     m.register_handler(sel.SessionEvent.ANY, handler=OnSessionEvent) | ||||
|     try: | ||||
|         while True: | ||||
|             pythoncom.PumpWaitingMessages() | ||||
|             m.listen() | ||||
|             time.sleep(0.1) # Don't use up all our CPU checking constantly | ||||
|     except KeyboardInterrupt: | ||||
|         print("exit")  | ||||
| if __name__ == "__main__": | ||||
|     gui = Gui() | ||||
| @ -21,24 +21,20 @@ pyz = PYZ(a.pure, a.zipped_data, | ||||
|              cipher=block_cipher) | ||||
| 
 | ||||
| exe = EXE(pyz, | ||||
|           a.scripts,  | ||||
|           a.scripts, | ||||
|           a.binaries, | ||||
|           a.zipfiles, | ||||
|           a.datas,   | ||||
|           [], | ||||
|           exclude_binaries=True, | ||||
|           name='__main__', | ||||
|           debug=False, | ||||
|           bootloader_ignore_signals=False, | ||||
|           strip=False, | ||||
|           upx=True, | ||||
|           upx_exclude=[], | ||||
|           runtime_tmpdir=None, | ||||
|           console=True, | ||||
|           disable_windowed_traceback=False, | ||||
|           target_arch=None, | ||||
|           codesign_identity=None, | ||||
|           entitlements_file=None ) | ||||
| coll = COLLECT(exe, | ||||
|                a.binaries, | ||||
|                a.zipfiles, | ||||
|                a.datas,  | ||||
|                strip=False, | ||||
|                upx=True, | ||||
|                upx_exclude=[], | ||||
|                name='__main__') | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 66 KiB | 
							
								
								
									
										147
									
								
								gui.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								gui.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,147 @@ | ||||
| # Import the required libraries | ||||
| import logging | ||||
| from tkinter import * | ||||
| from pystray import MenuItem as item | ||||
| import pystray | ||||
| from PIL import Image, ImageTk | ||||
| import threading | ||||
| from functools import partial | ||||
| import time | ||||
| 
 | ||||
| from mediacontrol import MediaControl | ||||
| from ledcontroll import BLACK, LedControl, RED1, GREEN | ||||
| from swyxcontrol import SwyxControl, LineState | ||||
| from workstationcontrol import LockscreenMonitor, SessionEvent | ||||
| 
 | ||||
| class Gui(): | ||||
| 
 | ||||
|     win: Tk | ||||
|     t_icon: threading.Thread | ||||
| 
 | ||||
|     strvar_swyx_connected_status: StringVar | ||||
|     strvar_screen_locked: StringVar | ||||
|     strvar_line_inactive: StringVar | ||||
|     strvar_play_state: StringVar | ||||
| 
 | ||||
|     on_quit = None | ||||
| 
 | ||||
|     def set_swyx_status(self, string): | ||||
|         self.strvar_swyx_connected_status.set(string) | ||||
| 
 | ||||
|     # Define a function for quit the window | ||||
|     def quit_window(self, icon, item = None): | ||||
|         self.sc.stop() | ||||
|         self.wm.stop() | ||||
|         self.mc.stop() | ||||
|         icon.stop() | ||||
|         self.win.deiconify() | ||||
|         self.win.quit() | ||||
| 
 | ||||
|     # Define a function to show the window again | ||||
|     def show_window(self, icon, item): | ||||
|         self.win.deiconify() | ||||
| 
 | ||||
|     # Hide the window and show on the system taskbar | ||||
|     def hide_window(self): | ||||
|         self.win.withdraw() | ||||
| 
 | ||||
|     def handle_lockscreen(self, event: SessionEvent): | ||||
|         if event == SessionEvent.SESSION_LOCK: | ||||
|             logging.debug("locked, pause") | ||||
|             self.mc.pause() | ||||
|             self.strvar_screen_locked.set("Locked") | ||||
|          | ||||
|         if event == SessionEvent.SESSION_UNLOCK: | ||||
|             if self.sc.all_lines_inactive: | ||||
|                 logging.debug("unlocked, global inactive, play") | ||||
|                 time.sleep(3) | ||||
|                 self.mc.play() | ||||
|             self.strvar_screen_locked.set("Unlocked") | ||||
| 
 | ||||
|     def handle_line_state_changed(self, line): | ||||
|         if not line.DispState == LineState.Inactive: | ||||
|             if line.DispState == LineState.Ringing: | ||||
|                 self.lc.show_all(GREEN) | ||||
|             else: | ||||
|                 self.lc.show_all(RED1) | ||||
|             self.mc.pause() | ||||
|             self.strvar_play_state.set("try pause") | ||||
|             self.strvar_line_inactive.set("False") | ||||
|         if self.sc.all_lines_inactive: | ||||
|             self.strvar_line_inactive.set("True") | ||||
|             self.lc.show_all(BLACK) | ||||
|             if not self.wm.screen_locked(): | ||||
|                 self.mc.play() | ||||
|                 self.strvar_play_state.set("try play") | ||||
| 
 | ||||
|     def handle_phone_mgr_connected(self): | ||||
|         if self.sc.all_lines_inactive: | ||||
|             self.strvar_line_inactive.set("True") | ||||
|             self.lc.show_all(BLACK) | ||||
|             return | ||||
|         self.strvar_line_inactive.set("False") | ||||
| 
 | ||||
|     def handle_media_control_init(self): | ||||
|         playback_info = self.mc.get_playback_info() | ||||
|         if playback_info is None: | ||||
|             print(playback_info) | ||||
|         self.strvar_play_state.set("no session active") | ||||
| 
 | ||||
|     def __init__(self): | ||||
|          | ||||
|         self.load_gui() | ||||
| 
 | ||||
|         self.sc = SwyxControl() | ||||
|         self.sc.name = "SwyxControl" | ||||
|         self.sc.add_phone_mgr_connected_handler(self.handle_phone_mgr_connected) | ||||
|         self.sc.add_line_state_changed_handler(self.handle_line_state_changed) | ||||
|         self.sc.start() | ||||
| 
 | ||||
|         self.lc = LedControl('COM3') | ||||
| 
 | ||||
|         self.mc = MediaControl() | ||||
|         self.mc.name = "MediaControl" | ||||
|         self.mc.add_init_handler(self.handle_media_control_init) | ||||
|         self.mc.start() | ||||
| 
 | ||||
|         self.wm = LockscreenMonitor() | ||||
|         self.wm.name = "LockscreenMonitor" | ||||
|         self.wm.register_handler(self.handle_lockscreen) | ||||
|         self.strvar_screen_locked.set("Locked" if self.wm.screen_locked() else "Unlocked") | ||||
|         self.wm.start() | ||||
| 
 | ||||
|         self.win.protocol('WM_DELETE_WINDOW', self.hide_window) | ||||
|         image=Image.open("favicon.ico") | ||||
|         menu=(item('Beenden', self.quit_window), item('Anzeigen', self.show_window)) | ||||
|         self.icon=pystray.Icon("name", image, "Swyx Media Controll", menu) | ||||
|         self.t_icon = threading.Thread(target=self.icon.run) | ||||
|         self.t_icon.name = "icon_thread" | ||||
|         self.t_icon.start() | ||||
|         self.win.mainloop() | ||||
| 
 | ||||
| 
 | ||||
|     def load_gui(self): | ||||
|         self.win=Tk() | ||||
|         # Create an instance of tkinter frame or window | ||||
|         self.win.title("Swyx Media Controll") | ||||
|         # Set the size of the window | ||||
|         self.win.geometry("350x150") | ||||
|         self.win.resizable(False, False) | ||||
| 
 | ||||
|         ## Screen Lock | ||||
|         Label(self.win, text="Screen Lock: ", font=("Helvetica", 10)).place(x=10, y=10) | ||||
|         self.strvar_screen_locked = StringVar(self.win) | ||||
|         Label(self.win, textvariable=self.strvar_screen_locked, font=("Helvetica", 10)).place(x=100, y=10) | ||||
| 
 | ||||
|         ## Line Inactive | ||||
|         Label(self.win, text="Line Inactive: ", font=("Helvetica", 10)).place(x=10, y=30) | ||||
|         self.strvar_line_inactive = StringVar(self.win) | ||||
|         Label(self.win, textvariable=self.strvar_line_inactive, font=("Helvetica", 10)).place(x=100, y=30) | ||||
| 
 | ||||
|         ## Play State | ||||
|         Label(self.win, text="Play State: ", font=("Helvetica", 10)).place(x=10, y=50) | ||||
|         self.strvar_play_state = StringVar(self.win) | ||||
|         Label(self.win, textvariable=self.strvar_play_state, font=("Helvetica", 10)).place(x=100, y=50) | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     gui = Gui() | ||||
							
								
								
									
										607
									
								
								ledcontroll.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										607
									
								
								ledcontroll.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,607 @@ | ||||
| import serial | ||||
| 
 | ||||
| class LedControl(): | ||||
|     portName = '' | ||||
| 
 | ||||
|     def __init__(self, portName: str) -> None: | ||||
|         '''portname is the com port of the ledstrip''' | ||||
|         self.portName = portName | ||||
|         pass | ||||
| 
 | ||||
|     def show_all(self, color:'RGB'): | ||||
|         '''shows all leds in a specified color''' | ||||
|         self.__sendSerial(b"shc"+color.hex_format()) | ||||
| 
 | ||||
|     def set_one(self, id, color: 'RGB'): | ||||
|         '''sets a led to a specified color''' | ||||
|         self.__sendSerial("dta{:03}".format(id).encode() + color.hex_format()) | ||||
| 
 | ||||
|     def show(self): | ||||
|         '''shows the colors set by set_one''' | ||||
|         self.__sendSerial(b'shw') | ||||
| 
 | ||||
|     def __sendSerial(self, byte): | ||||
|         try: | ||||
|             ser = serial.Serial(port=self.portName, baudrate=115200) | ||||
|             ser.write(byte) | ||||
|             for line in ser.readline(): | ||||
|                 pass | ||||
|         except serial.SerialException: | ||||
|             print('port already open') | ||||
| 
 | ||||
| """Provide RGB color constants and a colors dictionary with | ||||
| elements formatted: colors[colorname] = CONSTANT""" | ||||
| from collections import namedtuple, OrderedDict | ||||
| Color = namedtuple('RGB','red, green, blue') | ||||
| colors = {} #dict of colors | ||||
| class RGB(Color): | ||||
|     def hex_format(self) -> bytes: | ||||
|         '''Returns color in hex format''' | ||||
|         return '{:03}{:03}{:03}'.format(self.red,self.green,self.blue).encode() | ||||
| #Color Contants | ||||
| ALICEBLUE = RGB(240, 248, 255) | ||||
| ANTIQUEWHITE = RGB(250, 235, 215) | ||||
| ANTIQUEWHITE1 = RGB(255, 239, 219) | ||||
| ANTIQUEWHITE2 = RGB(238, 223, 204) | ||||
| ANTIQUEWHITE3 = RGB(205, 192, 176) | ||||
| ANTIQUEWHITE4 = RGB(139, 131, 120) | ||||
| AQUA = RGB(0, 255, 255) | ||||
| AQUAMARINE1 = RGB(127, 255, 212) | ||||
| AQUAMARINE2 = RGB(118, 238, 198) | ||||
| AQUAMARINE3 = RGB(102, 205, 170) | ||||
| AQUAMARINE4 = RGB(69, 139, 116) | ||||
| AZURE1 = RGB(240, 255, 255) | ||||
| AZURE2 = RGB(224, 238, 238) | ||||
| AZURE3 = RGB(193, 205, 205) | ||||
| AZURE4 = RGB(131, 139, 139) | ||||
| BANANA = RGB(227, 207, 87) | ||||
| BEIGE = RGB(245, 245, 220) | ||||
| BISQUE1 = RGB(255, 228, 196) | ||||
| BISQUE2 = RGB(238, 213, 183) | ||||
| BISQUE3 = RGB(205, 183, 158) | ||||
| BISQUE4 = RGB(139, 125, 107) | ||||
| BLACK = RGB(0, 0, 0) | ||||
| BLANCHEDALMOND = RGB(255, 235, 205) | ||||
| BLUE = RGB(0, 0, 255) | ||||
| BLUE2 = RGB(0, 0, 238) | ||||
| BLUE3 = RGB(0, 0, 205) | ||||
| BLUE4 = RGB(0, 0, 139) | ||||
| BLUEVIOLET = RGB(138, 43, 226) | ||||
| BRICK = RGB(156, 102, 31) | ||||
| BROWN = RGB(165, 42, 42) | ||||
| BROWN1 = RGB(255, 64, 64) | ||||
| BROWN2 = RGB(238, 59, 59) | ||||
| BROWN3 = RGB(205, 51, 51) | ||||
| BROWN4 = RGB(139, 35, 35) | ||||
| BURLYWOOD = RGB(222, 184, 135) | ||||
| BURLYWOOD1 = RGB(255, 211, 155) | ||||
| BURLYWOOD2 = RGB(238, 197, 145) | ||||
| BURLYWOOD3 = RGB(205, 170, 125) | ||||
| BURLYWOOD4 = RGB(139, 115, 85) | ||||
| BURNTSIENNA = RGB(138, 54, 15) | ||||
| BURNTUMBER = RGB(138, 51, 36) | ||||
| CADETBLUE = RGB(95, 158, 160) | ||||
| CADETBLUE1 = RGB(152, 245, 255) | ||||
| CADETBLUE2 = RGB(142, 229, 238) | ||||
| CADETBLUE3 = RGB(122, 197, 205) | ||||
| CADETBLUE4 = RGB(83, 134, 139) | ||||
| CADMIUMORANGE = RGB(255, 97, 3) | ||||
| CADMIUMYELLOW = RGB(255, 153, 18) | ||||
| CARROT = RGB(237, 145, 33) | ||||
| CHARTREUSE1 = RGB(127, 255, 0) | ||||
| CHARTREUSE2 = RGB(118, 238, 0) | ||||
| CHARTREUSE3 = RGB(102, 205, 0) | ||||
| CHARTREUSE4 = RGB(69, 139, 0) | ||||
| CHOCOLATE = RGB(210, 105, 30) | ||||
| CHOCOLATE1 = RGB(255, 127, 36) | ||||
| CHOCOLATE2 = RGB(238, 118, 33) | ||||
| CHOCOLATE3 = RGB(205, 102, 29) | ||||
| CHOCOLATE4 = RGB(139, 69, 19) | ||||
| COBALT = RGB(61, 89, 171) | ||||
| COBALTGREEN = RGB(61, 145, 64) | ||||
| COLDGREY = RGB(128, 138, 135) | ||||
| CORAL = RGB(255, 127, 80) | ||||
| CORAL1 = RGB(255, 114, 86) | ||||
| CORAL2 = RGB(238, 106, 80) | ||||
| CORAL3 = RGB(205, 91, 69) | ||||
| CORAL4 = RGB(139, 62, 47) | ||||
| CORNFLOWERBLUE = RGB(100, 149, 237) | ||||
| CORNSILK1 = RGB(255, 248, 220) | ||||
| CORNSILK2 = RGB(238, 232, 205) | ||||
| CORNSILK3 = RGB(205, 200, 177) | ||||
| CORNSILK4 = RGB(139, 136, 120) | ||||
| CRIMSON = RGB(220, 20, 60) | ||||
| CYAN2 = RGB(0, 238, 238) | ||||
| CYAN3 = RGB(0, 205, 205) | ||||
| CYAN4 = RGB(0, 139, 139) | ||||
| DARKGOLDENROD = RGB(184, 134, 11) | ||||
| DARKGOLDENROD1 = RGB(255, 185, 15) | ||||
| DARKGOLDENROD2 = RGB(238, 173, 14) | ||||
| DARKGOLDENROD3 = RGB(205, 149, 12) | ||||
| DARKGOLDENROD4 = RGB(139, 101, 8) | ||||
| DARKGRAY = RGB(169, 169, 169) | ||||
| DARKGREEN = RGB(0, 100, 0) | ||||
| DARKKHAKI = RGB(189, 183, 107) | ||||
| DARKOLIVEGREEN = RGB(85, 107, 47) | ||||
| DARKOLIVEGREEN1 = RGB(202, 255, 112) | ||||
| DARKOLIVEGREEN2 = RGB(188, 238, 104) | ||||
| DARKOLIVEGREEN3 = RGB(162, 205, 90) | ||||
| DARKOLIVEGREEN4 = RGB(110, 139, 61) | ||||
| DARKORANGE = RGB(255, 140, 0) | ||||
| DARKORANGE1 = RGB(255, 127, 0) | ||||
| DARKORANGE2 = RGB(238, 118, 0) | ||||
| DARKORANGE3 = RGB(205, 102, 0) | ||||
| DARKORANGE4 = RGB(139, 69, 0) | ||||
| DARKORCHID = RGB(153, 50, 204) | ||||
| DARKORCHID1 = RGB(191, 62, 255) | ||||
| DARKORCHID2 = RGB(178, 58, 238) | ||||
| DARKORCHID3 = RGB(154, 50, 205) | ||||
| DARKORCHID4 = RGB(104, 34, 139) | ||||
| DARKSALMON = RGB(233, 150, 122) | ||||
| DARKSEAGREEN = RGB(143, 188, 143) | ||||
| DARKSEAGREEN1 = RGB(193, 255, 193) | ||||
| DARKSEAGREEN2 = RGB(180, 238, 180) | ||||
| DARKSEAGREEN3 = RGB(155, 205, 155) | ||||
| DARKSEAGREEN4 = RGB(105, 139, 105) | ||||
| DARKSLATEBLUE = RGB(72, 61, 139) | ||||
| DARKSLATEGRAY = RGB(47, 79, 79) | ||||
| DARKSLATEGRAY1 = RGB(151, 255, 255) | ||||
| DARKSLATEGRAY2 = RGB(141, 238, 238) | ||||
| DARKSLATEGRAY3 = RGB(121, 205, 205) | ||||
| DARKSLATEGRAY4 = RGB(82, 139, 139) | ||||
| DARKTURQUOISE = RGB(0, 206, 209) | ||||
| DARKVIOLET = RGB(148, 0, 211) | ||||
| DEEPPINK1 = RGB(255, 20, 147) | ||||
| DEEPPINK2 = RGB(238, 18, 137) | ||||
| DEEPPINK3 = RGB(205, 16, 118) | ||||
| DEEPPINK4 = RGB(139, 10, 80) | ||||
| DEEPSKYBLUE1 = RGB(0, 191, 255) | ||||
| DEEPSKYBLUE2 = RGB(0, 178, 238) | ||||
| DEEPSKYBLUE3 = RGB(0, 154, 205) | ||||
| DEEPSKYBLUE4 = RGB(0, 104, 139) | ||||
| DIMGRAY = RGB(105, 105, 105) | ||||
| DIMGRAY = RGB(105, 105, 105) | ||||
| DODGERBLUE1 = RGB(30, 144, 255) | ||||
| DODGERBLUE2 = RGB(28, 134, 238) | ||||
| DODGERBLUE3 = RGB(24, 116, 205) | ||||
| DODGERBLUE4 = RGB(16, 78, 139) | ||||
| EGGSHELL = RGB(252, 230, 201) | ||||
| EMERALDGREEN = RGB(0, 201, 87) | ||||
| FIREBRICK = RGB(178, 34, 34) | ||||
| FIREBRICK1 = RGB(255, 48, 48) | ||||
| FIREBRICK2 = RGB(238, 44, 44) | ||||
| FIREBRICK3 = RGB(205, 38, 38) | ||||
| FIREBRICK4 = RGB(139, 26, 26) | ||||
| FLESH = RGB(255, 125, 64) | ||||
| FLORALWHITE = RGB(255, 250, 240) | ||||
| FORESTGREEN = RGB(34, 139, 34) | ||||
| GAINSBORO = RGB(220, 220, 220) | ||||
| GHOSTWHITE = RGB(248, 248, 255) | ||||
| GOLD1 = RGB(255, 215, 0) | ||||
| GOLD2 = RGB(238, 201, 0) | ||||
| GOLD3 = RGB(205, 173, 0) | ||||
| GOLD4 = RGB(139, 117, 0) | ||||
| GOLDENROD = RGB(218, 165, 32) | ||||
| GOLDENROD1 = RGB(255, 193, 37) | ||||
| GOLDENROD2 = RGB(238, 180, 34) | ||||
| GOLDENROD3 = RGB(205, 155, 29) | ||||
| GOLDENROD4 = RGB(139, 105, 20) | ||||
| GRAY = RGB(128, 128, 128) | ||||
| GRAY1 = RGB(3, 3, 3) | ||||
| GRAY10 = RGB(26, 26, 26) | ||||
| GRAY11 = RGB(28, 28, 28) | ||||
| GRAY12 = RGB(31, 31, 31) | ||||
| GRAY13 = RGB(33, 33, 33) | ||||
| GRAY14 = RGB(36, 36, 36) | ||||
| GRAY15 = RGB(38, 38, 38) | ||||
| GRAY16 = RGB(41, 41, 41) | ||||
| GRAY17 = RGB(43, 43, 43) | ||||
| GRAY18 = RGB(46, 46, 46) | ||||
| GRAY19 = RGB(48, 48, 48) | ||||
| GRAY2 = RGB(5, 5, 5) | ||||
| GRAY20 = RGB(51, 51, 51) | ||||
| GRAY21 = RGB(54, 54, 54) | ||||
| GRAY22 = RGB(56, 56, 56) | ||||
| GRAY23 = RGB(59, 59, 59) | ||||
| GRAY24 = RGB(61, 61, 61) | ||||
| GRAY25 = RGB(64, 64, 64) | ||||
| GRAY26 = RGB(66, 66, 66) | ||||
| GRAY27 = RGB(69, 69, 69) | ||||
| GRAY28 = RGB(71, 71, 71) | ||||
| GRAY29 = RGB(74, 74, 74) | ||||
| GRAY3 = RGB(8, 8, 8) | ||||
| GRAY30 = RGB(77, 77, 77) | ||||
| GRAY31 = RGB(79, 79, 79) | ||||
| GRAY32 = RGB(82, 82, 82) | ||||
| GRAY33 = RGB(84, 84, 84) | ||||
| GRAY34 = RGB(87, 87, 87) | ||||
| GRAY35 = RGB(89, 89, 89) | ||||
| GRAY36 = RGB(92, 92, 92) | ||||
| GRAY37 = RGB(94, 94, 94) | ||||
| GRAY38 = RGB(97, 97, 97) | ||||
| GRAY39 = RGB(99, 99, 99) | ||||
| GRAY4 = RGB(10, 10, 10) | ||||
| GRAY40 = RGB(102, 102, 102) | ||||
| GRAY42 = RGB(107, 107, 107) | ||||
| GRAY43 = RGB(110, 110, 110) | ||||
| GRAY44 = RGB(112, 112, 112) | ||||
| GRAY45 = RGB(115, 115, 115) | ||||
| GRAY46 = RGB(117, 117, 117) | ||||
| GRAY47 = RGB(120, 120, 120) | ||||
| GRAY48 = RGB(122, 122, 122) | ||||
| GRAY49 = RGB(125, 125, 125) | ||||
| GRAY5 = RGB(13, 13, 13) | ||||
| GRAY50 = RGB(127, 127, 127) | ||||
| GRAY51 = RGB(130, 130, 130) | ||||
| GRAY52 = RGB(133, 133, 133) | ||||
| GRAY53 = RGB(135, 135, 135) | ||||
| GRAY54 = RGB(138, 138, 138) | ||||
| GRAY55 = RGB(140, 140, 140) | ||||
| GRAY56 = RGB(143, 143, 143) | ||||
| GRAY57 = RGB(145, 145, 145) | ||||
| GRAY58 = RGB(148, 148, 148) | ||||
| GRAY59 = RGB(150, 150, 150) | ||||
| GRAY6 = RGB(15, 15, 15) | ||||
| GRAY60 = RGB(153, 153, 153) | ||||
| GRAY61 = RGB(156, 156, 156) | ||||
| GRAY62 = RGB(158, 158, 158) | ||||
| GRAY63 = RGB(161, 161, 161) | ||||
| GRAY64 = RGB(163, 163, 163) | ||||
| GRAY65 = RGB(166, 166, 166) | ||||
| GRAY66 = RGB(168, 168, 168) | ||||
| GRAY67 = RGB(171, 171, 171) | ||||
| GRAY68 = RGB(173, 173, 173) | ||||
| GRAY69 = RGB(176, 176, 176) | ||||
| GRAY7 = RGB(18, 18, 18) | ||||
| GRAY70 = RGB(179, 179, 179) | ||||
| GRAY71 = RGB(181, 181, 181) | ||||
| GRAY72 = RGB(184, 184, 184) | ||||
| GRAY73 = RGB(186, 186, 186) | ||||
| GRAY74 = RGB(189, 189, 189) | ||||
| GRAY75 = RGB(191, 191, 191) | ||||
| GRAY76 = RGB(194, 194, 194) | ||||
| GRAY77 = RGB(196, 196, 196) | ||||
| GRAY78 = RGB(199, 199, 199) | ||||
| GRAY79 = RGB(201, 201, 201) | ||||
| GRAY8 = RGB(20, 20, 20) | ||||
| GRAY80 = RGB(204, 204, 204) | ||||
| GRAY81 = RGB(207, 207, 207) | ||||
| GRAY82 = RGB(209, 209, 209) | ||||
| GRAY83 = RGB(212, 212, 212) | ||||
| GRAY84 = RGB(214, 214, 214) | ||||
| GRAY85 = RGB(217, 217, 217) | ||||
| GRAY86 = RGB(219, 219, 219) | ||||
| GRAY87 = RGB(222, 222, 222) | ||||
| GRAY88 = RGB(224, 224, 224) | ||||
| GRAY89 = RGB(227, 227, 227) | ||||
| GRAY9 = RGB(23, 23, 23) | ||||
| GRAY90 = RGB(229, 229, 229) | ||||
| GRAY91 = RGB(232, 232, 232) | ||||
| GRAY92 = RGB(235, 235, 235) | ||||
| GRAY93 = RGB(237, 237, 237) | ||||
| GRAY94 = RGB(240, 240, 240) | ||||
| GRAY95 = RGB(242, 242, 242) | ||||
| GRAY97 = RGB(247, 247, 247) | ||||
| GRAY98 = RGB(250, 250, 250) | ||||
| GRAY99 = RGB(252, 252, 252) | ||||
| GREEN = RGB(0, 128, 0) | ||||
| GREEN1 = RGB(0, 255, 0) | ||||
| GREEN2 = RGB(0, 238, 0) | ||||
| GREEN3 = RGB(0, 205, 0) | ||||
| GREEN4 = RGB(0, 139, 0) | ||||
| GREENYELLOW = RGB(173, 255, 47) | ||||
| HONEYDEW1 = RGB(240, 255, 240) | ||||
| HONEYDEW2 = RGB(224, 238, 224) | ||||
| HONEYDEW3 = RGB(193, 205, 193) | ||||
| HONEYDEW4 = RGB(131, 139, 131) | ||||
| HOTPINK = RGB(255, 105, 180) | ||||
| HOTPINK1 = RGB(255, 110, 180) | ||||
| HOTPINK2 = RGB(238, 106, 167) | ||||
| HOTPINK3 = RGB(205, 96, 144) | ||||
| HOTPINK4 = RGB(139, 58, 98) | ||||
| INDIANRED = RGB(176, 23, 31) | ||||
| INDIANRED = RGB(205, 92, 92) | ||||
| INDIANRED1 = RGB(255, 106, 106) | ||||
| INDIANRED2 = RGB(238, 99, 99) | ||||
| INDIANRED3 = RGB(205, 85, 85) | ||||
| INDIANRED4 = RGB(139, 58, 58) | ||||
| INDIGO = RGB(75, 0, 130) | ||||
| IVORY1 = RGB(255, 255, 240) | ||||
| IVORY2 = RGB(238, 238, 224) | ||||
| IVORY3 = RGB(205, 205, 193) | ||||
| IVORY4 = RGB(139, 139, 131) | ||||
| IVORYBLACK = RGB(41, 36, 33) | ||||
| KHAKI = RGB(240, 230, 140) | ||||
| KHAKI1 = RGB(255, 246, 143) | ||||
| KHAKI2 = RGB(238, 230, 133) | ||||
| KHAKI3 = RGB(205, 198, 115) | ||||
| KHAKI4 = RGB(139, 134, 78) | ||||
| LAVENDER = RGB(230, 230, 250) | ||||
| LAVENDERBLUSH1 = RGB(255, 240, 245) | ||||
| LAVENDERBLUSH2 = RGB(238, 224, 229) | ||||
| LAVENDERBLUSH3 = RGB(205, 193, 197) | ||||
| LAVENDERBLUSH4 = RGB(139, 131, 134) | ||||
| LAWNGREEN = RGB(124, 252, 0) | ||||
| LEMONCHIFFON1 = RGB(255, 250, 205) | ||||
| LEMONCHIFFON2 = RGB(238, 233, 191) | ||||
| LEMONCHIFFON3 = RGB(205, 201, 165) | ||||
| LEMONCHIFFON4 = RGB(139, 137, 112) | ||||
| LIGHTBLUE = RGB(173, 216, 230) | ||||
| LIGHTBLUE1 = RGB(191, 239, 255) | ||||
| LIGHTBLUE2 = RGB(178, 223, 238) | ||||
| LIGHTBLUE3 = RGB(154, 192, 205) | ||||
| LIGHTBLUE4 = RGB(104, 131, 139) | ||||
| LIGHTCORAL = RGB(240, 128, 128) | ||||
| LIGHTCYAN1 = RGB(224, 255, 255) | ||||
| LIGHTCYAN2 = RGB(209, 238, 238) | ||||
| LIGHTCYAN3 = RGB(180, 205, 205) | ||||
| LIGHTCYAN4 = RGB(122, 139, 139) | ||||
| LIGHTGOLDENROD1 = RGB(255, 236, 139) | ||||
| LIGHTGOLDENROD2 = RGB(238, 220, 130) | ||||
| LIGHTGOLDENROD3 = RGB(205, 190, 112) | ||||
| LIGHTGOLDENROD4 = RGB(139, 129, 76) | ||||
| LIGHTGOLDENRODYELLOW = RGB(250, 250, 210) | ||||
| LIGHTGREY = RGB(211, 211, 211) | ||||
| LIGHTPINK = RGB(255, 182, 193) | ||||
| LIGHTPINK1 = RGB(255, 174, 185) | ||||
| LIGHTPINK2 = RGB(238, 162, 173) | ||||
| LIGHTPINK3 = RGB(205, 140, 149) | ||||
| LIGHTPINK4 = RGB(139, 95, 101) | ||||
| LIGHTSALMON1 = RGB(255, 160, 122) | ||||
| LIGHTSALMON2 = RGB(238, 149, 114) | ||||
| LIGHTSALMON3 = RGB(205, 129, 98) | ||||
| LIGHTSALMON4 = RGB(139, 87, 66) | ||||
| LIGHTSEAGREEN = RGB(32, 178, 170) | ||||
| LIGHTSKYBLUE = RGB(135, 206, 250) | ||||
| LIGHTSKYBLUE1 = RGB(176, 226, 255) | ||||
| LIGHTSKYBLUE2 = RGB(164, 211, 238) | ||||
| LIGHTSKYBLUE3 = RGB(141, 182, 205) | ||||
| LIGHTSKYBLUE4 = RGB(96, 123, 139) | ||||
| LIGHTSLATEBLUE = RGB(132, 112, 255) | ||||
| LIGHTSLATEGRAY = RGB(119, 136, 153) | ||||
| LIGHTSTEELBLUE = RGB(176, 196, 222) | ||||
| LIGHTSTEELBLUE1 = RGB(202, 225, 255) | ||||
| LIGHTSTEELBLUE2 = RGB(188, 210, 238) | ||||
| LIGHTSTEELBLUE3 = RGB(162, 181, 205) | ||||
| LIGHTSTEELBLUE4 = RGB(110, 123, 139) | ||||
| LIGHTYELLOW1 = RGB(255, 255, 224) | ||||
| LIGHTYELLOW2 = RGB(238, 238, 209) | ||||
| LIGHTYELLOW3 = RGB(205, 205, 180) | ||||
| LIGHTYELLOW4 = RGB(139, 139, 122) | ||||
| LIMEGREEN = RGB(50, 205, 50) | ||||
| LINEN = RGB(250, 240, 230) | ||||
| MAGENTA = RGB(255, 0, 255) | ||||
| MAGENTA2 = RGB(238, 0, 238) | ||||
| MAGENTA3 = RGB(205, 0, 205) | ||||
| MAGENTA4 = RGB(139, 0, 139) | ||||
| MANGANESEBLUE = RGB(3, 168, 158) | ||||
| MAROON = RGB(128, 0, 0) | ||||
| MAROON1 = RGB(255, 52, 179) | ||||
| MAROON2 = RGB(238, 48, 167) | ||||
| MAROON3 = RGB(205, 41, 144) | ||||
| MAROON4 = RGB(139, 28, 98) | ||||
| MEDIUMORCHID = RGB(186, 85, 211) | ||||
| MEDIUMORCHID1 = RGB(224, 102, 255) | ||||
| MEDIUMORCHID2 = RGB(209, 95, 238) | ||||
| MEDIUMORCHID3 = RGB(180, 82, 205) | ||||
| MEDIUMORCHID4 = RGB(122, 55, 139) | ||||
| MEDIUMPURPLE = RGB(147, 112, 219) | ||||
| MEDIUMPURPLE1 = RGB(171, 130, 255) | ||||
| MEDIUMPURPLE2 = RGB(159, 121, 238) | ||||
| MEDIUMPURPLE3 = RGB(137, 104, 205) | ||||
| MEDIUMPURPLE4 = RGB(93, 71, 139) | ||||
| MEDIUMSEAGREEN = RGB(60, 179, 113) | ||||
| MEDIUMSLATEBLUE = RGB(123, 104, 238) | ||||
| MEDIUMSPRINGGREEN = RGB(0, 250, 154) | ||||
| MEDIUMTURQUOISE = RGB(72, 209, 204) | ||||
| MEDIUMVIOLETRED = RGB(199, 21, 133) | ||||
| MELON = RGB(227, 168, 105) | ||||
| MIDNIGHTBLUE = RGB(25, 25, 112) | ||||
| MINT = RGB(189, 252, 201) | ||||
| MINTCREAM = RGB(245, 255, 250) | ||||
| MISTYROSE1 = RGB(255, 228, 225) | ||||
| MISTYROSE2 = RGB(238, 213, 210) | ||||
| MISTYROSE3 = RGB(205, 183, 181) | ||||
| MISTYROSE4 = RGB(139, 125, 123) | ||||
| MOCCASIN = RGB(255, 228, 181) | ||||
| NAVAJOWHITE1 = RGB(255, 222, 173) | ||||
| NAVAJOWHITE2 = RGB(238, 207, 161) | ||||
| NAVAJOWHITE3 = RGB(205, 179, 139) | ||||
| NAVAJOWHITE4 = RGB(139, 121, 94) | ||||
| NAVY = RGB(0, 0, 128) | ||||
| OLDLACE = RGB(253, 245, 230) | ||||
| OLIVE = RGB(128, 128, 0) | ||||
| OLIVEDRAB = RGB(107, 142, 35) | ||||
| OLIVEDRAB1 = RGB(192, 255, 62) | ||||
| OLIVEDRAB2 = RGB(179, 238, 58) | ||||
| OLIVEDRAB3 = RGB(154, 205, 50) | ||||
| OLIVEDRAB4 = RGB(105, 139, 34) | ||||
| ORANGE = RGB(255, 128, 0) | ||||
| ORANGE1 = RGB(255, 165, 0) | ||||
| ORANGE2 = RGB(238, 154, 0) | ||||
| ORANGE3 = RGB(205, 133, 0) | ||||
| ORANGE4 = RGB(139, 90, 0) | ||||
| ORANGERED1 = RGB(255, 69, 0) | ||||
| ORANGERED2 = RGB(238, 64, 0) | ||||
| ORANGERED3 = RGB(205, 55, 0) | ||||
| ORANGERED4 = RGB(139, 37, 0) | ||||
| ORCHID = RGB(218, 112, 214) | ||||
| ORCHID1 = RGB(255, 131, 250) | ||||
| ORCHID2 = RGB(238, 122, 233) | ||||
| ORCHID3 = RGB(205, 105, 201) | ||||
| ORCHID4 = RGB(139, 71, 137) | ||||
| PALEGOLDENROD = RGB(238, 232, 170) | ||||
| PALEGREEN = RGB(152, 251, 152) | ||||
| PALEGREEN1 = RGB(154, 255, 154) | ||||
| PALEGREEN2 = RGB(144, 238, 144) | ||||
| PALEGREEN3 = RGB(124, 205, 124) | ||||
| PALEGREEN4 = RGB(84, 139, 84) | ||||
| PALETURQUOISE1 = RGB(187, 255, 255) | ||||
| PALETURQUOISE2 = RGB(174, 238, 238) | ||||
| PALETURQUOISE3 = RGB(150, 205, 205) | ||||
| PALETURQUOISE4 = RGB(102, 139, 139) | ||||
| PALEVIOLETRED = RGB(219, 112, 147) | ||||
| PALEVIOLETRED1 = RGB(255, 130, 171) | ||||
| PALEVIOLETRED2 = RGB(238, 121, 159) | ||||
| PALEVIOLETRED3 = RGB(205, 104, 137) | ||||
| PALEVIOLETRED4 = RGB(139, 71, 93) | ||||
| PAPAYAWHIP = RGB(255, 239, 213) | ||||
| PEACHPUFF1 = RGB(255, 218, 185) | ||||
| PEACHPUFF2 = RGB(238, 203, 173) | ||||
| PEACHPUFF3 = RGB(205, 175, 149) | ||||
| PEACHPUFF4 = RGB(139, 119, 101) | ||||
| PEACOCK = RGB(51, 161, 201) | ||||
| PINK = RGB(255, 192, 203) | ||||
| PINK1 = RGB(255, 181, 197) | ||||
| PINK2 = RGB(238, 169, 184) | ||||
| PINK3 = RGB(205, 145, 158) | ||||
| PINK4 = RGB(139, 99, 108) | ||||
| PLUM = RGB(221, 160, 221) | ||||
| PLUM1 = RGB(255, 187, 255) | ||||
| PLUM2 = RGB(238, 174, 238) | ||||
| PLUM3 = RGB(205, 150, 205) | ||||
| PLUM4 = RGB(139, 102, 139) | ||||
| POWDERBLUE = RGB(176, 224, 230) | ||||
| PURPLE = RGB(128, 0, 128) | ||||
| PURPLE1 = RGB(155, 48, 255) | ||||
| PURPLE2 = RGB(145, 44, 238) | ||||
| PURPLE3 = RGB(125, 38, 205) | ||||
| PURPLE4 = RGB(85, 26, 139) | ||||
| RASPBERRY = RGB(135, 38, 87) | ||||
| RAWSIENNA = RGB(199, 97, 20) | ||||
| RED1 = RGB(255, 0, 0) | ||||
| RED2 = RGB(238, 0, 0) | ||||
| RED3 = RGB(205, 0, 0) | ||||
| RED4 = RGB(139, 0, 0) | ||||
| ROSYBROWN = RGB(188, 143, 143) | ||||
| ROSYBROWN1 = RGB(255, 193, 193) | ||||
| ROSYBROWN2 = RGB(238, 180, 180) | ||||
| ROSYBROWN3 = RGB(205, 155, 155) | ||||
| ROSYBROWN4 = RGB(139, 105, 105) | ||||
| ROYALBLUE = RGB(65, 105, 225) | ||||
| ROYALBLUE1 = RGB(72, 118, 255) | ||||
| ROYALBLUE2 = RGB(67, 110, 238) | ||||
| ROYALBLUE3 = RGB(58, 95, 205) | ||||
| ROYALBLUE4 = RGB(39, 64, 139) | ||||
| SALMON = RGB(250, 128, 114) | ||||
| SALMON1 = RGB(255, 140, 105) | ||||
| SALMON2 = RGB(238, 130, 98) | ||||
| SALMON3 = RGB(205, 112, 84) | ||||
| SALMON4 = RGB(139, 76, 57) | ||||
| SANDYBROWN = RGB(244, 164, 96) | ||||
| SAPGREEN = RGB(48, 128, 20) | ||||
| SEAGREEN1 = RGB(84, 255, 159) | ||||
| SEAGREEN2 = RGB(78, 238, 148) | ||||
| SEAGREEN3 = RGB(67, 205, 128) | ||||
| SEAGREEN4 = RGB(46, 139, 87) | ||||
| SEASHELL1 = RGB(255, 245, 238) | ||||
| SEASHELL2 = RGB(238, 229, 222) | ||||
| SEASHELL3 = RGB(205, 197, 191) | ||||
| SEASHELL4 = RGB(139, 134, 130) | ||||
| SEPIA = RGB(94, 38, 18) | ||||
| SGIBEET = RGB(142, 56, 142) | ||||
| SGIBRIGHTGRAY = RGB(197, 193, 170) | ||||
| SGICHARTREUSE = RGB(113, 198, 113) | ||||
| SGIDARKGRAY = RGB(85, 85, 85) | ||||
| SGIGRAY12 = RGB(30, 30, 30) | ||||
| SGIGRAY16 = RGB(40, 40, 40) | ||||
| SGIGRAY32 = RGB(81, 81, 81) | ||||
| SGIGRAY36 = RGB(91, 91, 91) | ||||
| SGIGRAY52 = RGB(132, 132, 132) | ||||
| SGIGRAY56 = RGB(142, 142, 142) | ||||
| SGIGRAY72 = RGB(183, 183, 183) | ||||
| SGIGRAY76 = RGB(193, 193, 193) | ||||
| SGIGRAY92 = RGB(234, 234, 234) | ||||
| SGIGRAY96 = RGB(244, 244, 244) | ||||
| SGILIGHTBLUE = RGB(125, 158, 192) | ||||
| SGILIGHTGRAY = RGB(170, 170, 170) | ||||
| SGIOLIVEDRAB = RGB(142, 142, 56) | ||||
| SGISALMON = RGB(198, 113, 113) | ||||
| SGISLATEBLUE = RGB(113, 113, 198) | ||||
| SGITEAL = RGB(56, 142, 142) | ||||
| SIENNA = RGB(160, 82, 45) | ||||
| SIENNA1 = RGB(255, 130, 71) | ||||
| SIENNA2 = RGB(238, 121, 66) | ||||
| SIENNA3 = RGB(205, 104, 57) | ||||
| SIENNA4 = RGB(139, 71, 38) | ||||
| SILVER = RGB(192, 192, 192) | ||||
| SKYBLUE = RGB(135, 206, 235) | ||||
| SKYBLUE1 = RGB(135, 206, 255) | ||||
| SKYBLUE2 = RGB(126, 192, 238) | ||||
| SKYBLUE3 = RGB(108, 166, 205) | ||||
| SKYBLUE4 = RGB(74, 112, 139) | ||||
| SLATEBLUE = RGB(106, 90, 205) | ||||
| SLATEBLUE1 = RGB(131, 111, 255) | ||||
| SLATEBLUE2 = RGB(122, 103, 238) | ||||
| SLATEBLUE3 = RGB(105, 89, 205) | ||||
| SLATEBLUE4 = RGB(71, 60, 139) | ||||
| SLATEGRAY = RGB(112, 128, 144) | ||||
| SLATEGRAY1 = RGB(198, 226, 255) | ||||
| SLATEGRAY2 = RGB(185, 211, 238) | ||||
| SLATEGRAY3 = RGB(159, 182, 205) | ||||
| SLATEGRAY4 = RGB(108, 123, 139) | ||||
| SNOW1 = RGB(255, 250, 250) | ||||
| SNOW2 = RGB(238, 233, 233) | ||||
| SNOW3 = RGB(205, 201, 201) | ||||
| SNOW4 = RGB(139, 137, 137) | ||||
| SPRINGGREEN = RGB(0, 255, 127) | ||||
| SPRINGGREEN1 = RGB(0, 238, 118) | ||||
| SPRINGGREEN2 = RGB(0, 205, 102) | ||||
| SPRINGGREEN3 = RGB(0, 139, 69) | ||||
| STEELBLUE = RGB(70, 130, 180) | ||||
| STEELBLUE1 = RGB(99, 184, 255) | ||||
| STEELBLUE2 = RGB(92, 172, 238) | ||||
| STEELBLUE3 = RGB(79, 148, 205) | ||||
| STEELBLUE4 = RGB(54, 100, 139) | ||||
| TAN = RGB(210, 180, 140) | ||||
| TAN1 = RGB(255, 165, 79) | ||||
| TAN2 = RGB(238, 154, 73) | ||||
| TAN3 = RGB(205, 133, 63) | ||||
| TAN4 = RGB(139, 90, 43) | ||||
| TEAL = RGB(0, 128, 128) | ||||
| THISTLE = RGB(216, 191, 216) | ||||
| THISTLE1 = RGB(255, 225, 255) | ||||
| THISTLE2 = RGB(238, 210, 238) | ||||
| THISTLE3 = RGB(205, 181, 205) | ||||
| THISTLE4 = RGB(139, 123, 139) | ||||
| TOMATO1 = RGB(255, 99, 71) | ||||
| TOMATO2 = RGB(238, 92, 66) | ||||
| TOMATO3 = RGB(205, 79, 57) | ||||
| TOMATO4 = RGB(139, 54, 38) | ||||
| TURQUOISE = RGB(64, 224, 208) | ||||
| TURQUOISE1 = RGB(0, 245, 255) | ||||
| TURQUOISE2 = RGB(0, 229, 238) | ||||
| TURQUOISE3 = RGB(0, 197, 205) | ||||
| TURQUOISE4 = RGB(0, 134, 139) | ||||
| TURQUOISEBLUE = RGB(0, 199, 140) | ||||
| VIOLET = RGB(238, 130, 238) | ||||
| VIOLETRED = RGB(208, 32, 144) | ||||
| VIOLETRED1 = RGB(255, 62, 150) | ||||
| VIOLETRED2 = RGB(238, 58, 140) | ||||
| VIOLETRED3 = RGB(205, 50, 120) | ||||
| VIOLETRED4 = RGB(139, 34, 82) | ||||
| WARMGREY = RGB(128, 128, 105) | ||||
| WHEAT = RGB(245, 222, 179) | ||||
| WHEAT1 = RGB(255, 231, 186) | ||||
| WHEAT2 = RGB(238, 216, 174) | ||||
| WHEAT3 = RGB(205, 186, 150) | ||||
| WHEAT4 = RGB(139, 126, 102) | ||||
| WHITE = RGB(255, 255, 255) | ||||
| WHITESMOKE = RGB(245, 245, 245) | ||||
| WHITESMOKE = RGB(245, 245, 245) | ||||
| YELLOW1 = RGB(255, 255, 0) | ||||
| YELLOW2 = RGB(238, 238, 0) | ||||
| YELLOW3 = RGB(205, 205, 0) | ||||
| YELLOW4 = RGB(139, 139, 0) | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     import time | ||||
|     ledcount = 9 | ||||
|     lc = LedControl('COM3') | ||||
|     while(True): | ||||
|         for led in range(ledcount): | ||||
|             lc.set_one(led, BLUEVIOLET) | ||||
|             lc.show() | ||||
|             time.sleep(0.1) | ||||
|         lc.show_all(BLACK) | ||||
|         time.sleep(0.1) | ||||
							
								
								
									
										119
									
								
								mediacontrol.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								mediacontrol.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | ||||
| import asyncio | ||||
| from threading import Thread | ||||
| import logging | ||||
| import time | ||||
| 
 | ||||
| 
 | ||||
| class SessionPlaybackStatus: | ||||
| 
 | ||||
|     Changing: 2 # Das Medium ändert sich. | ||||
|     Closed:	0	# Das Medium ist geschlossen. | ||||
|     Opened:	1   # Das Medium wird geöffnet. | ||||
|     Paused:	5   # Das Medium wird angehalten. | ||||
|     Playing: 4	# Die Medien werden abspielt. | ||||
|     Stopped: 3  # Das Medium wird beendet. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| class MediaControl(Thread): | ||||
| 
 | ||||
|     __init_handler = [] | ||||
|     __session_changed_handler = [] | ||||
|     __running = True | ||||
| 
 | ||||
|              | ||||
|     def run(self) -> None: | ||||
|         from  winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager, CurrentSessionChangedEventArgs | ||||
|         | ||||
|         self.MediaManager = MediaManager | ||||
|         # MediaManager.add_current_session_changed(Event) | ||||
|         for handler in self.__init_handler: | ||||
|             handler() | ||||
|         while self.__running: | ||||
|             time.sleep(1) | ||||
|         return super().run() | ||||
| 
 | ||||
|     def __init__(self) -> None: | ||||
|         super().__init__() | ||||
| 
 | ||||
|     def __current_session_changed(self, **kwargs): | ||||
|         print(kwargs) | ||||
|         for handler in self.__session_changed_handler: | ||||
|             handler() | ||||
| 
 | ||||
|     def add_init_handler(self, handler): | ||||
|         self.__init_handler.append(handler) | ||||
|      | ||||
|     # def add_session_changed_handler(self, handler): | ||||
|     #     self.__session_changed_handler.append(handler) | ||||
| 
 | ||||
|     def play(self): | ||||
|         asyncio.run(self.__try_play()) | ||||
| 
 | ||||
|     def pause(self): | ||||
|         asyncio.run(self.__try_pause()) | ||||
| 
 | ||||
|     def get_media_info(self): | ||||
|         return asyncio.run(self.__get_media_info()) | ||||
| 
 | ||||
|     def get_playback_info(self): | ||||
|         return asyncio.run(self.__get_playback_info()) | ||||
|      | ||||
|     def stop(self): | ||||
|         self.__running = False | ||||
| 
 | ||||
|     async def __try_play(self): | ||||
|         logging.debug("__try_play") | ||||
|         sessions = await self.MediaManager.request_async() | ||||
|         current_session = sessions.get_current_session() | ||||
|         if current_session: | ||||
|             print("try_play!!!!!!!") | ||||
|             await current_session.try_play_async() | ||||
| 
 | ||||
|     async def __try_pause(self): | ||||
|         logging.debug("__try_pause") | ||||
|         sessions = await self.MediaManager.request_async() | ||||
|         current_session = sessions.get_current_session() | ||||
|         if current_session: | ||||
|             await current_session.try_pause_async() | ||||
| 
 | ||||
|     async def __get_media_info(self): | ||||
|         sessions = await self.MediaManager.request_async() | ||||
| 
 | ||||
|         current_session = sessions.get_current_session() | ||||
|         if current_session:  # there needs to be a media session running | ||||
|             info = await current_session.try_get_media_properties_async() | ||||
| 
 | ||||
|             # song_attr[0] != '_' ignores system attributes | ||||
|             info_dict = {song_attr: info.__getattribute__(song_attr) for song_attr in dir(info) if song_attr[0] != '_'} | ||||
| 
 | ||||
|             # converts winrt vector to list | ||||
|             info_dict['genres'] = list(info_dict['genres']) | ||||
| 
 | ||||
|             return info_dict | ||||
| 
 | ||||
|     async def __get_playback_info(self): | ||||
|         sessions = await self.MediaManager.request_async() | ||||
| 
 | ||||
|         current_session = sessions.get_current_session() | ||||
|         if current_session:  # there needs to be a media session running | ||||
|             info = current_session.get_playback_info() | ||||
| 
 | ||||
|             # song_attr[0] != '_' ignores system attributes | ||||
|             info_dict = {playback_attr: info.__getattribute__(playback_attr) for playback_attr in dir(info) if playback_attr[0] != '_'} | ||||
| 
 | ||||
|             # converts winrt vector to list | ||||
|             info_dict['controls'] = {control_attr: info.controls.__getattribute__(control_attr) for control_attr in dir(info.controls) if control_attr[0] != '_'} | ||||
| 
 | ||||
|             return info_dict | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     def handle_init(): | ||||
|         print(mc.get_media_info()) | ||||
|         print(mc.get_playback_info()) | ||||
|         pass | ||||
| 
 | ||||
|     logging.getLogger().setLevel(logging.DEBUG) | ||||
|     mc = MediaControl() | ||||
|     mc.start() | ||||
|     mc.add_init_handler(handle_init) | ||||
| @ -1,3 +1,4 @@ | ||||
| winrt | ||||
| pywin32 | ||||
| python3-tk | ||||
| python3-tk | ||||
| pystray | ||||
							
								
								
									
										100
									
								
								resources.py
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								resources.py
									
									
									
									
									
								
							| @ -1,100 +0,0 @@ | ||||
| 
 | ||||
| class CLMgrMessage(): | ||||
|     CLMgrLineStateChangedMessage = 0      # state of at least one line has changed | ||||
|     CLMgrLineSelectionChangedMessage = 1  # line in focus has changed | ||||
|     CLMgrLineDetailsChangedMessage = 2    # details of at least one line have changed | ||||
|     CLMgrCallDetailsMessage = 4           # details of last call are available, post mortem for logging purpose | ||||
|     CLMgrServerDownMessage = 5            # server goes down, keep line manager, wait for ServerUp message | ||||
|     CLMgrServerUpMessage = 6              # server is up again, keep interfaces to line manger | ||||
|     CLMgrWaveDeviceChanged = 7            # speaker / micro has been switched on / off | ||||
|     CLMgrGroupCallNotificationMessage = 8 # notification about group call | ||||
|     CLMgrNumberOfLinesChangedMessage = 10 # the number of lines has changed | ||||
|     CLMgrClientShutDownRequest = 11       # Client Line Manager requests client to shutdown and release all interfaces | ||||
|     CLMgrLineStateChangedMessageEx = 28   # state of certain line has changed, lParam: LOWORD: line index of line that changed its state (starting with 0) HIWORD: new state of this line | ||||
| 
 | ||||
|     s = [ | ||||
|         "CLMgrLineStateChangedMessage", | ||||
|         "CLMgrLineSelectionChangedMessage", | ||||
|         "CLMgrLineDetailsChangedMessage", | ||||
|         "3", | ||||
|         "CLMgrCallDetailsMessage", | ||||
|         "CLMgrServerDownMessage", | ||||
|         "CLMgrServerUpMessage", | ||||
|         "CLMgrWaveDeviceChanged", | ||||
|         "CLMgrGroupCallNotificationMessage", | ||||
|         "9", | ||||
|         "CLMgrNumberOfLinesChangedMessage", | ||||
|         "CLMgrClientShutDownRequest", | ||||
|         "12", | ||||
|         "13", | ||||
|         "14", | ||||
|         "15", | ||||
|         "16", | ||||
|         "17", | ||||
|         "18", | ||||
|         "19", | ||||
|         "20", | ||||
|         "21", | ||||
|         "22", | ||||
|         "23", | ||||
|         "24", | ||||
|         "25", | ||||
|         "26", | ||||
|         "27", | ||||
|         "CLMgrLineStateChangedMessageEx" | ||||
|     ] | ||||
| 
 | ||||
| class LineState(): | ||||
|     Inactive = 0                        # line is inactive | ||||
|     HookOffInternal = 1                 # off hook, internal dialtone | ||||
|     HookOffExternal = 2                 # off hook, external dialtone | ||||
|     Ringing = 3                         # incoming call, ringing | ||||
|     Dialing = 4                         # outgoing call, we are dialing, no sound | ||||
|     Alerting = 5                        # outgoing call, alerting = ringing on destination | ||||
|     Knocking = 6                        # outgoing call, knocking = second call ringing on destination | ||||
|     Busy = 7                            # outgoing call, destination is busy | ||||
|     Active = 8                          # incoming / outgoing call, logical and physical connection is established | ||||
|     OnHold = 9                          # incoming / outgoing call, logical connection is established, destination gets music on hold | ||||
|     ConferenceActive = 10               # incoming / outgoing conference, logical and physical connection is established | ||||
|     ConferenceOnHold = 11               # incoming / outgoing conference, logical connection is established, not physcically connected | ||||
|     Terminated = 12                     # incoming / outgoing connection / call has been disconnected | ||||
|     Transferring = 13                   # special LSOnHold, call is awaiting to be transferred, peer gets special music on hold | ||||
|     Disabled = 14                       # special LSInactive: wrap up time | ||||
| 
 | ||||
|     s = [ | ||||
|         "Inactive", | ||||
|         "HookOffInternal", | ||||
|         "HookOffExternal", | ||||
|         "Ringing", | ||||
|         "Dialing", | ||||
|         "Alerting", | ||||
|         "Knocking", | ||||
|         "Busy", | ||||
|         "Active", | ||||
|         "OnHold", | ||||
|         "ConferenceActive", | ||||
|         "ConferenceOnHold", | ||||
|         "Terminated", | ||||
|         "Transferring", | ||||
|         "Disabled" | ||||
|     ] | ||||
| 
 | ||||
| class DisconnectReason(): | ||||
|     Normal = 0 | ||||
|     Busy = 1 | ||||
|     Rejected = 2 | ||||
|     Cancelled = 3 | ||||
|     Transferred = 4 | ||||
|     JoinedConference = 5 | ||||
|     NoAnswer = 6 | ||||
|     TooLate = 7 | ||||
|     DirectCallImpossible = 8 | ||||
|     WrongNumber = 9 | ||||
|     Unreachable = 10 | ||||
|     CallDiverted = 11 | ||||
|     CallRoutingFailed = 12 | ||||
|     PermissionDenied = 13 | ||||
|     NetworkCongestion = 14 | ||||
|     NoChannelAvailable = 15 | ||||
|     NumberChanged = 16 | ||||
|     IncompatibleDestination = 17 | ||||
							
								
								
									
										44
									
								
								swyx-media-control.spec
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								swyx-media-control.spec
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| # -*- mode: python ; coding: utf-8 -*- | ||||
| 
 | ||||
| 
 | ||||
| block_cipher = None | ||||
| 
 | ||||
| 
 | ||||
| a = Analysis(['gui.py'], | ||||
|              pathex=['X:\\Documents\\Projekte\\Simon\\python media controll'], | ||||
|              binaries=[], | ||||
|              datas=[('favicon.ico', '.')], | ||||
|              hiddenimports=[], | ||||
|              hookspath=[], | ||||
|              hooksconfig={}, | ||||
|              runtime_hooks=[], | ||||
|              excludes=[], | ||||
|              win_no_prefer_redirects=False, | ||||
|              win_private_assemblies=False, | ||||
|              cipher=block_cipher, | ||||
|              noarchive=False) | ||||
| pyz = PYZ(a.pure, a.zipped_data, | ||||
|              cipher=block_cipher) | ||||
| 
 | ||||
| exe = EXE(pyz, | ||||
|           a.scripts,  | ||||
|           [], | ||||
|           exclude_binaries=True, | ||||
|           name='swyx-media-control', | ||||
|           debug=False, | ||||
|           bootloader_ignore_signals=False, | ||||
|           strip=False, | ||||
|           upx=True, | ||||
|           console=False, | ||||
|           disable_windowed_traceback=False, | ||||
|           target_arch=None, | ||||
|           codesign_identity=None, | ||||
|           entitlements_file=None , icon='favicon.ico') | ||||
| coll = COLLECT(exe, | ||||
|                a.binaries, | ||||
|                a.zipfiles, | ||||
|                a.datas,  | ||||
|                strip=False, | ||||
|                upx=True, | ||||
|                upx_exclude=[], | ||||
|                name='swyx-media-control') | ||||
							
								
								
									
										221
									
								
								swyxcontrol.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								swyxcontrol.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,221 @@ | ||||
| import asyncio | ||||
| from threading import Thread | ||||
| import logging | ||||
| import time | ||||
| import logging | ||||
| import pythoncom | ||||
| 
 | ||||
| class CLMgrMessage(): | ||||
|     CLMgrLineStateChangedMessage = 0      # state of at least one line has changed | ||||
|     CLMgrLineSelectionChangedMessage = 1  # line in focus has changed | ||||
|     CLMgrLineDetailsChangedMessage = 2    # details of at least one line have changed | ||||
|     CLMgrCallDetailsMessage = 4           # details of last call are available, post mortem for logging purpose | ||||
|     CLMgrServerDownMessage = 5            # server goes down, keep line manager, wait for ServerUp message | ||||
|     CLMgrServerUpMessage = 6              # server is up again, keep interfaces to line manger | ||||
|     CLMgrWaveDeviceChanged = 7            # speaker / micro has been switched on / off | ||||
|     CLMgrGroupCallNotificationMessage = 8 # notification about group call | ||||
|     CLMgrNumberOfLinesChangedMessage = 10 # the number of lines has changed | ||||
|     CLMgrClientShutDownRequest = 11       # Client Line Manager requests client to shutdown and release all interfaces | ||||
|     CLMgrLineStateChangedMessageEx = 28   # state of certain line has changed, lParam: LOWORD: line index of line that changed its state (starting with 0) HIWORD: new state of this line | ||||
| 
 | ||||
|     s = [ | ||||
|         "CLMgrLineStateChangedMessage", | ||||
|         "CLMgrLineSelectionChangedMessage", | ||||
|         "CLMgrLineDetailsChangedMessage", | ||||
|         "3", | ||||
|         "CLMgrCallDetailsMessage", | ||||
|         "CLMgrServerDownMessage", | ||||
|         "CLMgrServerUpMessage", | ||||
|         "CLMgrWaveDeviceChanged", | ||||
|         "CLMgrGroupCallNotificationMessage", | ||||
|         "9", | ||||
|         "CLMgrNumberOfLinesChangedMessage", | ||||
|         "CLMgrClientShutDownRequest", | ||||
|         "12", | ||||
|         "13", | ||||
|         "14", | ||||
|         "15", | ||||
|         "16", | ||||
|         "17", | ||||
|         "18", | ||||
|         "19", | ||||
|         "20", | ||||
|         "21", | ||||
|         "22", | ||||
|         "23", | ||||
|         "24", | ||||
|         "25", | ||||
|         "26", | ||||
|         "27", | ||||
|         "CLMgrLineStateChangedMessageEx" | ||||
|     ] | ||||
| 
 | ||||
| class LineState(): | ||||
|     Inactive = 0                        # line is inactive | ||||
|     HookOffInternal = 1                 # off hook, internal dialtone | ||||
|     HookOffExternal = 2                 # off hook, external dialtone | ||||
|     Ringing = 3                         # incoming call, ringing | ||||
|     Dialing = 4                         # outgoing call, we are dialing, no sound | ||||
|     Alerting = 5                        # outgoing call, alerting = ringing on destination | ||||
|     Knocking = 6                        # outgoing call, knocking = second call ringing on destination | ||||
|     Busy = 7                            # outgoing call, destination is busy | ||||
|     Active = 8                          # incoming / outgoing call, logical and physical connection is established | ||||
|     OnHold = 9                          # incoming / outgoing call, logical connection is established, destination gets music on hold | ||||
|     ConferenceActive = 10               # incoming / outgoing conference, logical and physical connection is established | ||||
|     ConferenceOnHold = 11               # incoming / outgoing conference, logical connection is established, not physcically connected | ||||
|     Terminated = 12                     # incoming / outgoing connection / call has been disconnected | ||||
|     Transferring = 13                   # special LSOnHold, call is awaiting to be transferred, peer gets special music on hold | ||||
|     Disabled = 14                       # special LSInactive: wrap up time | ||||
| 
 | ||||
|     s = [ | ||||
|         "Inactive", | ||||
|         "HookOffInternal", | ||||
|         "HookOffExternal", | ||||
|         "Ringing", | ||||
|         "Dialing", | ||||
|         "Alerting", | ||||
|         "Knocking", | ||||
|         "Busy", | ||||
|         "Active", | ||||
|         "OnHold", | ||||
|         "ConferenceActive", | ||||
|         "ConferenceOnHold", | ||||
|         "Terminated", | ||||
|         "Transferring", | ||||
|         "Disabled" | ||||
|     ] | ||||
| 
 | ||||
| class DisconnectReason(): | ||||
|     Normal = 0 | ||||
|     Busy = 1 | ||||
|     Rejected = 2 | ||||
|     Cancelled = 3 | ||||
|     Transferred = 4 | ||||
|     JoinedConference = 5 | ||||
|     NoAnswer = 6 | ||||
|     TooLate = 7 | ||||
|     DirectCallImpossible = 8 | ||||
|     WrongNumber = 9 | ||||
|     Unreachable = 10 | ||||
|     CallDiverted = 11 | ||||
|     CallRoutingFailed = 12 | ||||
|     PermissionDenied = 13 | ||||
|     NetworkCongestion = 14 | ||||
|     NoChannelAvailable = 15 | ||||
|     NumberChanged = 16 | ||||
|     IncompatibleDestination = 17 | ||||
| 
 | ||||
| class SwyxControlException(Exception): | ||||
|      | ||||
|     def __init__(self, msg, *args: object) -> None: | ||||
|         self.msg = msg | ||||
|         super().__init__(*args) | ||||
| 
 | ||||
| class SwyxControl(Thread): | ||||
| 
 | ||||
|     __running = True | ||||
|     phone_mgr = None | ||||
|     __line_state_changed_hander = [] | ||||
|     __phone_mgr_connected_hander = [] | ||||
|     all_lines_inactive = False | ||||
| 
 | ||||
|     class __PhoneLineEventHandler(): | ||||
|         outer: 'SwyxControl' = None | ||||
| 
 | ||||
|         def OnDispOnLineMgrNotification(self, msg, param, returns=""): | ||||
|             if not self.outer: | ||||
|                 logging.debug("self.outer not set") | ||||
|                 return True | ||||
|             logging.debug("msg: {}\tparam: {}\treturns: {}".format(msg, param,returns)) | ||||
|             if msg == CLMgrMessage.CLMgrLineStateChangedMessage: | ||||
|                 self.outer._handle_line_state_changed(msg, param) | ||||
|             return True | ||||
| 
 | ||||
|         def setOuter(self, outer: 'SwyxControl'): | ||||
|             logging.debug("set outer class") | ||||
|             self.outer = outer | ||||
| 
 | ||||
|     def _handle_line_state_changed(self, msg, param): | ||||
|         line = self.phone_mgr.DispGetLine(param) | ||||
|         logging.debug("Line: {} {} / {}".format( | ||||
|             param, | ||||
|             LineState.s[line.DispState], | ||||
|             LineState.s[msg] | ||||
|             ) | ||||
|         ) | ||||
|         self.all_lines_inactive = self.__all_lines_inactive() | ||||
|         for handler in self.__line_state_changed_hander: | ||||
|             handler(line) | ||||
| 
 | ||||
|     def __init__(self) -> None: | ||||
|         super().__init__() | ||||
|         pass | ||||
| 
 | ||||
|     def __all_lines_inactive(self)  -> bool: | ||||
|         '''returns true if all lines are inactive''' | ||||
|         for linenum in range(self.phone_mgr.DispNumberOfLines): | ||||
|             line = self.phone_mgr.DispGetLine(linenum) | ||||
|             if line.DispState != LineState.Inactive: | ||||
|                 return False | ||||
|         return True | ||||
| 
 | ||||
|     def add_line_state_changed_handler(self, handler): | ||||
|         '''handler called when CLMgrMessage.CLMgrLineStateChangedMessage | ||||
|         is fired | ||||
|          | ||||
|         def handler(line): | ||||
|             if line.DispState == LineState.Ringing: | ||||
|                 print("Ringing") | ||||
|             if line.DispState == LineState.HookOffInternal: | ||||
|                 print("HookOffInternal") | ||||
|         sc.add_line_state_changed_handler(handler) | ||||
|         ''' | ||||
|         self.__line_state_changed_hander.append(handler) | ||||
| 
 | ||||
|     def add_phone_mgr_connected_handler(self, handler): | ||||
|         ''' | ||||
|         handler called when CLMgr.ClientLineMgr dispatched | ||||
|          | ||||
|         def handler(): | ||||
|             print("connected") | ||||
|         sc.add_phone_mgr_connected_handler(handler) | ||||
|         ''' | ||||
|         self.__phone_mgr_connected_hander.append(handler) | ||||
|      | ||||
|     def stop(self): | ||||
|         '''stops the running thread''' | ||||
|         self.__running = False | ||||
| 
 | ||||
|     def run(self): | ||||
|         # Initialize | ||||
|         import win32com.client | ||||
|         #pythoncom.CoInitialize(pythoncom.COINIT_MULTITHREADED) | ||||
|         #try: | ||||
|         self.phone_mgr = win32com.client.Dispatch("CLMgr.ClientLineMgr") | ||||
|         self.all_lines_inactive = self.__all_lines_inactive() | ||||
|         for handler in self.__phone_mgr_connected_hander: | ||||
|             handler() | ||||
|         # except Exception: | ||||
|         #     raise SwyxControlException("Swyx Client not installed") | ||||
|         self.e = win32com.client.WithEvents("CLMgr.ClientLineMgr", self.__PhoneLineEventHandler) | ||||
|         self.e.setOuter(self) | ||||
|         while self.__running: | ||||
|             pythoncom.PumpWaitingMessages() | ||||
|             time.sleep(0.1) | ||||
|      | ||||
| if __name__ == "__main__": | ||||
|     logging.getLogger().setLevel(logging.DEBUG) | ||||
|     def line_change_handler(line): | ||||
|         if line.DispState == LineState.Ringing: | ||||
|             print("Ringing") | ||||
|         if line.DispState == LineState.HookOffInternal: | ||||
|             print("HookOffInternal") | ||||
|      | ||||
|     def phone_mgr_connected_handler(): | ||||
|         print(sc.all_lines_inactive) | ||||
| 
 | ||||
|     sc = SwyxControl() | ||||
|     sc.add_line_state_changed_handler(line_change_handler) | ||||
|     sc.add_phone_mgr_connected_handler(phone_mgr_connected_handler) | ||||
|     sc.start() | ||||
|     pass | ||||
| @ -1,9 +1,12 @@ | ||||
| from collections import defaultdict | ||||
| from enum import Enum | ||||
| from threading import Thread | ||||
| import win32api | ||||
| import win32con | ||||
| import win32gui | ||||
| import win32ts | ||||
| import time | ||||
| import ctypes | ||||
| 
 | ||||
| 
 | ||||
| class SessionEvent(Enum): | ||||
| @ -22,14 +25,32 @@ class SessionEvent(Enum): | ||||
|     SESSION_REMOTE_CONTROL = 0x9  # WTS_SESSION_REMOTE_CONTROL | ||||
| 
 | ||||
| 
 | ||||
| class WorkstationMonitor: | ||||
|     CLASS_NAME = "WorkstationMonitor" | ||||
|     WINDOW_TITLE = "Workstation Event Monitor" | ||||
| class LockscreenMonitor(Thread): | ||||
|     CLASS_NAME = "LockscreenMonitor" | ||||
|     WINDOW_TITLE = "Lockscreen Event Monitor" | ||||
|     __running = True | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self.window_handle = None | ||||
|         self.event_handlers = defaultdict(list) | ||||
|         self._register_listener() | ||||
|         super().__init__() | ||||
| 
 | ||||
|     def run(self) -> None: | ||||
|         while self.__running: | ||||
|             self.listen() | ||||
|             time.sleep(0.1) | ||||
|      | ||||
|     def stop(self): | ||||
|         self.__running = False | ||||
|         exit_code = 0 | ||||
|         win32gui.PostQuitMessage(exit_code) | ||||
| 
 | ||||
|     def screen_locked(self) -> bool: | ||||
|         if (ctypes.windll.User32.GetForegroundWindow() % 10 == 0): | ||||
|             return True  | ||||
|         else: | ||||
|             return False | ||||
| 
 | ||||
|     def _register_listener(self): | ||||
|         wc = win32gui.WNDCLASS() | ||||
| @ -51,11 +72,7 @@ class WorkstationMonitor: | ||||
|         win32ts.WTSRegisterSessionNotification(self.window_handle, scope) | ||||
| 
 | ||||
|     def listen(self): | ||||
|         win32gui.PumpMessages() | ||||
| 
 | ||||
|     def stop(self): | ||||
|         exit_code = 0 | ||||
|         win32gui.PostQuitMessage(exit_code) | ||||
|         win32gui.PumpWaitingMessages() | ||||
| 
 | ||||
|     def _window_procedure(self, window_handle: int, message: int, event_id, session_id): | ||||
|         """ | ||||
| @ -78,11 +95,11 @@ class WorkstationMonitor: | ||||
|         for handler in self.event_handlers[SessionEvent.ANY]: | ||||
|             handler(event) | ||||
| 
 | ||||
|     def register_handler(self, event: SessionEvent, handler: callable): | ||||
|         self.event_handlers[event].append(handler) | ||||
|     def register_handler(self, handler: callable): | ||||
|         self.event_handlers[SessionEvent.ANY].append(handler) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     m = WorkstationMonitor() | ||||
|     m = LockscreenMonitor() | ||||
|     m.register_handler(SessionEvent.ANY, handler=print) | ||||
|     m.listen() | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user