initial commit

This commit is contained in:
2025-06-24 15:10:49 +02:00
commit 0bb1605068
24 changed files with 3449 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

9
README.md Normal file
View File

@@ -0,0 +1,9 @@
Order of Operations:
- start program
- check if adis is open (2 instances)
- yes -> continue
- no -> exit
- await press of spacebar
- take over control:
-

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
images/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/exemplar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
images/exemplar_ident.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

6
images/hello.py Normal file
View File

@@ -0,0 +1,6 @@
def main():
print("Hello from magazinaenderung!")
if __name__ == "__main__":
main()

BIN
images/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/loading.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
images/new_search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/notation.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
images/print_ok.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
images/save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
images/save_ok.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

64
main.py Normal file
View File

@@ -0,0 +1,64 @@
import keyboard
from src.adischeck import is_adis_running, get_active_name, print_new_signature, adis_get_signature, adis_save_and_enter_exemplar, new_search, taskswitcher_name
import pyautogui
from src.database import Database
import time
import sys
import clipboard
catalogue_pid = None
print_pid = None
database = Database()
def main():
global catalogue_pid, print_pid
if not is_adis_running():
print("aDISCl is not running. Please start all required aDIS instances and try again.")
return
print("aDISCl is running. Proceeding to capture PIDs...")
print("Press 'c' to capture the PID of the Catalogue aDIS instance.")
keyboard.wait('c')
#press backspace to clear any previous input
catalogue_pid = get_active_name()
print("Captured Catalogue PID:", catalogue_pid)
pyautogui.hotkey("ctrl", "a") # Switch to the next aDIS instance
pyautogui.hotkey("delete")
# pyautogui.press("backspace")
print("Press 'p' to capture the PID of the Print aDIS instance.")
keyboard.wait('p')
print_pid = get_active_name()
print("Captured Print PID:", print_pid)
pyautogui.hotkey("ctrl", "a") # Switch to the next aDIS instance
pyautogui.hotkey("delete")
if catalogue_pid and print_pid:
print("Both Catalogue and Print PIDs captured successfully.")
print("Switching back to Catalogue aDIS instance...")
taskswitcher_name(catalogue_pid) # Switch to Catalogue aDIS instance
# pyautogui.hotkey("alt", "s") # Open the search dialog in Catalogue aDIS
else:
print("Failed to capture one or both PIDs. Please ensure you have the correct aDIS instances open.")
print("Exiting the program.")
sys.exit(1)
while True:
keyboard.wait('space')
print("Space key pressed. Switching to Catalogue aDIS instance...")
time.sleep(5)
text = adis_get_signature()
new = database.insert_ma(text)
clipboard.copy(new) # Copy the new signature to clipboard
print(text, new)
pyautogui.hotkey('ctrl', 'v') # Select all text
mednr = adis_save_and_enter_exemplar(new) # Example usage with a new signature
print("finished main work, printing new signature")
time.sleep(1)
print_new_signature(catalogue_pid, print_pid, mednr)
new_search()
if __name__ == "__main__":
main()
# time.sleep(5) # Wait for a few seconds before starting
# print_new_signature("3 - PHFR: Katalog - aDIS/Client", "4 - PHFR(42): Exemplare - aDIS/Client", "004862920129")

21
pyproject.toml Normal file
View File

@@ -0,0 +1,21 @@
[project]
name = "magazinaenderung"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"clipboard>=0.0.4",
"keyboard>=0.13.5",
"opencv-python>=4.11.0.86",
"psutil>=7.0.0",
"pyautogui>=0.9.54",
"pytesseract>=0.3.13",
"pywin32>=310",
"winregistry>=2.1.1",
]
[dependency-groups]
dev = [
"nuitka>=2.7.10",
]

0
src/__init__.py Normal file
View File

209
src/adischeck.py Normal file
View File

