mame webtv import sys, os, re, subprocess, ctypes, shutil, random import winreg, win32gui, win32process, win32con, win32pipe, win32file, pywintypes from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * import socket, time import threading # Mapping of machine codes to human-readable names MACHINE_NAMES = { mame webtv How to dowload it? mame webtv "wtv1bf0": "WebTV Classic (2MB)", "wtv1bfe": "WebTV Classic (Prototype)", "wtv1dev": "WebTV Classic Dev Box (4MB)", "wtv1dv2": "WebTV Classic Dev Box (2MB)", "wtv1pal": "WebTV Classic (PAL)", "wtv2drb": "WebTV Plus (Derby)", "wtv2lc2": "WebTV Plus (LC2)", "wtv2dev": "WebTV Plus (Virtual 16MB Dev)", "wtv2esr": "WebTV Echostar", mame webtv How to get it? mame webtv "wtv2jpc": "WebTV Classic (Japan)", "wtv2jpp": "WebTV Plus (Japan)", "wtv2ncl": "WebTV New Classic (BPS, 8MB)", "wtv2npl": "WebTV New Plus (16MB)", "wtv2utv": "Ultimate TV", "wtv2uvd": "Ultimate TV Dev Box (Fake)", "wtv2wld": "WebTV Italian Prototype" } class MameWorker(QThread): mame webtv How to use it? mame webtv window_found = pyqtSignal(int) # Signal to send back the HWND def __init__(self, command, parent=None): super().__init__(parent) self.command = command self.mame_hwnd = None self.process = None self._should_stop = False def run(self): mame webtv PasteShr mame webtv # Launch MAME process self.process = subprocess.Popen(self.command) pid = self.process.pid # Try to find the MAME window for _ in range(30): # Try for ~3 seconds hwnd = self._find_window_by_pid(pid) if hwnd: self.mame_hwnd = hwnd self.window_found.emit(hwnd) mame webtv How to dowload it? mame webtv break time.sleep(0.1) self.process.wait() def stop(self): self._should_stop = True if self.process and self.process.poll() is None: self.process.terminate() try: mame webtv PasteShr mame webtv self.process.wait(timeout=5) except subprocess.TimeoutExpired: self.process.kill() def _find_window_by_pid(self, target_pid): def callback(hwnd, pid_list): if win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd): _, pid = win32process.GetWindowThreadProcessId(hwnd) if pid == target_pid: pid_list.append(hwnd) mame webtv How to get it for free? mame webtv hwnds = [] win32gui.EnumWindows(callback, hwnds) return hwnds[0] if hwnds else None def send_key(self, key): try: pipe = win32pipe.CreateNamedPipe( r'\\.\pipe\mame_input', win32pipe.PIPE_ACCESS_OUTBOUND, win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT, mame webtv How to get it? mame webtv 1, 65536, 65536, 0, None ) win32pipe.ConnectNamedPipe(pipe, None) win32file.WriteFile(pipe, (key + "\n").encode()) win32pipe.DisconnectNamedPipe(pipe) except pywintypes.error as e: print("Pipe closed or failed:", e) win32file.CloseHandle(pipe) mame webtv How to use it? mame webtv class MainWindow(QMainWindow): append_text_signal = pyqtSignal(str) def closeEvent(self, event): self.stop_socket_server() if self.worker: self.stop_mame() super().closeEvent(event) # Ensure default cleanup continues mame webtv PasteShr mame webtv def __init__(self): super().__init__() self.diskpath = os.path.join(os.getcwd(), "disks") self.setWindowTitle("WebTV MAME Launcher") self.setGeometry(100, 100, 400, 100) self.server_socket = None self.conn = None self.server_thread = None mame webtv How to use it? mame webtv self.apply_dark_mode() # Create the Menu Bar self.create_menu_bar() main_widget = QWidget() self.settings = QSettings("zefie", "WebTVLauncher") self.setCentralWidget(main_widget) layout = QVBoxLayout() possible_executables = [ mame webtv How to dowload it? mame webtv "webtv.exe", "webtv", "webtv2.exe", "webtv2", "webtv1.exe", "webtv1", ] self.executable = None for prog in possible_executables: path = shutil.which(prog) mame webtv PasteShr mame webtv if path: self.executable = path break if not self.executable: print("Could not find mame executable (webtv, webtv1, webtv2)(.exe)") exit(1) # Dropdown self.dropdown = QComboBox() pattern = r'\((wtv[^)]+)\)' mame webtv How to use it? mame webtv data = subprocess.run([self.executable, '-listbios'], capture_output=True, text=True) matches = re.findall(pattern, data.stdout) # For each match, check MACHINE_NAMES for a friendly description items = [] for m in matches: desc = MACHINE_NAMES.get(m, "") if desc: items.append(f"{m} - {desc}") else: items.append(m) mame webtv How to get it? mame webtv self.dropdown.addItems(items) top_layout = QHBoxLayout() top_layout.setSizeConstraint(QLayout.SetFixedSize) sel_opt = QLabel("Select Machine:") top_layout.addWidget(sel_opt) ssid_static = QLabel("SSID:") ssid_static.setAlignment(Qt.AlignRight) top_layout.addWidget(ssid_static) self.ssid_label = QLabel("No SSID") top_layout.addWidget(self.ssid_label) mame webtv How to get it for free? mame webtv layout.addLayout(top_layout) layout.addWidget(self.dropdown) # Checkboxes checkboxes_layout = QHBoxLayout() self.verbose = QCheckBox("Verbose") self.mamedebug = QCheckBox("MAME Debugger") self.serialdbg = QCheckBox("Serial Debug") self.diskboot = QCheckBox("Disk Boot") self.diskboot.setChecked(True) mame webtv How to dowload it? mame webtv self.modem = QCheckBox("Modem") self.verbose.setChecked(True) self.modem.setChecked(True) self.mamedebug.setChecked(False) self.serialdbg.setChecked(True) self.bitblab = QLabel("BITB:") self.bitb = QLineEdit("touchppp.lan.zef:1122"); checkboxes_layout.addWidget(self.verbose) checkboxes_layout.addWidget(self.mamedebug) mame webtv How to use it? mame webtv checkboxes_layout.addWidget(self.serialdbg) checkboxes_layout.addWidget(self.modem) checkboxes_layout.addWidget(self.diskboot) bitb_layout = QHBoxLayout() bitb_layout.addWidget(self.bitblab) bitb_layout.addWidget(self.bitb) disk_layout = QHBoxLayout() self.disklab = QLabel("Disk:") self.disklab.hide() self.disk = QComboBox() mame webtv How to get it? mame webtv self.scan_disk_list() bitb_layout.addWidget(self.disklab) bitb_layout.addWidget(self.disk) layout.addLayout(checkboxes_layout) layout.addLayout(bitb_layout) layout.addLayout(disk_layout) # Button self.button = QPushButton("Launch MAME") mame webtv How to use it? mame webtv self.dropdown.currentTextChanged.connect(self.on_dropdown_changed) self.button.clicked.connect(self.on_button_click) self.modem.clicked.connect(self.on_modem_click) layout.addWidget(self.button) self.setMinimumWidth(1280) self.setMinimumHeight(792) # Multiline Text Area self.text_area = QTextEdit() self.text_area.setReadOnly(True) self.text_area.setContextMenuPolicy(Qt.CustomContextMenu) mame webtv How to get it for free? mame webtv self.text_area.customContextMenuRequested.connect(self.show_text_area_context_menu) hbox = QHBoxLayout() self.mame_window = QWidget(); self.mame_window.setFixedSize(800, 600) self.mame_window.setFocusPolicy(Qt.ClickFocus) self.mame_window.mousePressEvent = lambda event: self.mame_window.setFocus() self.mame_window.setStyleSheet("background-color: black; border: 1px solid #555;") hbox.addWidget(self.mame_window) hbox.addWidget(self.text_area) layout.addLayout(hbox) mame webtv How to dowload it? mame webtv input_layout = QHBoxLayout() self.single_line_input = QLineEdit() self.send_button = QPushButton("Send") self.send_button.clicked.connect(lambda: self.send_serial_data(self.single_line_input.text())) input_layout.addWidget(self.single_line_input) input_layout.addWidget(self.send_button) self.single_line_input.returnPressed.connect(self.send_button.click) layout.addLayout(input_layout) main_widget.setLayout(layout) self.text_area.setVisible(self.serialdbg.isChecked()) mame webtv How to dowload it? mame webtv self.text_area.setStyleSheet("font-family: monospace; font-size: 8pt;") #self.text_area.setLineWrapMode(QTextEdit.NoWrap) self.text_area.setPlaceholderText("Serial output will appear here...") self.serialdbg.toggled.connect(self.toggleSerialDebug) self.append_text_signal.connect(self.handle_serial_data) self.text_area.autoFormattingEnabled = False self.load_settings() self.on_dropdown_changed() def show_text_area_context_menu(self, position): mame webtv How to dowload it? mame webtv """Show context menu for the text area""" context_menu = QMenu(self) clear_action = QAction("Clear Output", self) clear_action.triggered.connect(self.text_area.clear) context_menu.addAction(clear_action) copy_action = QAction("Copy All", self) copy_action.triggered.connect(lambda: self.text_area.selectAll() or self.text_area.copy()) context_menu.addAction(copy_action) mame webtv PasteShr mame webtv save_action = QAction("Save to File...", self) save_action.triggered.connect(self.save_serial_output) context_menu.addAction(save_action) context_menu.exec_(self.text_area.mapToGlobal(position)) def save_serial_output(self): """Save serial output to a file""" options = QFileDialog.Options() mame webtv How to use it? mame webtv file_name, _ = QFileDialog.getSaveFileName(self, "Save Serial Output", "serial_output.txt", "Text Files (*.txt);;All Files (*)", options=options) if file_name: try: with open(file_name, 'w', encoding='utf-8') as f: f.write(self.text_area.toPlainText()) QMessageBox.information(self, "Success", f"Serial output saved to:\n{file_name}") except Exception as e: QMessageBox.critical(self, "Error", f"Failed to save file:\n{str(e)}") mame webtv How to get it for free? mame webtv def getMachine(self): return self.dropdown.currentText().split(' ')[0] def toggleSerialDebug(self, checked): self.text_area.setEnabled(checked) self.single_line_input.setEnabled(checked) self.send_button.setEnabled(checked) def send_serial_data(self, data): self.single_line_input.clear() mame webtv PasteShr mame webtv if not data: return if hasattr(self, 'conn') and self.conn: try: self.conn.sendall((data + '\n').encode('utf-8')) except Exception as e: self.append_text_signal.emit(f"Send error: {e}") else: self.append_text_signal.emit("No serial connection established.") mame webtv How to get it for free? mame webtv def handle_serial_data(self, data): """Append data to the text area.""" if isinstance(data, bytes): data = data.decode(errors='replace') # Handle backspace (byte 0x08): remove previous character cursor = self.text_area.textCursor() def handle_serial_data(self, data): """Append data to the text area.""" if isinstance(data, bytes): mame webtv How to get it? mame webtv data = data.decode(errors='replace') # Limit text area size to prevent memory issues with large amounts of data current_text = self.text_area.toPlainText() if len(current_text) > 100000: # If more than 100k characters # Keep only the last 50k characters lines = current_text.split('\n') # Keep approximately last half of the lines keep_lines = lines[len(lines)//2:] self.text_area.setPlainText('\n'.join(keep_lines)) mame webtv How to dowload it? mame webtv # Handle backspace (byte 0x08): remove previous character cursor = self.text_area.textCursor() if data and (data[-1] == '\x08' or data[-1] == chr(8)): # Remove the last character in the text area cursor.movePosition(cursor.End) cursor.deletePreviousChar() data = data[:-1] mame webtv How to dowload it? mame webtv # Handle carriage return (byte 0x0D): move to the start of the line if data and (data[-1] == '\r' or data[-1] == chr(13)): # Remove the carriage return character data = data[:-1] # Insert the data at the end of the text area if data: cursor = self.text_area.textCursor() cursor.movePosition(cursor.End) cursor.insertText(data) mame webtv How to dowload it? mame webtv self.text_area.setTextCursor(cursor) # Auto-scroll to bottom to show latest data scrollbar = self.text_area.verticalScrollBar() scrollbar.setValue(scrollbar.maximum()) # Check for "Disk Boot?" prompt after updating display last_text = self.text_area.toPlainText() if "Disk Boot?" in last_text and hasattr(self, 'conn') and self.conn and self.diskboot.isChecked(): try: mame webtv PasteShr mame webtv diskboot = "y\n" if self.diskboot.isChecked() else "n\n" self.conn.sendall(diskboot.encode()) self.text_area.clear() except Exception as e: self.append_text_signal.emit(f"Auto-response error: {e}") def get_ssid_crc(self, ssid): """ Compute a 2-digit hexadecimal CRC for the SSID. Only the first 14 characters of the ssid are used. mame webtv How to dowload it? mame webtv """ ssid = ssid[:14] crc = 0 # Process every two characters of the SSID as a byte. for i in range(0, len(ssid), 2): inbyte = int(ssid[i:i+2], 16) for _ in range(8, 0, -1): mix = (crc ^ inbyte) & 0x01 crc >>= 1 if mix != 0: mame webtv How to get it for free? mame webtv crc ^= 0x8C inbyte >>= 1 out = format(crc, 'x') if len(out) == 1: out = "0" + out return out def generate_ssid(self, manufacturer_id_checked): """ Generate an SSID based on a template. mame webtv How to get it? mame webtv The template "71xxxxxy00b002" has: - 'x' replaced by random hex digits (0-F) - 'y' replaced by "1" if manufacturer_id_checked is True; otherwise "0" The final SSID is the template plus a computed 2-digit CRC. """ ssid_template = "71xxxxxy00b002" ssid = ssid_template # Replace each occurrence of "x" with a random hex digit while "x" in ssid: mame webtv How to dowload it? mame webtv random_hex = format(random.randint(0, 15), 'x') ssid = ssid.replace("x", random_hex, 1) # Replace "y" based on the manufacturer_id_checked flag. if manufacturer_id_checked: ssid = ssid.replace("y", "1") else: ssid = ssid.replace("y", "0") # Append the CRC computed from the first 14 characters. mame webtv How to use it? mame webtv ssid_full = ssid + self.get_ssid_crc(ssid) return ssid_full def apply_dark_mode(self): """Detects Windows dark mode and applies a dark stylesheet.""" if self.is_windows_dark_mode(): self.setStyleSheet(self.dark_stylesheet()) def is_windows_dark_mode(self): mame webtv How to use it? mame webtv """Checks if Windows is in dark mode by reading the registry.""" try: key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize") value, _ = winreg.QueryValueEx(key, "AppsUseLightTheme") winreg.CloseKey(key) return value == 0 # 0 means dark mode is enabled, 1 means light mode except Exception: return False # Default to light mode if registry read fails def dark_stylesheet(self): mame webtv How to dowload it? mame webtv """Returns a dark mode stylesheet for PyQt5.""" return """ QWidget { background-color: #2b2b2b; color: #ffffff; } QComboBox, QLineEdit, QTextEdit, QPlainTextEdit { background-color: #3c3f41; color: #ffffff; border: 1px solid #555; } QPushButton { background-color: #555; color: white; border-radius: 4px; padding: 5px; } QPushButton:hover { background-color: #777; } QPushButton:pressed { background-color: #333; } QMenuBar { background-color: #2b2b2b; color: white; } QMenuBar::item { background: transparent; padding: 5px; } QMenuBar::item:selected { background: #444; } mame webtv How to dowload it? mame webtv QMenu { background-color: #2b2b2b; color: white; } QMenu::item:selected { background: #444; } QLabel { color: white; } QCheckBox { color: white; } """ def getMachineSSID(self, machine): try: filename = "roms/" + machine + "/ds2401.bin" with open(filename, "rb") as file: mame webtv How to get it? mame webtv data = file.read() hex_str = data.hex() return hex_str except FileNotFoundError: return "No SSID" def setMachineSSID(self, machine, ssid): filepath = "roms/" + machine filename = filepath + "/ds2401.bin" os.makedirs(filepath, exist_ok=True) mame webtv How to use it? mame webtv with open(filename, "wb") as file: data = bytes.fromhex(ssid) file.write(data) def createSSID(self): machine = self.getMachine() self.setMachineSSID(machine, self.generate_ssid(True)) self.readSSID() def readSSID(self): mame webtv How to use it? mame webtv machine = self.getMachine() try: self.ssid_label.setText(self.getMachineSSID(machine)) except: self.ssid_label.setText("No SSID") def scan_disk_list(self): img_files = [file for file in os.listdir(self.diskpath) if file.lower().endswith('.img')] self.disk.clear() mame webtv PasteShr mame webtv self.disk.addItems(img_files) def create_menu_bar(self): """Creates the top menu bar""" menubar = self.menuBar() # File Menu file_menu = menubar.addMenu("File") exit_action = QAction("Exit", self) exit_action.triggered.connect(self.close) mame webtv How to use it? mame webtv file_menu.addAction(exit_action) # Settings Menu tools_menu = menubar.addMenu("Tools") create_image = QAction("Create 1GB Disk Image", self) create_image.triggered.connect(self.create_disk_image_1g) create_image2 = QAction("Create 8GB Disk Image", self) create_image2.triggered.connect(self.create_disk_image_8g) create_ssid = QAction("Generate New SSID", self) create_ssid.triggered.connect(self.createSSID) mame webtv How to get it? mame webtv tools_menu.addAction(create_image) tools_menu.addAction(create_image2) tools_menu.addAction(create_ssid) # Settings Menu settings_menu = menubar.addMenu("Settings") save_action = QAction("Save Settings", self) save_action.triggered.connect(self.save_settings) settings_menu.addAction(save_action) mame webtv How to use it? mame webtv # PO Codes Menu po_menu = menubar.addMenu("PO Codes") po_action = QAction("411 - Technical Info", self) po_action.triggered.connect(self.send_po_411) po_menu.addAction(po_action) po_action = QAction("314159 - Ignore ROM Signature", self) po_action.triggered.connect(self.send_po_314159) po_menu.addAction(po_action) po_action = QAction("32768 - Blast NVRAM", self) mame webtv How to get it for free? mame webtv po_action.triggered.connect(self.send_po_32768) po_menu.addAction(po_action) po_action = QAction("93288 - Connect Setup", self) po_action.triggered.connect(self.send_po_93288) po_menu.addAction(po_action) po_action = QAction("8675309 - Minibrowser", self) po_action.triggered.connect(self.send_po_8675309) po_menu.addAction(po_action) # Help Menu mame webtv How to get it? mame webtv help_menu = menubar.addMenu("Help") about_action = QAction("About", self) about_action.triggered.connect(self.show_about_dialog) help_menu.addAction(about_action) def isMAMERunning(self): """Check if MAME is currently running""" if hasattr(self, 'worker') and self.worker and self.worker.isRunning(): return True mame webtv How to dowload it? mame webtv return False def send_po_preamble(self): if self.isMAMERunning(): self.worker.send_key('{F11}') self.worker.send_key('{F11}') def send_po_411(self): if self.isMAMERunning(): mame webtv How to get it? mame webtv self.send_po_preamble() self.worker.send_key("411") else: QMessageBox.warning(self, "Warning", "MAME is not running. Please launch MAME first.") def send_po_314159(self): if self.isMAMERunning(): self.send_po_preamble() self.worker.send_key("314159") else: mame webtv How to use it? mame webtv QMessageBox.warning(self, "Warning", "MAME is not running. Please launch MAME first.") def send_po_8675309(self): if self.isMAMERunning(): self.send_po_preamble() self.worker.send_key("8675309") else: QMessageBox.warning(self, "Warning", "MAME is not running. Please launch MAME first.") def send_po_93288(self): mame webtv How to use it? mame webtv if self.isMAMERunning(): self.send_po_preamble() self.worker.send_key("93288") else: QMessageBox.warning(self, "Warning", "MAME is not running. Please launch MAME first.") def send_po_32768(self): if self.isMAMERunning(): self.send_po_preamble() self.worker.send_key("32768") mame webtv PasteShr mame webtv else: QMessageBox.warning(self, "Warning", "MAME is not running. Please launch MAME first.") def create_disk_image_1g(self): self.create_disk_image(1) def create_disk_image_8g(self): self.create_disk_image(8) def create_disk_image(self, sizegb): mame webtv PasteShr mame webtv """Opens a save dialog and creates a 1GB empty disk image""" options = QFileDialog.Options() file_name, _ = QFileDialog.getSaveFileName(self, "Create Disk Image", "", "Disk Image (*.img);;All Files (*)", options=options) if file_name: try: with open(file_name, "wb") as f: f.seek((sizegb * 1024 * 1024 * 1024) - 1) # Seek to 1GB - 1 byte f.write(b'\0') # Write a single null byte to allocate space mame webtv How to get it? mame webtv QMessageBox.information(self, "Success", f"Disk image created:\n{file_name}") # Refresh disk list self.scan_disk_list() except Exception as e: QMessageBox.critical(self, "Error", f"Failed to create disk image:\n{str(e)}") mame webtv How to get it? mame webtv def show_about_dialog(self): """Displays an About dialog""" QMessageBox.information(self, "About", "WebTV MAME Launcher\nVersion 1.1\nCreated by zefie with PyQt5") def save_settings(self): """Save settings before closing""" self.settings.setValue("dropdownIndex", self.dropdown.currentIndex()) self.settings.setValue("verbose", self.verbose.isChecked()) self.settings.setValue("modem", self.modem.isChecked()) self.settings.setValue("mamedebug", self.mamedebug.isChecked()) mame webtv How to dowload it? mame webtv self.settings.setValue("serialdbg", self.serialdbg.isChecked()) self.settings.setValue("bitb", self.bitb.text()) self.settings.setValue("disk", self.disk.currentText()) def load_settings(self): """Load settings on startup""" self.dropdown.setCurrentIndex(self.settings.value("dropdownIndex", 0, type=int)) self.verbose.setChecked(self.settings.value("verbose", True, type=bool)) self.modem.setChecked(self.settings.value("modem", True, type=bool)) self.mamedebug.setChecked(self.settings.value("mamedebug", False, type=bool)) mame webtv How to dowload it? mame webtv self.serialdbg.setChecked(self.settings.value("serialdbg", True, type=bool)) self.bitb.setText(self.settings.value("bitb", "touchppp.lan.zef:1122")) self.diskboot.setChecked(self.settings.value("diskboot", True, type=bool)) self.disk.setCurrentText(self.settings.value("disk", "")) def on_dropdown_changed(self): self.readSSID() if self.getMachine()[3] == "1": self.disklab.hide() self.disk.hide() mame webtv How to get it for free? mame webtv elif (self.getMachine()[3] == "2" and (self.getMachine()[4] == "n" or self.getMachine()[4] == "w")): self.disklab.hide() self.disk.hide() elif self.getMachine()[3] == "2" and (self.getMachine()[4] != "n" and self.getMachine()[4] != "w"): self.disklab.show() self.disk.show() def on_modem_click(self): if self.modem.isChecked(): self.bitblab.show() mame webtv How to get it? mame webtv self.bitb.show() else: self.bitblab.hide() self.bitb.hide() def stop_mame(self): self.stop_socket_server() if self.worker and self.worker.isRunning(): self.worker.stop() self.worker.wait() mame webtv How to dowload it? mame webtv self.button.setText("Launch MAME") self.button.clicked.disconnect() self.button.clicked.connect(self.on_button_click) def embed_window(self, hwnd): """ Reparent the MAME window to self.mame_window directly using Win32 APIs. """ parent_hwnd = int(self.mame_window.winId()) mame webtv How to get it for free? mame webtv # Reparent MAME window to our QWidget win32gui.SetParent(hwnd, parent_hwnd) # Optional: remove window border/style style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE) style = style & ~win32con.WS_CAPTION & ~win32con.WS_THICKFRAME win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, style) # Resize MAME window to fill self.mame_window rect = self.mame_window.rect() mame webtv PasteShr mame webtv win32gui.SetWindowPos( hwnd, None, 0, 0, rect.width(), rect.height(), win32con.SWP_NOZORDER | win32con.SWP_SHOWWINDOW ) # Ensure MAME gets input ctypes.windll.user32.SetForegroundWindow(hwnd) def on_button_click(self): mame webtv How to use it? mame webtv self.text_area.clear() selected = self.getMachine() command = [self.executable, selected] command += ["-nomouse", "-nomax", "-window"] if self.verbose.isChecked(): command += ["-verbose"] if self.mamedebug.isChecked(): command += ["-debug"] if self.modem.isChecked(): if selected[3] == "1": mame webtv How to get it for free? mame webtv command += ["-spot:modem"] elif selected[3] == "2": command += ["-solo:modem"] command += ["null_modem"] command += ["-bitb1", "socket."+self.bitb.text()] if selected[3] == "2" and selected[4] != "n" and selected[4] != "w": command += ["-hard1", os.path.join(self.diskpath, self.disk.currentText())] if self.serialdbg.isChecked(): command += ["-bitb2", "socket.127.0.0.1:3344"] self.start_socket_server() mame webtv How to dowload it? mame webtv command += ["-skip_gameinfo"] command += ["-video", "sdl"] command += ["-keyboardprovider", "win32"] command += ["-autoboot_script", "mame_input_pipe.lua"] self.save_settings() print(f"{command}") # Run the command in another thread to avoid blocking the UI self.worker = MameWorker(command) self.worker.window_found.connect(self.embed_window) self.worker.start() mame webtv How to dowload it? mame webtv # Soft loop: process events while the worker thread is running self.button.setText("Stop MAME") self.button.clicked.disconnect() self.button.clicked.connect(self.stop_mame) while self.worker.isRunning(): QApplication.processEvents(QEventLoop.AllEvents, 100) self.button.setText("Launch MAME") self.button.clicked.disconnect() self.button.clicked.connect(self.on_button_click) self.mame_window.repaint() mame webtv How to use it? mame webtv def start_socket_server(self): # Stop any existing server first self.stop_socket_server() def handle_client(): try: self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Increase socket buffer sizes for high-volume data mame webtv How to get it for free? mame webtv self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536) self.server_socket.settimeout(1.0) # Add timeout to prevent hanging self.server_socket.bind(('127.0.0.1', 3344)) self.server_socket.listen(1) while True: try: self.conn, addr = self.server_socket.accept() # Increase connection buffer and set TCP_NODELAY for faster transmission self.conn.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536) mame webtv PasteShr mame webtv self.conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.conn.settimeout(0.05) # Shorter timeout for more responsive flushing # Buffer for accumulating partial data data_buffer = b'' while True: try: # Use larger buffer for high-volume data chunk = self.conn.recv(8192) mame webtv How to get it for free? mame webtv if not chunk: break data_buffer += chunk # Process and emit data more aggressively for better responsiveness while data_buffer: # Look for complete lines first if b'\n' in data_buffer: line, data_buffer = data_buffer.split(b'\n', 1) mame webtv How to get it for free? mame webtv # Include the newline in the output complete_line = line + b'\n' self.append_text_signal.emit(complete_line.decode(errors='replace')) else: # If no newline, emit data in smaller chunks for responsiveness # But wait a bit to see if more data comes quickly if len(data_buffer) > 256: # Reduced threshold for faster response # Emit partial data to keep display responsive self.append_text_signal.emit(data_buffer.decode(errors='replace')) data_buffer = b'' mame webtv How to dowload it? mame webtv else: # Small amount of data, break and wait for more or timeout break except socket.timeout: # On timeout, flush any remaining buffered data immediately if data_buffer: self.append_text_signal.emit(data_buffer.decode(errors='replace')) data_buffer = b'' # Check if we should stop mame webtv How to get it for free? mame webtv if not hasattr(self, 'server_socket') or self.server_socket is None: break continue except (ConnectionResetError, ConnectionAbortedError, OSError): # Connection was closed by client break # Flush any remaining data when connection closes if data_buffer: self.append_text_signal.emit(data_buffer.decode(errors='replace')) mame webtv How to get it for free? mame webtv except socket.timeout: # Check if we should stop if not hasattr(self, 'server_socket') or self.server_socket is None: break continue except OSError as e: if e.errno == 10048: # Address already in use self.append_text_signal.emit("Error: Port 3344 already in use. Try again.") break mame webtv How to use it? mame webtv elif "forcibly closed" in str(e) or "connection" in str(e).lower(): # Expected disconnection break else: print(f"Socket error: {e}") break except Exception as e: self.append_text_signal.emit(f"Socket server error: {e}") finally: mame webtv PasteShr mame webtv self.stop_socket_server() self.server_thread = threading.Thread(target=handle_client, daemon=True) self.server_thread.start() def stop_socket_server(self): """Properly close socket server and cleanup resources""" if hasattr(self, 'conn') and self.conn: try: self.conn.close() mame webtv How to use it? mame webtv except: pass self.conn = None if hasattr(self, 'server_socket') and self.server_socket: try: self.server_socket.close() except: pass self.server_socket = None mame webtv How to dowload it? mame webtv if hasattr(self, 'server_thread') and self.server_thread and self.server_thread.is_alive(): self.server_thread.join(timeout=1.0) # Wait up to 1 second for thread to finish if __name__ == "__main__": os.environ['PATH'] += ":" + os.path.dirname(os.path.abspath(__file__)) app = QApplication(sys.argv) window = MainWindow() window.show() mame webtv How to get it? mame webtv app.exec() #sys.exit(app.exec_()) mame webtv