diff options
Diffstat (limited to 'irdecoderunit.pas')
-rw-r--r-- | irdecoderunit.pas | 365 |
1 files changed, 288 insertions, 77 deletions
diff --git a/irdecoderunit.pas b/irdecoderunit.pas index 9114421..06b7c28 100644 --- a/irdecoderunit.pas +++ b/irdecoderunit.pas @@ -21,11 +21,14 @@ type ersterEmpf, letzterEmpf: boolean; eingabePuffer: array of longword; - eingabeLaenge: longword; + eingabeLaenge, + zustand: longword; _watte: boolean; procedure init; procedure tastenDruckAnhaengen(lw: longword); procedure befehlAusfuehren(cmd,params: string); + function findeZeichen(lw: longword): longword; + function findeBefehl(lw: longword): longword; public constructor create(inputName: string); overload; constructor create(inputName, konfigName: string); overload; @@ -38,14 +41,24 @@ type end; tBefehl = record + nummer,altZustand, // Index des gesendeten Zeichens in zeichenTabelle, sowie alter + neuZustand: longword; // und neuer Zustand einzelKlick, // gedrückt gehaltene Taste = Befehl mehrmals? kollapsTrenner: boolean; // Darf über diesen Befehl hinweg kollabiert werden? cmd,params: string; // Befehl + Parameter kollapsArt: tKollapsArt; // Wie kollabiert dieser Befehl? end; +procedure befehleKonfLesen(konfigName: string); +procedure sortiereZeichenTabelle(von,bis: longword); +procedure sortiereBefehlsTabelle(von,bis: longword); +function befehlsVergleich(b1,b2: longword): integer; inline; overload; +function befehlsVergleich(b1,b2Num,b2Zus: longword): integer; inline; overload; + implementation +uses math; + var zeichenTabelle: array of longword; befehlsTabelle: array of tBefehl; @@ -68,54 +81,12 @@ begin end; constructor tIRDecoder.create(inputName, konfigName: string; watte: boolean); -var - konfigDatei: tMyStringList; - zeile,taste: string; begin inherited create; if (length(zeichenTabelle)=0) or (length(befehlsTabelle)=0) then begin - konfigDatei:=tMyStringList.create; - konfigDatei.loadFromFile(konfigName); - if not konfigDatei.unfoldMacros then - raise exception.create('Fehler beim Entfalten der Makros in '''+konfigName+'''!'); - while konfigDatei.readln(zeile) do begin - setlength(zeichenTabelle,length(zeichenTabelle)+1); - setlength(befehlsTabelle,length(befehlsTabelle)+1); - if copy(zeile,length(zeile),1)<>':' then - raise exception.create('Die erste Zeile einer Befehlsdefinition muss mit einem : enden, '''+zeile+''' tut das nicht!'); - delete(zeile,length(zeile),1); - taste:=trim(zeile); - zeichenTabelle[length(zeichenTabelle)-1]:=strtoint(taste); - if not konfigDatei.readln(zeile) then - raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!'); - befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=not startetMit('!',zeile); - if zeile<>'einzelKlick' then - raise exception.create('Syntaxfehler: erste Option muss ''[!] einzelKlick'' sein (Taste '+taste+')!'); - if not konfigDatei.readln(zeile) then - raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!'); - befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=not startetMit('!',zeile); - if zeile<>'kollapsTrenner' then - raise exception.create('Syntaxfehler: zweite Option muss ''[!] kollapsTrenner'' sein (Taste '+taste+')!'); - if not konfigDatei.readln(zeile) then - raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!'); - if not startetMit('kollapsArt:',zeile) then - raise exception.create('Syntaxfehler: dritte Option muss ''kollapsArt: ...'' sein, '''+zeile+''' ist das nicht (Taste '+taste+')!'); - if zeile='ignorieren' then - befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaIgnorieren - else if zeile='toggle' then - befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaToggle - else if zeile='addieren' then - befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaAddieren - else if zeile='nurEinMal' then - befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaNurEinMal - else - raise exception.create('Unbekannte kollapsArt '''+zeile+''' (Taste '+taste+')!'); - if not konfigDatei.readln(zeile) then - raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!'); - befehlsTabelle[length(befehlsTabelle)-1].cmd:=erstesArgument(zeile); - befehlsTabelle[length(befehlsTabelle)-1].params:=zeile; - end; - konfigDatei.free; + setlength(zeichenTabelle,0); + setlength(befehlsTabelle,0); + befehleKonfLesen(konfigName); end; _watte:=watte; @@ -137,6 +108,7 @@ begin letztesZeichen[true]:=$ffffffff; letzterEmpf:=false; ersterEmpf:=false; + zustand:=0; setlength(eingabePuffer,0); eingabeLaenge:=0; end; @@ -144,7 +116,6 @@ end; procedure tIRDecoder.tastenDruckAnhaengen(lw: longword); var empf: boolean; - i: longword; begin empf:=odd(lw shr 1); lw:=((lw shr 1) and not 1) or byte(odd(lw)); @@ -155,14 +126,7 @@ begin if empf=ersterEmpf then begin if eingabeLaenge>=length(eingabePuffer) then setlength(eingabePuffer,eingabeLaenge+1024); - eingabePuffer[eingabeLaenge]:=$ffffffff; - for i:=0 to length(zeichenTabelle)-1 do - if (lw and not $08)=zeichenTabelle[i] then begin - eingabePuffer[eingabeLaenge]:=i; - break; - end; - if eingabePuffer[eingabeLaenge]=$ffffffff then - raise exception.create('Kann Tastencode '''+inttohex(lw,4)+''' nicht finden!'); + eingabePuffer[eingabeLaenge]:=findeZeichen(lw and not $08); inc(eingabeLaenge); end; @@ -187,6 +151,60 @@ begin end; end; +function tIRDecoder.findeZeichen(lw: longword): longword; +var + mi,ma: longword; +begin + mi:=0; + ma:=length(zeichenTabelle)-1; + while mi<ma do begin + result:=(mi+ma) div 2; + if zeichenTabelle[result]<lw then begin + mi:=min(ma,result+1); + continue; + end; + if zeichenTabelle[result]>lw then begin + ma:=max(mi,result-1); + continue; + end; + mi:=result; + ma:=result; + break; + end; + if mi<>ma then + raise exception.create('Sanity-Check nicht bestanden: mi<>ma nach Bisektion!'); + result:=mi; + if zeichenTabelle[result]<>lw then + raise exception.create('Kann Tastencode '''+inttohex(lw,4)+''' nicht finden!'); +end; + +function tIRDecoder.findeBefehl(lw: longword): longword; +var + mi,ma: longword; +begin + mi:=0; + ma:=length(befehlsTabelle)-1; + while mi<ma do begin + result:=(mi+ma+1) div 2; + if befehlsVergleich(result,lw,zustand)>0 then begin + ma:=max(mi,result-1); + continue; + end; + if befehlsVergleich(result,lw,zustand)<0 then begin + mi:=min(ma,result); + continue; + end; + mi:=result; + ma:=result; + break; + end; + if mi<>ma then + raise exception.create('Sanity-Check nicht bestanden: mi<>ma nach Bisektion!'); + result:=mi; + if (befehlsTabelle[result].nummer<>lw) or (befehlsTabelle[result].altZustand>zustand) then + raise exception.create('Kann Befehl Nummer '''+inttohex(lw,4)+''' im Zustand '+inttostr(zustand)+' nicht finden!'); +end; + function tIRDecoder.zeileVerarbeitet: boolean; var s: string; @@ -211,33 +229,39 @@ end; function tIRDecoder.befehlVerarbeitet: boolean; var - i,cnt: longword; + i,cnt,bef,bef2: longword; cmd,params,s,t: string; begin result:=eingabeLaenge>0; if not result then exit; - cmd:=befehlsTabelle[eingabePuffer[0]].cmd; - params:=befehlsTabelle[eingabePuffer[0]].params; + bef:=findeBefehl(eingabePuffer[0]); + + for i:=1 to eingabeLaenge-1 do + eingabePuffer[i-1]:=eingabePuffer[i]; + dec(eingabeLaenge); + + cmd:=befehlsTabelle[bef].cmd; + params:=befehlsTabelle[bef].params; + zustand:=befehlsTabelle[bef].neuZustand; - if befehlsTabelle[eingabePuffer[0]].kollapsArt<>kaIgnorieren then begin - cnt:=1; + if befehlsTabelle[bef].kollapsArt<>kaIgnorieren then begin + cnt:=0; while cnt<eingabeLaenge do begin - if (befehlsTabelle[eingabePuffer[0]].kollapsArt=befehlsTabelle[eingabePuffer[cnt]].kollapsArt) and - (befehlsTabelle[eingabePuffer[0]].cmd=befehlsTabelle[eingabePuffer[cnt]].cmd) then begin - case befehlsTabelle[eingabePuffer[0]].kollapsArt of + bef2:=findeBefehl(eingabePuffer[cnt]); + if (befehlsTabelle[bef].kollapsArt=befehlsTabelle[bef2].kollapsArt) and + (befehlsTabelle[bef].cmd=befehlsTabelle[bef2].cmd) then begin + for i:=1 to eingabeLaenge-1 do + eingabePuffer[i-1]:=eingabePuffer[i]; + dec(eingabeLaenge,1); + case befehlsTabelle[bef].kollapsArt of kaToggle: begin - for i:=1 to cnt-1 do - eingabePuffer[i-1]:=eingabePuffer[i]; - for i:=cnt+1 to eingabeLaenge-1 do - eingabePuffer[i-2]:=eingabePuffer[i]; - dec(eingabeLaenge,2); result:=befehlVerarbeitet; exit; end; kaAddieren: begin s:=params; - t:=befehlsTabelle[eingabePuffer[cnt]].params; + t:=befehlsTabelle[bef2].params; params:=''; while s<>'' do params:=trim(params+' '+zusammenFassen(erstesArgument(s),erstesArgument(t))); @@ -246,21 +270,16 @@ begin else raise exception.create('Weder Toggle, noch Addieren, noch NurEinMal, noch Ignorieren! Das ist komisch ...'); end{of case}; - for i:=cnt+1 to eingabeLaenge-1 do - eingabePuffer[i-1]:=eingabePuffer[i]; - dec(eingabeLaenge); continue; end; - if befehlsTabelle[eingabePuffer[cnt]].kollapsTrenner then + if befehlsTabelle[bef2].kollapsTrenner then break; inc(cnt); end; end; - befehlAusfuehren(cmd,params); - for i:=1 to eingabeLaenge-1 do - eingabePuffer[i-1]:=eingabePuffer[i]; - dec(eingabeLaenge); + if cmd<>'nop' then + befehlAusfuehren(cmd,params); end; function tIRDecoder.gibAlleBefehle: string; @@ -278,5 +297,197 @@ begin end; end; +// allgemeine Funktionen ******************************************************* + +procedure befehleKonfLesen(konfigName: string); +var + konfigDatei: tMyStringList; + zeile,taste: string; + cStat: longword; +begin + konfigDatei:=tMyStringList.create; + konfigDatei.loadFromFile(konfigName); + if not konfigDatei.unfoldMacros then + raise exception.create('Fehler beim Entfalten der Makros in '''+konfigName+'''!'); + while konfigDatei.readln(zeile) do begin // Iteration über die Zeichen + setlength(zeichenTabelle,length(zeichenTabelle)+1); + if copy(zeile,length(zeile),1)<>':' then + raise exception.create('Die erste Zeile einer Befehlsdefinition muss mit einem : enden, '''+zeile+''' tut das nicht!'); + delete(zeile,length(zeile),1); + taste:=trim(zeile); + zeichenTabelle[length(zeichenTabelle)-1]:=strtoint(taste); + cStat:=0; + repeat // Iteration über die Befehle pro Zeichen + if not konfigDatei.readln(zeile) then + raise exception.create('Unerwartetes Dateiende in '''+konfigName+''' (Taste '+taste+')!'); + if zeile='Ende' then break; + if startetMit('Befehl:',zeile) then begin + setlength(befehlsTabelle,length(befehlsTabelle)+1); + befehlsTabelle[length(befehlsTabelle)-1].nummer:=length(zeichenTabelle)-1; + befehlsTabelle[length(befehlsTabelle)-1].altZustand:=cStat; + befehlsTabelle[length(befehlsTabelle)-1].neuZustand:=cStat; + inc(cStat); + befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaIgnorieren; + befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=true; + befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=false; + befehlsTabelle[length(befehlsTabelle)-1].cmd:=erstesArgument(zeile); + befehlsTabelle[length(befehlsTabelle)-1].params:=zeile; + continue; + end; + if startetMit('altZustand:',zeile) then begin + befehlsTabelle[length(befehlsTabelle)-1].altZustand:=strtoint(zeile); + continue; + end; + if startetMit('neuZustand:',zeile) then begin + befehlsTabelle[length(befehlsTabelle)-1].neuZustand:=strtoint(zeile); + continue; + end; + if startetMit('einzelKlick:',zeile) then begin + if zeile='ja' then befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=true + else if zeile='nein' then befehlsTabelle[length(befehlsTabelle)-1].einzelKlick:=false + else raise exception.create('''einzelKlick'' kann nur ''ja'' oder ''nein'' sein, nicht aber '''+zeile+'''!'); + continue; + end; + if startetMit('kollapsTrenner:',zeile) then begin + if zeile='ja' then befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=true + else if zeile='nein' then befehlsTabelle[length(befehlsTabelle)-1].kollapsTrenner:=false + else raise exception.create('''kollapsTrenner'' kann nur ''ja'' oder ''nein'' sein, nicht aber '''+zeile+'''!'); + continue; + end; + if startetMit('kollapsArt:',zeile) then begin + if zeile='ignorieren' then + befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaIgnorieren + else if zeile='toggle' then + befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaToggle + else if zeile='addieren' then + befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaAddieren + else if zeile='nurEinMal' then + befehlsTabelle[length(befehlsTabelle)-1].kollapsArt:=kaNurEinMal + else + raise exception.create('Unbekannte kollapsArt '''+zeile+''' (Taste '+taste+')!'); + continue; + end; + raise exception.create('Verstehe Option '''+zeile+''' nicht in '''+konfigName+''' (Taste '+taste+')!'); + until false; + end; + konfigDatei.free; + sortiereZeichenTabelle(0,length(zeichenTabelle)-1); + sortiereBefehlsTabelle(0,length(befehlsTabelle)-1); +end; + +procedure sortiereZeichenTabelle(von,bis: longword); +var + li,re,pv,i: longword; +begin + if von>=bis then exit; + pv:=zeichenTabelle[von]; + re:=pv; + for li:=von+1 to bis do begin + pv:=min(pv,zeichenTabelle[li]); + re:=max(re,zeichenTabelle[li]); + end; + pv:=(pv+re) div 2; // das Pivot-Element + li:=von; + re:=bis; + while li<=re do begin + while (li<bis) and (zeichenTabelle[li]<=pv) do + inc(li); + while (re>von) and (zeichenTabelle[re]>pv) do + dec(re); + if li>=re then break; + i:=zeichenTabelle[re]; + zeichenTabelle[re]:=zeichenTabelle[li]; + zeichenTabelle[li]:=i; + for i:=0 to length(befehlsTabelle)-1 do + if befehlsTabelle[i].nummer=li then + befehlsTabelle[i].nummer:=re + else if befehlsTabelle[i].nummer=re then + befehlsTabelle[i].nummer:=li; + inc(li); + dec(re); + end; + if li<>re+1 then + raise exception.create('Sanity-Check nicht bestanden: li<>re+1 kann beim Quicksort nicht sein!'); + if re=bis then + raise exception.create('Rechter Rand hat sich nicht verbessert!'); + if li=von then + raise exception.create('Linker Rand hat sich nicht verbessert!'); + sortiereZeichenTabelle(von,re); + sortiereZeichenTabelle(li,bis); +end; + +procedure sortiereBefehlsTabelle(von,bis: longword); +var + mi,ma,li,re,pv,pvZ,i: longword; + tmp: tBefehl; +begin + if von>=bis then exit; + mi:=von; + ma:=mi; + for i:=von+1 to bis do begin + if befehlsVergleich(mi,i)>0 then mi:=i; + if befehlsVergleich(ma,i)<0 then ma:=i; + end; + pv:=(befehlsTabelle[mi].nummer+befehlsTabelle[ma].nummer) div 2; // das + pvZ:=(befehlsTabelle[mi].altZustand+befehlsTabelle[ma].altZustand) div 2; // Pivot-Element + + if befehlsVergleich(mi,pv,pvZ)<0 then begin + pv:=befehlsTabelle[mi].nummer; + pvZ:=befehlsTabelle[mi].altZustand; + end; + + li:=von; + re:=bis; + while li<=re do begin + while (li<=bis) and + (befehlsVergleich(li,pv,pvZ)<=0) do + inc(li); + while (re>=von) and + (befehlsVergleich(re,pv,pvZ)>0) do + dec(re); + if li>=re then break; + move(befehlsTabelle[re],tmp,sizeOf(tBefehl)); + move(befehlsTabelle[li],befehlsTabelle[re],sizeOf(tBefehl)); + move(tmp,befehlsTabelle[li],sizeOf(tBefehl)); + inc(li); + dec(re); + end; + fillchar(tmp,sizeof(tBefehl),#0); + if li<>re+1 then + raise exception.create('Sanity-Check nicht bestanden: li<>re+1 kann beim Quicksort nicht sein!'); + if re=bis then + raise exception.create('Rechter Rand hat sich nicht verbessert!'); + if li=von then + raise exception.create('Linker Rand hat sich nicht verbessert!'); + sortiereBefehlsTabelle(von,re); + sortiereBefehlsTabelle(li,bis); +end; + +function befehlsVergleich(b1,b2: longword): integer; +begin + result:=befehlsVergleich(b1,befehlsTabelle[b2].nummer,befehlsTabelle[b2].altZustand); +end; + +function befehlsVergleich(b1,b2Num,b2Zus: longword): integer; +begin + if befehlsTabelle[b1].nummer<b2Num then begin + result:=-1; + exit; + end; + if befehlsTabelle[b1].nummer>b2Num then begin + result:=1; + exit; + end; + if befehlsTabelle[b1].altZustand<b2Zus then begin + result:=-1; + exit; + end; + if befehlsTabelle[b1].altZustand>b2Zus then begin + result:=1; + exit; + end; + result:=0; +end; + end. |