@@ -0,0 +1,209 @@
import keyboard
import psutil
import pygetwindow
import pyautogui
import time
import clipboard
from src.cursor import classify_cursor, get_current_hcursor
def is_adis_running():
for proc in psutil.process_iter(['pid', 'name']):
if proc.info['name'].startswith('aDISCl'):
return True
return False
def get_active_name():
#get the active window's name
active_window = pygetwindow.getActiveWindow()
if active_window is not None:
return active_window.title
return None
def taskswitcher():
# Simulate Alt+Tab to switch tasks
import pyautogui
pyautogui.hotkey('alt', 'tab')
def taskswitcher_name(name):
#switch to application with the given name
import pygetwindow as gw
try:
window = gw.getWindowsWithTitle(name)[0]
if window.isMinimized:
window.restore() # Restore the window if it's minimized
window.activate() # Bring the window to the foreground
print(f"Switched to window: {name}")
except IndexError:
print(f"Window with title '{name}' not found. Please ensure the application is open.")
def adis_get_signature():
# get the current signature, create a new one and insert it into the needed places
print("Getting current signature...")
old_signature = None
pyautogui.click(566,86)
location_visible = False
time.sleep(5)
while not location_visible:
location = pyautogui.locateOnScreen('images/sacherschliessung.png', confidence=0.8, minSearchTime=1)
if location is None:
time.sleep(0.5)
else:
location_visible = True
print("Found the Sacherschliessung button on the screen.")
pyautogui.click(location)
notation_visible = False
while not notation_visible:
notation = pyautogui.locateOnScreen('images/notation.png', confidence=0.8)
if notation is None:
time.sleep(0.5)
else:
notation_visible = True
print("Found the Notation button on the screen.")
pyautogui.click(notation)
pyautogui.click(1216,665)
#store text at mouse position
pyautogui.hotkey('ctrl', 'a') # Select all text
pyautogui.hotkey('ctrl', 'c')
text = clipboard.paste()
print("Text copied to clipboard:", text)
return text
def get_click_locations():
while True:
#if the user presses 'c', capture the current mouse position
keyboard.wait('c')
x, y = pyautogui.position()
print(f"Captured mouse position: ({x}, {y})")
# Store the position in a list or dictionary for later use
with open('click_locations.txt', 'a') as f:
f.write(f"{x}, {y}\n")
print("Mouse position saved. Press 'c' again to capture another position or 'q' to quit.")
if keyboard.is_pressed('q'):
print("Exiting the position capture loop.")
break
def save_part():
save_location = None
while save_location is None:
save_location = pyautogui.locateOnScreen('images/save.png', confidence=0.8)
if save_location is None:
print("Save button not found, retrying...")
time.sleep(1)
else:
print("Save button found, clicking...")
pyautogui.click(save_location)
time.sleep(1.5)
def commit_changes():
pyautogui.keyDown("alt")
pyautogui.press("b")
time.sleep(0.6)
pyautogui.press( "l") # Select all text
pyautogui.keyUp("alt")
time.sleep(1)
while pyautogui.locateOnScreen('images/save_ok.png', confidence=0.6, minSearchTime=1) is None:
time.sleep(1)
save_ok = pyautogui.locateOnScreen('images/save_ok.png', confidence=0.6)
pyautogui.click(save_ok)
print("Changes committed successfully.")
def adis_save_and_enter_exemplar(new_signature):
# Simulate the action of saving and entering the exemplar
save_part()
#move mouse down 300 px to be in scrollable area
while pyautogui.locateOnScreen('images/exemplar.png', confidence=0.6, minSearchTime=1) is None:
time.sleep(1)
pyautogui.move(0, 300)
print("Exemplar button found, continuing...")
#scroll page down to the exemplar button
pyautogui.scroll(-5000)
pyautogui.click(499,974)
exemplar = pyautogui.locateOnScreen('images/exemplar.png', confidence=0.6)
pyautogui.click(exemplar)
time.sleep(1)
while pyautogui.locateOnScreen('images/exemplar_ident.png', confidence=0.6, minSearchTime=1) is None:
time.sleep(1)
pyautogui.move(125,0)
pyautogui.click()
time.sleep(1)
while pyautogui.locateOnScreen('images/save.png', confidence=0.6, minSearchTime=1) is None:
time.sleep(1)
pyautogui.click(1325,250)
pyautogui.hotkey('ctrl', 'a') # Select all text
pyautogui.typewrite(new_signature)
save_part()
while pyautogui.locateOnScreen('images/back.png', confidence=0.6, minSearchTime=1) is None:
time.sleep(1)
pyautogui.doubleClick(585,357)
time.sleep(0.2)
pyautogui.hotkey('ctrl', 'c')
time.sleep(0.2)
text = clipboard.paste()
print("Text copied to clipboard:", text)
pyautogui.click(pyautogui.locateOnScreen('images/back.png', confidence=0.6))
while pyautogui.locateOnScreen('images/info.png', confidence=0.6, minSearchTime=1) is None:
time.sleep(1)
time.sleep(1)
print("Arrived at Info page, committing changes...")
commit_changes()
return text
def print_new_signature(catalogue_name:str, print_name:str, mednr:str):
taskswitcher_name(print_name)
time.sleep(1)
#check if active window is named print_name
active_window = get_active_name()
if active_window != print_name:
print(f"Active window is not '{print_name}', switching to it...")
taskswitcher_name(print_name)
time.sleep(2)
pyautogui.click()
print("Please press space to print the new signature.")
# keyboard.wait('space') # Wait for the user to press space to print
pyautogui.press('space') # Simulate pressing space to print
#sleep as long as the cursor is not arrow, ibeam or hand
while True:
cursor = get_current_hcursor()
cursor_name = classify_cursor(cursor)
if cursor_name in ['arrow', 'ibeam', 'hand']:
print(f"Cursor is now {cursor_name}, proceeding...")
break
else:
print(f"Cursor is {cursor_name}, waiting...")
time.sleep(1)
time.sleep(1)
taskswitcher_name(catalogue_name)
def new_search():
pyautogui.hotkey("alt", "s")
time.sleep(2)
while True:
if pyautogui.locateOnScreen('images/new_search.png', confidence=0.8, minSearchTime=1.5) is None:
print("Searching")
else:
print("Found the New Search button, clicking...")
break
#press arrow up
pyautogui.click(480,280)
if __name__ == "__main__":
time.sleep(5) # Wait for a few seconds before starting
# commit_changes()
#new_search()
get_click_locations()

