Wenn man sich nicht auf ein Sleep verlassen will kann man auch per Schleife mit While _Ispressed(...) And Sleep(10) WEnd innerhalb des Aufrufs solange blockieren bis die Taste wieder losgelassen wurde. Dann wird auch alles nur 1x gesendet.
Beiträge von Mars
-
-
Schau dir mal die Hilfe zu _IsPressed an. Sollte dir das nicht weiterhelfen bastel ich gerne ein Beispiel
lg
M -
Nach der Einleitung hab ich 500 Zeilen hochkomplizierten Code erwartet den man mindestens eine Stunde studieren muss bevor man in etwa weiß wie er funktioniert
Die Drehfunktion zum Zeichnen ist super, ich habe eigentlich immer mit der Matrixvariante gearbeitet, deine Methode ist aber um ein vielfaches einfacher
lg
M -
Guten Tag,
Diese UDF ermöglicht das (relativ) einfache Erzeugen von COM-Objekten in AutoIt. Dabei wird die Syntax von Sprachen die OOP nativ unterstützen teilweise imitiert (wozu das Rad neu erfinden), sodass man sowohl als Einsteiger als auch als alter Hase schnell zurechtfindet.
Wie funktioniert das ganze?
Das ist eine gute Frage , es gibt die wunderbare BuiltIn Funktion ObjCreateInterface die so umständlich zu handhaben ist, dass niemand viel damit angefangen hat und niemals ans Licht kam was man damit alles anstellen kann. Die hier erzeugbaren Objekte bestehen aus einer DllStruct die Objektvariablen und Callbacks zu AutoIt-Funktionen beinhaltet. Da es sehr viel Aufwand ist diese Struct jedes Mal manuell zu erstellen nimmt einem die UDF diesen Part der Arbeit ab. Die AutoIt-Funktionen die später als Objekt-Methoden dienen muss man natürlich trotzdem von Hand schreiben.
Was geht:
- Objektvariablen MIT Datentyp (kein Variant, genauso wie die Datentypen in DllStructs)
- Methoden mit Alias, man kann also eine Funktion schreiben die zwar __IchBin_EinKomplizierterName_BerechnePI() heißt, vom Objekt aber als $o.PI aufgerufen werden kann (bei Methoden gilt etwas das für AutoIt-Funktionen nicht gilt, haben sie keinen Parameter kann man die Klammern weglassen)
- Objekte in Objekten (was wäre die Welt, wenn man ein Rechteck aus 4 Zahlen und nicht aus 2 Punkten definieren müsste)
- Zugriff auf Objektvariablen und Methoden von außerhalb und innerhalb von Objekten (jetzt auch ohne Maps, keine BETA Pflicht mehr)
- Vieles mehr (was man eben so alles anstellen kann)
Bekannte Bugs/Probleme/ToDo-Liste (je nachdem wie man es nennen will):
- Objektvariablen sind alle "privat", man kann nicht via $o.x auf die Variable x aus $o zugreifen. Man kann aber die Struct die die Variablen enthält auch von außerhalb erreichen und so die Objektvariablen lesen und schreiben... Das ganze lässt sich wrappen, aber (zumindest nach meinem Kenntnissstand) nicht trivial als $o.x.
- ByRef funktioniert in Objektmethoden nicht. (DllCallbackRegister will sowas nicht... ob man das wrappen kann muss noch erörtert werden, sieht aber schwierig aus)
- Arrays können nicht an Methoden übergeben werden. (DllCallbackRegister will sowas nicht... ob man das... siehe oben)
Edit: 18.Mär.19
Rebrand:
- Die UDF heißt jetzt NAUO (Native AutoItObject) um Namenskollisionen mit der AutoItObject UDF von ProgAndy zu verhindern. (Native weil keine DLLs oder andere Zusatzsoftware benötigt wird)
Added:
- Method(string, [string, [string, [string, [string]]]]) kann jetzt die Parameter auch im ersten String haben, z.B. Method('Math_Sqrt[Sqrt](double, double)') = Method('Math_Sqrt[Sqrt]', 'double', 'double')
- Var(Obj, string) -> Read Variable called "string"
- Var(Obj, string, x) -> Write x into Variable called "string"
BugFixes:
- Objekte ohne Variablen führen nun nicht mehr zum Absturz.
Script Breaking Changes:
- New('String', $this) liefert jetzt automatisch New('String', $this).Ptr, in alten Skripten muss also das .Ptr entfernt werden (verschachtelung von Objekten, Siehe Beispielskript 2).
Ladet den Anhang herunter und probiert die 4 Beispiele mal aus
Anregungen oder Wünsche oder Bugmeldungen sind gerne gesehen, nur so kann die UDF weiterentwickelt werden. Ich bin aber ein fauler Mensch und es kann Monate oder Jahre dauern bis ich an der UDF weiterarbeite
Alter inhalt
Seit AutoIt die Funktion ObjCreateInterface besitzt ist es möglich mit kleinem Aufwand "echte" Objekte zu erzeugen. In den letzten Tagen ist daraus eine kleine UDF entstanden. Sie befindet sich im Aufbau und bietet aktuell deutlich weniger als Konkurrenzprodukte welche auf externe Dateien wie DLLs, oder nicht Standard UDFs zurückgreifen. Sie soll auch keine echte Konkurrenz darstellen, sondern eine einfache und kleine Lösung bieten.
Für Interessierte:
Es steht jedem frei Features zu wünschen, Bugs zu melden oder Beispiele zu OOP und spezifischen Problemen zu verfassen (bitte im Thread hier posten). Dabei sollte darauf geachtet werden, dass die UDF möglichst unabhängig bleibt (also keine DLLs, keine nicht Standard UDFs und StandardUDFs nur im Notfall). Optimal wäre es natürlich, wenn man zu Problemen die man findet eine geeignete Lösung parat hat, falls dem nicht so ist kommt der Bug auf die Liste, gleiches gilt für Features.Manche Funktionen der UDF setzen die BETA voraus, so werden Methoden in Methoden Beispielsweise als Map gehandelt (sodass man möglichst einfach an die Methoden kommt).
Wir freuen uns über jeden der etwas zu der UDF sagt, oder sie verbessern/benutzen möchte.
Update 05.01.2019:
In letzter Zeit kamen mir ein paar Ideen wie man die "umständliche" Verwendung der UDF ein wenig auslagern kann, sodass die Bedienung stark vereinfacht wird (man kann Objekte jetzt "ähnlich" (aber nicht gleich) wie in anderen Sprachen deklarieren. Außerdem sind ein paar kleine neue Features/Fixes hinzugekommen. Das Ganze ist noch nicht gut kommentiert und UDF-Header mit Erklärungen gibt es auch erst später, aber man kann schonmal reinschauen.
Hinweis: Die Klassen müssen immer VOR der Verwendung deklariert werden, da AutoIt keine Keywords "Class" oder "Method" besitzt werden diese durch Funktionen imitiert die ausgeführt werden müssen bevor es möglich ist Instanzen einer Klasse zu erzeugen. Klassen also am besten Themenbedingt in einzelne Dateien verpacken und diese zu Beginn includen, dann kann nichts schiefgehen.
Die UDF + Beispiel gibts im Anhang.Offene Fragen:
-
Wie speichert man Objekte in Objektvariablen? (Diese Variablen sind nur primitive Datentypen, kann man ggf. via oPtr Objekte verschachteln?)- Kann es möglich sein Klassen innerhalb von Funktionen/Anderen Anweisungen zu deklarieren? (Aktuell MÜSSEN Klassen toplevel deklariert werden, da das Func-Keyword für Methoden benutzt wird was es leider ausschließt woanders ausgeführt zu werden....)
Wie immer gilt: Wer Vorschläge (Antworten) hat, her damit (auch wenn ich 3 Jahre brauche bis ich darauf zurück komme )
Gelöste Fragen:
# Objekte in Objekten # 06.01.2019
Erstmal wird ein Objekt automatisch gelöscht, sobald die letzte AutoIt-Interne Referenz verlorengeht. Also muss dafür gesorgt werden, dass Objekte die man nur via ptr speichern will dennoch erhalten bleiben. Zum Glück haben Objekte einen einzigartigen Ort im RAM (ptr) den man super als Hashkey benutzen kann, sodass jedes Objekt bei der Erzeugung in einem Hashtable hinterlegt wird. Möchte man nun via ptr darauf zugreifen muss man nur im HashTable wühlen und das Objekt wieder herausholen. Das geht von überall aus, sodass man Objekte in Objekten ohne Probleme als Variablentyp ptr speichern kann. Damit AutoIt korrekt löscht, wenn z.B. ein Objekt das Objekte enthält gelöscht wird muss der Destruktor benutzt werden, in diesem werden alle child Objekte abgearbeitet (aus dem Hashtable löschen). Dabei taucht ein neues Problem auf: Was ist, wenn ein Objekt in mehreren anderen Objekten enthalten ist? Dann wird es im Hashtable nur 1x hinterlegt und liefert eine ungültige Referenz sobald es gelöscht wird, obwohl es in anderen Objekten ggf. noch vorkommt. Abhilfe könnte hier ein Hash aus (ptr Child & ptr Parent) liefern, dann wird jedes Objekt so oft in den HT gelegt wie es referenziert wird. Da das ganze nicht so rund läuft wie ich es gerne hätte und vorallem noch NICHT automatisiert ist (man muss child Objekte explizit löschen, das lässt sich sicherlich wrappen, sodass man sich als Benutzer nicht darum kümmern muss) gibts noch kein Update der Dateien an dieser Stelle.
Update 06.01.2019:
Es ist nun möglich Objekte innerhalb von Objekten zu erzeugen. Die Ganze Sache ist noch etwas holprig (und nicht vollständig gewrappt) funktioniert aber schonmal. Daher gibt es ein Beispiel02 welches ein Rect durch 2xPoint definiert.
lg
M -
Alternativ geht auch @GUI_CtrlId oder @GUI_CtrlHandle. (Ersteres gibt die ID (also die Nummer) des Ctrls zurück, welches das Event ausgelöst hat und Letzteres das dazugehörige Handle)
Edit: Wobei "alternativ" Falsch ist. Ergänzend wäre besser, da es um Labels geht...
M
-
Die Tidy.exe liegt im Normalfall in C:\Program Files (x86)\AutoIt3\SciTE\tidy\tidy.exe.
Nicht direkt im AutoIt Ordner, sondern im SciTe Ordner. Ggf hilft es die SciTe Version von der Downloadseite zu installieren, die ist etwas umfangreicher als die Version im AutoIt-Installer.M
-
Zum Thema Zufall:
Habe schon ein paar Mal versucht einen "echten" Zufallsgenerator als reines Programm zu basteln indem irgendwelche Hardwarewerte angezapft werden. Leider macht einem Windows da einen dicken Strich durch die Rechnung, da viele Daten scheinbar in regelmäßigem Abstand ausgelesen werden und bei zu schneller Abfrage immer das gleiche ausgegeben wird. Und ein Zufallsgenerator der nur ein paar Byte pro Sek schafft, weil er auf irgendwelche Aktualisierungszyklen warten muss ist kacke. Radioaktivität ist sehr schön, und alpha Strahlung ist außerhalb des Körpers auch ungefährlich. Leider ist der Wissensstand eines normalen Deutschen in etwa so: "Atome sind giftig". Deshalb wird man eines Tages auch radioaktive Chips als Zufallsgenerator in Computern haben die irgend einen coolen Namen haben wie "True Random Tech" (und als Abkürzung "TRT Technologie", analog zum "LCD Display").Zum Thema Orwell:
Dystopien stellen doch nur eine Checkliste dar die die Regierungen nach und nach abarbeiten, oder habe ich da irgendwas missverstanden ? -
Wenn es dir ums Skalieren mit Beschränkungen geht hab ich kurz eine Funktion zusammengestrickt die die Bildgröße berechnen kann.
Als Beispiel wäre dein 3264x2448 Bild mit einer Beschränkung auf 1920x1080 -> 1440x1080.
Da jpg mit Blöcken arbeitet kann diese Funktion auch auf eine beliebige Blockgröße Runden. Dabei wird das Bild aber leicht verzerrt.AutoIt
Alles anzeigen#include <Array.au3> _ArrayDisplay(_Scale(3264, 2448, 1440, 768), 'Beispiel 1') _ArrayDisplay(_Scale(3264, 2448, 2048, 2048), 'Beispiel 2') _ArrayDisplay(_Scale(3264, 2448, 1920, 1080), 'Beispiel 3') _ArrayDisplay(_Scale(3264, 2448, 1920, 800), 'Beispiel 4') ; Ungerundet _ArrayDisplay(_Scale(3264, 2448, 1920, 800, 8), 'Beispiel 5') ; Auf 8 gerundet _ArrayDisplay(_Scale(3264, 2448, 1920, 800, 16), 'Beispiel 6') ; Auf 16 gerundet ; $iWSrc - Breite des Originals ; $iHSrc - Höhe des Originals ; $iWScale - PixelMaß Breite ; $iHScale - PixelMaß Höhe ; $iCap - Runden der Werte auf eine bestimmte Blockgröße, z.B. 16px. ; Returnwert: Array[2] -> [Berechnete Breite, Berechnete Höhe] ; Beispiel: _Scale(3264, 2448, 1920, 1080) = [1440, 1080] Func _Scale($iWSrc, $iHSrc, $iWScale, $iHScale, $iCap = 0) Local $nFactorW = $iWScale / $iWSrc, $nFactorH = $iHScale / $iHSrc, $nMulti = ($nFactorW > $nFactorH _ Or $nFactorW = $nFactorH) ? $nFactorH : $nFactorW, $aRet = [($iCap ? Round($iWSrc * $nMulti / $iCap, _ 0) * $iCap : $iWSrc * $nMulti), ($iCap ? Round($iHSrc * $nMulti / $iCap, 0) * $iCap : $iHSrc * $nMulti)] Return $aRet EndFunc
lg
M -
Eine vereinfachte Betrachtungsweise von Komplexität habe ich in AutoIt schonmal erklärt. Ob man da als Anfänger durchsteigt weiß ich leider nicht...
Komplexitätlg
M -
Die Aufteilung on Ring0 und Ring3 hat einen Sinn. "Programme" haben da unten nichts zu suchen.
Und als Treiber sind AutoIt-Skripte nicht benutzbar. Ein Treiber ist dafür da direkt die Hardware abzufragen, ggf. etwas mit den ermittelten Werten herumzurechnen und diese dann z.B. nach oben weiterzureichen. Für diesen Vorgang ist AutoIt viel zu langsam. Außerdem ist der Interpreter ein Klotz am Bein.
Im Regelfall wird hier C oder ASM benutzt.
Edit: Was willst du denn machen ? Villeicht kann man das auch einfacher lösen.
lg
M -
Ich glaube, das man den Code eines laufenden AutoIt Skripts nicht manipulieren kann. Immerhin wird er nicht einfach "ausgeführt" sondern interpretiert. Das bedeutet, das der Interpreter intern verschiedene Zustände haben kann. Diese Zustände hängen vom bisher gelaufenen Code ab. Ändert man nun einfach ein Stück des Codes bin ich sehr sicher, das der Interpreter (selbstverständlich ohne nachvollziehbaren Errorcode) abschmiert.
[100% Offtopic]
NomadMemory: Die Person die diese UDF geschrieben hat hat mehr erreicht, als dieses gesamte Forum in den letzten 100 Jahren. Wirklich JEDER der aus welchen Gründen auch immer irgendetwas mit AutoIt zu tun hatte, haben könnte, haben will, haben wird, hätte gehabt hat, usw kennt diese UDF. Wenn ich diesen Namen lese füllt sich mein Herz mit Neid, da es ein Anderer außer mir geschafft hat sich in alle Ewigkeit einen Namen zu machen, obwohl die Leistung für diesen Erfolg lächerlich gering ist. Ich bin dafür das jeder hier Anwesende eine MarsMemory, eine Make-GrafikMemory, eine AndyMemory, usw erstellt die jeweils den gleichen Funktionsumfang haben. Villeicht schaffen wir es auf dieses 20 Jahre alte Schiff aufzuspringen, um wenigstens ein kleines Bisschen Erfolg im Leben zu haben. Amen.
[/Bitte innerlich so lesen, als würden diese Worte in der Kirche vorgetragen werden] -
Was da genau passiert ist weiß keiner der keine Einsicht in den Code hat. Es heißt immer: Je mehr eine Funktion kann, desto langsamer ist sie im Vergleich zu einer Funktion die nur eine bestimmte Sache kann.
In AutoIt kann man aktuell mit einem Taschenmesser besser Schießen als mit der Magnum. -
Sieht tatsächlich so aus als wäre in die Stringfunktionen ein Sleep(10) in der Hauptschleife eingebaut worden...
-
Das erste was mir eingefallen ist ist ein Workaround mit einem Local Static Timer.
Die Funktion kann also nur 0.5s (natürlich beliebig veränderbar) nachdem sie zuletzt beendet wurde wieder aufgerufen werden. Ist glaube ich keine besonderst elegante Lösung, so bleibt aber der Fokus auf dem Inputfeld erhalten und trotzdem kann das Popup mit Return beendet werden.AutoIt
Alles anzeigen#include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <GUIListBox.au3> #include <StaticConstants.au3> #include <TabConstants.au3> #include <WindowsConstants.au3> #include <Misc.au3> ;~ #RequireAdmin $frmMain = GUICreate("", 170, 200) $Log_edtBot = GUICtrlCreateEdit("", 8, 35, 150, 150, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $ES_WANTRETURN, $ws_hscroll, $ws_vscroll), $WS_EX_CLIENTEDGE) ;untere Detailansicht GUICtrlSetBkColor(-1, "0xffffff") GUICtrlSetFont(-1, 10, 500, 0, "Arial") $Log_txtSkript = GUICtrlCreateInput("", 8, 8, 150, 25) ;~ $frmRefreshButton = GUICtrlCreateButton("", 8, 8, 20, 25) ;~ GUICtrlSetState($frmRefreshButton, $GUI_HIDE) GUISetState(@SW_SHOW) Global $Log_sUser, $iLog, $iEnter, $hPwrShell ;~ #Region Hotkeys ;~ Global $aAccelKeys[1][2] = [["{ENTER}", $frmRefreshButton]] ;~ GUISetAccelerators($aAccelKeys) ;~ #EndRegion While 1 $nMsg = GUIGetMsg(1) Switch $nMsg[0] Case $GUI_EVENT_CLOSE Switch $nMsg[1] Case $frmMain If $hPwrShell = True Then WinClose($hPwrShell) EndIf Exit Case Else GUISetState(@SW_SHOW, $frmMain) GUISetState(@SW_HIDE, $nMsg[1]) GUISetState(@SW_DISABLE, $nMsg[1]) GUISwitch($frmMain) EndSwitch ;~ Case $frmRefreshButton ;~ _Enter() Case $Log_txtSkript $iEnter = 1 EndSwitch If _IsPressed('0D') And ControlGetFocus($frmMain) <> 'Edit1' Then _Enter() WEnd #Region Enter Taste Func _Enter() Local Static $iTimer = TimerInit(), $bFirstrun = True If TimerDiff($iTimer) < 500 And Not $bFirstrun Then Return $bFirstrun = False ;1 = Details anzeigen _TestFunc() ;~ Switch $iEnter ;~ Case 1 ;~ If ControlGetFocus($frmMain) <> 'Edit1' Then ;~ MsgBox(0, "", "Details anzeigen") ;~ _TestFunc() ;~ Else ;~ MsgBox(0, "", "Details anzeigen") ;~ EndIf ;~ EndSwitch $iTimer = TimerInit() EndFunc #EndRegion Func _TestFunc() MsgBox(0, "", "TestFunc") EndFunc
-
Ich rate von versteckten Buttons ab. Ein einfacher Trick wäre die nutzung von _IsPressed.
Nachteil: Muss im Main Loop auftauchen -> verbraucht etwas Rechenzeit
Vorteil: Absolut Ctrl-Unabhängig, da einfach nur gecheckt wird ob eine Taste gedrückt wurde.AutoIt
Alles anzeigen#include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <GUIListBox.au3> #include <StaticConstants.au3> #include <TabConstants.au3> #include <WindowsConstants.au3> #include <Misc.au3> ;~ #RequireAdmin $frmMain = GUICreate("", 170, 200) $Log_edtBot = GUICtrlCreateEdit("", 8, 35, 150, 150, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $ES_WANTRETURN, $ws_hscroll, $ws_vscroll), $WS_EX_CLIENTEDGE) ;untere Detailansicht GUICtrlSetBkColor(-1, "0xffffff") GUICtrlSetFont(-1, 10, 500, 0, "Arial") $Log_txtSkript = GUICtrlCreateInput("", 8, 8, 150, 25) ;~ $frmRefreshButton = GUICtrlCreateButton("", 8, 8, 20, 25) ;~ GUICtrlSetState($frmRefreshButton, $GUI_HIDE) GUISetState(@SW_SHOW) Global $Log_sUser, $iLog, $iEnter, $hPwrShell ;~ #Region Hotkeys ;~ Global $aAccelKeys[1][2] = [["{ENTER}", $frmRefreshButton]] ;~ GUISetAccelerators($aAccelKeys) ;~ #EndRegion While 1 $nMsg = GUIGetMsg(1) Switch $nMsg[0] Case $GUI_EVENT_CLOSE Switch $nMsg[1] Case $frmMain If $hPwrShell = True Then WinClose($hPwrShell) EndIf Exit Case Else GUISetState(@SW_SHOW, $frmMain) GUISetState(@SW_HIDE, $nMsg[1]) GUISetState(@SW_DISABLE, $nMsg[1]) GUISwitch($frmMain) EndSwitch ;~ Case $frmRefreshButton ;~ _Enter() Case $Log_txtSkript $iEnter = 1 EndSwitch If _IsPressed('0D') And ControlGetFocus($frmMain) <> 'Edit1' Then _Enter() WEnd #Region Enter Taste Func _Enter() ;1 = Details anzeigen _TestFunc() ;~ Switch $iEnter ;~ Case 1 ;~ If ControlGetFocus($frmMain) <> 'Edit1' Then ;~ MsgBox(0, "", "Details anzeigen") ;~ _TestFunc() ;~ Else ;~ MsgBox(0, "", "Details anzeigen") ;~ EndIf ;~ EndSwitch EndFunc #EndRegion Func _TestFunc() MsgBox(0, "", "TestFunc") EndFunc
lg
M -
Eigentlich müsste das funktionieren (wenn es an die richtige Stelle gepackt wird). Du musst an die Stelle wo $frmRefreshButton abgefragt wird und dort eine Abfrage zum Fokus einbauen, sodass das Event (oder wie auch immer du das gemacht hast) nur ausgelöst wird wenn der Fokus stimmt.
Wenn das nicht läuft müssten wir einen Blick in den Code werfen.
(PS: Sry, wegen dem ersten Post, aus "dass das Programm beim schreiben in Editboxen die Entertaste vorübergehend "deaktiviert"" hab ich geschlossen das die Entertaste im Edit nicht funktionieren soll^^)
-
Aus der AutoIt Hilfe zu GuiCtrlCreateEdit: Defines the style of the control. See [url='../appendix/GUIStyles.htm#Edit']GUI Control Styles Appendix[/url]. default ( -1) : $ES_WANTRETURN, $WS_VSCROLL, $WS_HSCROLL, $ES_AUTOVSCROLL, $ES_AUTOHSCROLL forced styles : $ES_MULTILINE, $WS_TABSTOP only if not $ES_READONLY.
Der Standardstyle beinhaltet alle diese Komponenten. Wenn man einen Teil davon nicht braucht kann man manuell eigene Styles beim erstellen des GuiCtrlEdit angeben. In deinem Fall müsstest du jeden Style außer $ES_WANTRETURN benutzen damit die EditBox gleich bleibt aber kein Return mehr akzeptiert. -
Das ist der dazugehörige Code. (Der war doch gestern auch in der SB^^)
AutoIt
Alles anzeigenFunc __MyASM() _('use32') ; ASM von Mars@AutoIt.de 27.Mai.2015 ; Im Code wird SSE ausschließlich zum Zwischenspeichern von Konstanten ; oder Vairablen benutzt. Da der Input flexibel bleiben soll kann nicht ; von Breite- oder Höhewerten die durch 2,4,8,usw teilbar sind aus- ; gegangen werden. SSE würde den Programmieraufwand erhöhen und die ; Funktion läuft ohnehin schnell genug. _('mov eax, [esp+4]') ; 01 [00] - pInput ; 02 [04] - pOutput ; 03 [08] - WidthInput ; 04 [12] - HeightInput ; 05 [16] - SizePx ; 06 [20] - SizeLine ; 07 [24] - ColBG ; 08 [28] - WidthOutput ; 09 [32] - HeightOutput ; 10 [36] - PxInput (Anzahl Pixel) ; 11 [40] - PxOutput _('mov edi, [eax+00]') ; Pointer Input _('mov esi, [eax+04]') ; Pointer Output ; Hintergrund färben ; Der komplette Hintergrund wird _('mov ecx, [eax+40]') ; Anzahl Pixel Output _('mov edx, esi') ; Output Pointer _('mov ebx, [eax+24]') ; Hintergrundfarbe _('_ColBG:') ; Schleife zum Färben _('mov [edx], ebx') ; Farbe reinspachteln _('add edx, 4') ; 1 Px weiter _('dec ecx') ; Counter verringern _('ja _ColBG') ; Schleifenende ; Hauptschleife Vorbereitungen _('mov ecx, [eax+36]') ; Anzahl Pixel Input _('mov ebx, [eax+20]') ; SizeLine _('add ebx, [eax+16]') ; SizeLine + SizePx _('movd xmm7, ebx') ; xmm7 = $_Const01 = SizePx + SizeLine ; Input Pointer verschieben, weil wir Rückwärts laufen _('mov ebx, [eax+12]') ; WidthInput _('imul ebx, [eax+08]') ; HeightInput _('shl ebx, 2') ; BytesInput _('sub ebx, 4') ; UBound ist nicht gleich LBound ! _('add edi, ebx') ; edi zeigt jetzt auf den letzten Pixel statt auf den Ersten ; Hauptschleife _('_MainLoop:') ; Label der Hauptschleife _('push ecx') ; ecx sichern _('dec ecx') ; UBound Nummer 2 _('mov ebx, [edi]') ; Inputfarbe _('movd xmm6, ebx') ; Farbe in xmm6 sichern _('sub edi, 4') ; Direkt 1 Px weiter (obwohl der aktuelle noch nichtmal gezeichnet wurde) _('and ebx, 0xFF000000'); Alphakanal abchecken _('cmp ebx, 0xFF000000'); Ist der Pixel vollständig undurchsichtig ? _('jne _PxIsTrans') ; Wenn nicht -> Pixel überspringen ; Berechnung von x und y ; $x = Mod($i, $vLCD.x(03)) ; $y = Int($i / $vLCD.x(03)) _('mov ebx, [eax+08]') ; ebx = $vLCD.x(03) _('push eax') ; eax wird für div gebraucht -> eax auf den Stack _('push ebx') ; Den Wert brauchen wir gleich nochmal, so muss er nicht aus dem Ram geholt werden. _('mov edx, 0') ; edx bekommt den Modulo Wert, bei der Division stellt edx die ersten 32 Bit (die alle 0 sind) _('mov eax, ecx') ; eax = $i _('div ebx') ; wir Teilen edx:eax / ebx -> $i/$vLCD.x(03). Der Rest der Division liegt in edx, das Ergebnis in eax _('movd xmm1, edx') ; xmm1 = $x = Mod($i, $vLCD.x(03)) _('movd xmm2, eax') ; xmm2 = $y = Int($i / $vLCD.x(03)) ; $iTmp = Int($x / $vLCD.x(03)) * $vLCD.x(03) ; $y -= $iTmp _('pop ebx') ; ebx = $vLCD.x(03) _('mov eax, edx') ; eax = $x _('mov edx, 0') ; Die ersten 32Bit bei div sind leer... _('div ebx') ; Gleiches wie Oben. Ergebnis -> eax, Rest -> edx _('imul eax, ebx') ; eax = Int($x / $vLCD.x(03)) * $vLCD.x(03) _('movd ebx, xmm2') ; Leider haben wir kein freies Register gehabt -> y aus xmm2 holen. _('sub ebx, eax') ; ebx = $y - Int($x / $vLCD.x(03)) * $vLCD.x(03) _('pop eax') ; eax kann endlich wieder als Pointer benutzt werden. _('movd edx, xmm7') ; edx = $_Const01 _('imul ebx, edx') ; $y *= $_Const01 _('add ebx, [eax+20]') ; $y += $vLCD.x(06) _('movd xmm2, ebx') ; xmm2 = $y _('movd ebx, xmm1') ; Wiedermal fehlt ein zusätzliches Register -> x aus xmm1 holen _('imul ebx, edx') ; $x *= $_Const01 _('add ebx, [eax+20]') ; $x += $vLCD.x(06) _('movd xmm1, ebx') ; xmm1 = $x ; H Schleife Vorbereitungen _('push ecx') _('mov edx, [eax+16]') ; edx = SizePx = $vLCD.x(05) _('mov ebx, [eax+28]') ; edx = WidthOutput = $vLCD.x(08) _('push eax') ; eax -> Stack _('mov ecx, edx') ; ecx = $vLCD.x(05) _('_LoopH:') ; For $h = 0 To $vLCD.x(05) - 1 Step 1 _('movd eax, xmm2') ; eax = $y _('add eax, edx') ; eax = $y + $vLCD.x(05) _('sub eax, ecx') ; eax = $y + $h, da $h = $vLCD.x(05) - ecx _('imul eax, ebx') ; eax = ($y + $h) * $vLCD.x(05) _('push ebx') ; $vLCD.x(08) wird erstmal nicht mehr gebraucht _('movd ebx, xmm1') ; ebx = x _('add eax, ebx') ; eax = Pixelnummer _('shl eax, 2') ; Umrechnung in Bytes _('add eax, esi') ; eax = Position der Vordersten Pixel in jedem zu zeichnenden Rechteck _('mov ebx, eax') ; ebx = Kopie von eax ; W Schleife Vorbereitung _('push ecx') ; ecx wird wieder unser Counter _('push edx') ; Kuchen für alle ! _('mov ecx, edx') ; Counter einstellen _('shl edx, 2') ; Umrechnung in Bytes _('add eax, edx') ; siehe oben _('movd edx, xmm6') ; Wer weiß ob es besser ist aus einem 32er Register zu schreiben... _('_LoopW:') ; For $w = 0 To $vLCD.x(05) - 1 Step 1 _('sub eax, 4') ; siehe oben _('mov [eax], edx') ; Hier wird der Pixel erst gezeichnet. Auf diese eine Zeile ist das komplette Gebilde ausgelegt. _('dec ecx') ; _('jnz _LoopW') ; _('mov eax, ebx') ; eax wieder herstellen _('pop edx') ; _('pop ecx') ; _('pop ebx') ; _('dec ecx') ; _('jnz _LoopH') ; _('pop eax') ; _('pop ecx') ; _('_PxIsTrans:') ; _('pop ecx') ; _('dec ecx') ; _('jnz _MainLoop') ; _('ret 4') ; Wir haben 4 Bytes gebraucht für unseren Datenpointer in [esp+4] EndFunc
Alles was er macht ist eine kleine Bitmap (in diesem Fall 33x11 px) in die Form zu bringen die man auf der Uhr siehtUnd das ist der AutoIt-Code der genau das gleiche macht:
Code
Alles anzeigenFunc _LCD_Render(ByRef $aLCD) ; Extra schön einfach aufgebaut damit der Local $pLCD = DllStructGetPtr($aLCD[0]) Local $vLCD = DllStructCreate('int x[11]', $pLCD) ; 01 [00] - pInput ; 02 [04] - pOutput ; 03 [08] - WidthInput ; 04 [12] - HeightInput ; 05 [16] - SizePx ; 06 [20] - SizeLine ; 07 [24] - ColBG ; 08 [28] - WidthOutput ; 09 [32] - HeightOutput ; 10 [36] - PxInput (Anzahl Pixel) ; 11 [40] - PxOutput Local $vIn = DllStructCreate('int x[' & $vLCD.x(10) & ']', $vLCD.x(01)) Local $vOut = DllStructCreate('int x[' & $vLCD.x(11) & ']', $vLCD.x(02)) For $i = 0 To $vLCD.x(11) - 1 Step 1 $vOut.x(($i + 1)) = $vLCD.x(07) Next Local $x, $y, $iTmp, $_Const01 = $vLCD.x(06) + $vLCD.x(05) For $i = 0 To $vLCD.x(10) - 1 Step 1 If $vIn.x(($i + 1)) Then $x = Mod($i, $vLCD.x(03)) $y = Int($i / $vLCD.x(03)) $iTmp = Int($x / $vLCD.x(03)) * $vLCD.x(03) $y -= $iTmp $x *= $_Const01 $x += $vLCD.x(06) $y *= $_Const01 $y += $vLCD.x(06) For $h = 0 To $vLCD.x(05) - 1 Step 1 For $w = 0 To $vLCD.x(05) - 1 Step 1 $iTmp = $y $iTmp += $h $iTmp *= $vLCD.x(08) $iTmp += $x $iTmp += $w $vOut.x(($iTmp + 1)) = $vIn.x(($i + 1)) Next Next EndIf Next EndFunc
Die Funktion ist in AutoIt (wenn man die Rechtecke via GDI+ zeichnet und mit einigen Tricks arbeitet) auch sehr schnell, der Code hier ist extra so umgemodelt das er 1:1 in ASM übernommen werden kann. Die ASM Version ist aber schneller, egal wie viele Tricks man mit AutoIt + GDI+ einsetzt
Den Sinn der Sache muss ich noch herausfinden, hab die Funktion geschrieben weil ich ein Nokiafeeling haben wollte...
-
Hier gibts ne LCD Uhr
Spoiler anzeigen
AutoIt
Alles anzeigen#include <GDIPlus.au3> Opt('GUIOnEventMode', 1) Global Const $iCol1 = 0xFF404A57 ; Pixelfarbe Global Const $iCol2 = 0xFFA3B5A2 ; Hintergrundfarbe Global Const $iSizePx = 16 Global Const $iSizeLine = 2 Global Const $iW = 33 Global Const $iH = 11 Global $bExit = False _GDIPlus_Startup() Global $vPX = DllStructCreate('int x[' & $iW * $iH & ']') Global $aLCD = _LCD_New(DllStructGetPtr($vPX), $iW, $iH, $iSizePx, $iSizeLine, $iCol2) Global $hGUI = GUICreate('LCD Uhr', $aLCD[0].WidthOutput, $aLCD[0].HeightOutput) Global $hBmp = _GDIPlus_BitmapCreateFromScan0($aLCD[0].WidthOutput, $aLCD[0].HeightOutput, $GDIP_PXF32ARGB, $aLCD[0].WidthOutput * 4, $aLCD[0].pOutput) Global $hGfx = _GDIPlus_GraphicsCreateFromHWND($hGUI) For $x = 0 To $iW - 1 Step 1 For $y = 0 To $iH - 1 Step 1 If $x = 0 Or $x = $iW - 1 Or $y = 0 Or $y = $iH - 1 Then DllStructSetData($vPX, 1, $iCol1, $x + $y * $iW + 1) Next Next GUISetBkColor('0x' & StringRight(Hex($iCol2, 8), 6), $hGUI) GUISetState(@SW_SHOW, $hGUI) GUISetOnEvent(-3, 'x', $hGUI) OnAutoItExitRegister('_Release') GUIRegisterMsg(0xF, 'WM_PAINT') While Sleep(20) And Not $bExit _Uhr() WEnd Func _Uhr() Local Static $iTimer = @SEC If $iTimer <> @SEC Then $iTimer = @SEC Local $s = @SEC, $m = @MIN, $h = @HOUR, $z = IsInt($s / 2) For $i = 0 To 3 Step 1 DllStructSetData($vPX, 1, $z ? $iCol1 : 0, 144 + IsInt(($i + 1) / 2) * 66 + ($i > 1) * 10) Next _Ziffer(3, 3, Int($h/10)) _Ziffer(7, 3, $h - Int($h/10)*10) _Ziffer(13, 3, Int($m/10)) _Ziffer(17, 3, $m - Int($m/10)*10) _Ziffer(23, 3, Int($s/10)) _Ziffer(27, 3, $s - Int($s/10)*10) _LCD_RenderASM($aLCD) WM_PAINT() EndIf EndFunc Func _Ziffer($x, $y, $n) Local Static $a[] = ['111101101101111','110010010010111','111001111100111','111001011001111','100101101111001','111100111001111','100100111101111','111001001001001','111101111101111','111101111001001'] If IsString($a[0]) Then For $i = 0 To 9 Step 1 $a[$i] = StringSplit($a[$i], '', 2) Next EndIf For $i = 0 To 14 Step 1 DllStructSetData($vPX, 1, (($a[$n])[$i] = 1 ? $iCol1 : 0), $x + $y * $iW + 1 + Mod($i, 3) + Int($i/3)*$iW) Next EndFunc Func WM_PAINT() _GDIPlus_GraphicsDrawImage($hGfx, $hBmp, 0, 0) EndFunc Func x() $bExit = True EndFunc Func _Release() _GDIPlus_GraphicsDispose($hGfx) _GDIPlus_BitmapDispose($hBmp) _GDIPlus_Shutdown() EndFunc Func _LCD_RenderASM(ByRef $aLCD) Local Static $vOP = DllStructCreate('byte[229]'), $xTmp = DllStructSetData($vOP, 1, '0x8B4424048B388B70048B482889F28B5818891A83C2044977F88B48248B5814035810660F6EFB8B580C0FAF5808C1E30283EB0401DF51498B1F660F6EF383EF0481E3000000FF81FB000000FF0F85880000008B58085053BA0000000089C8F7F3660F6ECA660F6ED05B89D0BA00000000F7F30FAFC3660F7ED329C358660F7EFA0FAFDA035814660F6ED3660F7ECB0FAFDA035814660F6ECB518B50108B581C5089D1660F7ED001D029C80FAFC353660F7ECB01D8C1E00201F089C3515289D1C1E20201D0660F7EF283E80489104975F889D85A595B4975CA585959490F8553FFFFFFC20400'), $pOP = DllStructGetPtr($vOP) DllCallAddress('none', $pOP, 'ptr', $aLCD[2]) EndFunc Func _LCD_New($pInput, $iWInput, $iHInput, $iSizePx, $iSizeLine, $iColBG) Local $vLCD = DllStructCreateEx('int pInput=' & $pInput & ';int pOutput;int WidthInput=' & $iWInput & ';int HeightInput=' & $iHInput & ';int SizePx=' & $iSizePx & ';int SizeLine=' & $iSizeLine & ';int ColBG=' & $iColBG & ';int WidthOutput;int HeightOutput;int PxInput=' & $iWInput * $iHInput & ';int PxOutput') $vLCD.WidthOutput = $vLCD.WidthInput * ($vLCD.SizePx + $vLCD.SizeLine) + $vLCD.SizeLine $vLCD.HeightOutput = $vLCD.HeightInput * ($vLCD.SizePx + $vLCD.SizeLine) + $vLCD.SizeLine $vLCD.PxOutput = $vLCD.WidthOutput * $vLCD.HeightOutput Local $aLCD[] = [$vLCD, DllStructCreate('int x[' & $vLCD.WidthOutput * $vLCD.HeightOutput & ']'), DllStructGetPtr($vLCD)] $vLCD.pOutput = DllStructGetPtr($aLCD[1]) Return $aLCD EndFunc Func DllStructCreateEx($sStruct, $pPointer = Default) ; klappt nur OHNE Arrays, also kein int a[5]=[1,2,3,4,5] ! Local $aSplit = StringSplit($sStruct, ';', 2), $u = UBound($aSplit), $sDef = '', $a[$u] For $i = 0 To $u - 1 Step 1 $a[$i] = StringSplit($aSplit[$i], '=', 2) $sDef &= ($a[$i])[0] & (($i < $u - 1) ? ';' : '') Next Local $vStr = $pPointer = Default ? DllStructCreate($sDef) : DllStructCreate($sDef, $pPointer) For $i = 0 To $u - 1 Step 1 If UBound($a[$i]) = 2 Then DllStructSetData($vStr, $i + 1, ($a[$i])[1]) Next Return $vStr EndFunc
-
Das mit der vertrauenswürdigen Seite ist sowieso quatsch. Nur weil der Stempel auf einem Produkt einen halben Millimeter zu weit links sitzt, muss es noch lange nicht schlecht sein.
Habe zum Glück fast all meine Uploads wiedergefunden. Müsste nun wieder da sein.lg
M