94
src/cursor.py Normal file
View File

@@ -0,0 +1,94 @@
import ctypes
from ctypes import wintypes
import time
# ---------------------------------------------------------------------
# Helper definitions missing from ctypes.wintypes
# ---------------------------------------------------------------------
HCURSOR = wintypes.HANDLE
class POINT(ctypes.Structure):
_fields_ = [("x", wintypes.LONG),
("y", wintypes.LONG)]
class CURSORINFO(ctypes.Structure):
_fields_ = [("cbSize", wintypes.DWORD),
("flags", wintypes.DWORD),
("hCursor", HCURSOR),
("ptScreenPos", POINT)]
# ---------------------------------------------------------------------
# Win-API bindings
# ---------------------------------------------------------------------
user32 = ctypes.WinDLL("user32", use_last_error=True)
GetCursorInfo = user32.GetCursorInfo
GetCursorInfo.restype = wintypes.BOOL
GetCursorInfo.argtypes = [ctypes.POINTER(CURSORINFO)]
LoadCursorW = user32.LoadCursorW
LoadCursorW.restype = HCURSOR
LoadCursorW.argtypes = [wintypes.HINSTANCE, wintypes.LPCWSTR]
# --- helper: C's MAKEINTRESOURCE -------------------------------
def MAKEINTRESOURCE(i: int) -> wintypes.LPCWSTR:
"""Cast an integer resource ID to LPCWSTR (same trick as MAKEINTRESOURCE)."""
return ctypes.cast(ctypes.c_void_p(i & 0xFFFF), wintypes.LPCWSTR)
# Standard resource IDs (IDC_* values)
IDC = {
"arrow": 32512,
"ibeam": 32513,
"wait": 32514,
"cross": 32515,
"uparrow": 32516,
"sizenwse": 32642,
"sizenesw": 32643,
"sizewe": 32644,
"sizens": 32645,
"sizeall": 32646,
"no": 32648,
"hand": 32649,
"appstarting": 32650,
"help": 32651,
}
# Pre-load the handles for the standard cursors
STANDARD_CURSORS = {
name: LoadCursorW(None, MAKEINTRESOURCE(res_id))
for name, res_id in IDC.items()
}
CURSOR_SHOWING = 0x00000001
# ---------------------------------------------------------------------
# Utility functions
# ---------------------------------------------------------------------
def get_current_hcursor() -> HCURSOR | None:
"""Return the HCURSOR currently visible on screen, or None if none."""
ci = CURSORINFO()
ci.cbSize = ctypes.sizeof(ci)
if GetCursorInfo(ctypes.byref(ci)) and ci.flags & CURSOR_SHOWING:
return ci.hCursor
return None
def classify_cursor(hcursor: HCURSOR) -> str:
"""Translate an HCURSOR to a readable name."""
for name, std_handle in STANDARD_CURSORS.items():
if hcursor == std_handle:
return name
return "custom or unknown"
# ---------------------------------------------------------------------
# Demo: watch the cursor and report changes for 10 s
# ---------------------------------------------------------------------
if __name__ == "__main__":
print("Watching cursor for 10 seconds — move the mouse or open menus …")
last = None
t_end = time.time()
while time.time() < t_end:
cur = get_current_hcursor()
if cur and cur != last:
print("Now showing:", classify_cursor(cur))
last = cur
time.sleep(0.05)

95
src/database.py Normal file
View File

@@ -0,0 +1,95 @@
import sqlite3 as sql
from src.utils import SignatureType
MA_TABLE = """
CREATE TABLE IF NOT EXISTS ma (
id INTEGER PRIMARY KEY AUTOINCREMENT,
old_signature TEXT NOT NULL UNIQUE,
new_signature TEXT NOT NULL UNIQUE
)"""
MB_TABLE = """
CREATE TABLE IF NOT EXISTS mb (
id INTEGER PRIMARY KEY AUTOINCREMENT,
old_signature TEXT NOT NULL,
new_signature TEXT NOT NULL,
UNIQUE(old_signature, new_signature)
)"""
MC_TABLE = """
CREATE TABLE IF NOT EXISTS mc (
id INTEGER PRIMARY KEY AUTOINCREMENT,
old_signature TEXT NOT NULL,
new_signature TEXT NOT NULL,
UNIQUE(old_signature, new_signature)
)"""
class Database:
def __init__(self) -> None:
self.connection = sql.connect("adis.db")
self.create_tables()
def create_tables(self) -> None:
cursor = self.connection.cursor()
cursor.execute(MA_TABLE)
cursor.execute(MB_TABLE)
cursor.execute(MC_TABLE)
self.connection.commit()
def create_new_signature(self, table:str)->str:
"""Create a new signature for the given table.
The new signature is generated by using 01 / as prefix, then incrementing the number by 1 for each new entry."""
cursor = self.connection.cursor()
cursor.execute(f"SELECT COUNT(*) FROM {table}")
count = cursor.fetchone()[0]
signature_prefix = SignatureType.new_signature_prefix(table)
new_signature = f"{signature_prefix}{count + 1}"
return new_signature
def signature_exists(self, old_signature: str, table: str) -> bool:
"""Check if a signature already exists in the specified table."""
cursor = self.connection.cursor()
cursor.execute(f"SELECT COUNT(*) FROM {table} WHERE old_signature = ?", (old_signature,))
count = cursor.fetchone()[0]
return count > 0
def insert_ma(self, old_signature: str) -> str|None:
"""Insert an old signature into the ma table and return the new signature.
New Signatures is generated by using 01 / as prefix, then incrementing the number by 1 for each new entry."""
if self.signature_exists(old_signature, "ma"):
print(f"Error: The old_signature '{old_signature}' already exists in the ma table.")
return None
new_signature = self.create_new_signature("ma")
try:
cursor = self.connection.cursor()
cursor.execute("INSERT INTO ma (old_signature, new_signature) VALUES (?, ?)", (old_signature, new_signature))
self.connection.commit()
return new_signature
except sql.IntegrityError:
print(f"Error: The combination of old_signature '{old_signature}' and new_signature '{new_signature}' already exists.")
return None
def insert_mb(self, old_signature: str) -> str:
"""Insert an old signature into the mb table and return the new signature.
New Signatures is generated by using 02 / as prefix, then incrementing the number by 1 for each new entry."""
new_signature = self.create_new_signature("mb")
try:
cursor = self.connection.cursor()
cursor.execute("INSERT INTO mb (old_signature, new_signature) VALUES (?, ?)", (old_signature, new_signature))
self.connection.commit()
return new_signature
except sql.IntegrityError:
print(f"Error: The combination of old_signature '{old_signature}' and new_signature '{new_signature}' already exists.")
return None
def insert_mc(self, old_signature: str) -> str:
"""Insert an old signature into the mc table and return the new signature.
New Signatures is generated by using 03 / as prefix, then incrementing the number by 1 for each new entry."""
new_signature = self.create_new_signature("mc")
try:
cursor = self.connection.cursor()
cursor.execute("INSERT INTO mc (old_signature, new_signature) VALUES (?, ?)", (old_signature, new_signature))
self.connection.commit()
return new_signature
except sql.IntegrityError:
print(f"Error: The combination of old_signature '{old_signature}' and new_signature '{new_signature}' already exists.")
return None

32
src/utils.py Normal file
View File

@@ -0,0 +1,32 @@
import enum
class SignatureType(enum.Enum):
MA = "ma"
MB = "mb"
MC = "mc"
@classmethod
def from_string(cls, value: str) -> "SignatureType":
"""Convert a string to a SignatureType enum."""
match value.lower():
case "ma":
return cls.MA.value
case "mb":
return cls.MB.value
case "mc":
return cls.MC.value
case _:
raise ValueError(f"Unknown signature type: {value}")
@classmethod
def new_signature_prefix(cls, value: str) -> str:
"""Generate a new signature prefix based on the signature type."""
match value.lower():
case "ma":
return "01/ "
case "mb":
return "02/ "
case "mc":
return "03/ "
case _:
raise ValueError(f"Unknown signature type: {value}")

2908
uv.lock generated Normal file

File diff suppressed because it is too large Load Diff