Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add simple input remapping support (no user interface yet)
This reads %APPDATA%\DCS-BIOS\Config\inputmap.txt Each line is either three or five comma-separated values: AIRCRAFT,FROM,TO remaps FROM to TO when AIRCRAFT is active in the simulator. AIRCRAFT,FROM_CMD,FROM_ARG,TO_CMD,TO_ARG remaps FROM_CMD with FROM_ARG to TO_CMD with TO_ARG when AIRCRAFT is active in the simulator. inputmap.txt is read on startup; to pick up changes, restart dcs-bios-hub.
- Loading branch information
Showing
5 changed files
with
257 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package exportdataparser | ||
|
||
import ( | ||
"bytes" | ||
"sync" | ||
) | ||
|
||
type parserState int | ||
|
||
const ( | ||
StateWaitForSync = parserState(0) | ||
StateAddressLow = parserState(1) | ||
StateAddressHigh = parserState(2) | ||
StateCountLow = parserState(3) | ||
StateCountHigh = parserState(4) | ||
StateDataLow = parserState(5) | ||
StateDataHigh = parserState(6) | ||
) | ||
|
||
type stringBuffer struct { | ||
address int | ||
length int | ||
data []byte | ||
callback func([]byte) | ||
} | ||
|
||
type twoByteBuffer [2]byte | ||
|
||
func (buf *twoByteBuffer) AsUint16() uint16 { | ||
return uint16(buf[1])<<8 | uint16(buf[0]) | ||
} | ||
func (buf *twoByteBuffer) SetUint16(n uint16) { | ||
buf[0] = uint8(n & 0x00FF) | ||
buf[1] = uint8((n & 0xFF00) >> 8) | ||
} | ||
|
||
type ExportDataParser struct { | ||
state parserState | ||
syncByteCount int | ||
addressBuffer twoByteBuffer | ||
countBuffer twoByteBuffer | ||
dataBuffer twoByteBuffer | ||
totalBuffer [65536]byte | ||
stringBuffers []stringBuffer | ||
stringBufferLock sync.Mutex | ||
} | ||
|
||
func (ep *ExportDataParser) SubscribeStringBuffer(address int, length int, callback func([]byte)) { | ||
sb := stringBuffer{ | ||
address: address, | ||
length: length, | ||
data: make([]byte, length), | ||
callback: callback, | ||
} | ||
ep.stringBufferLock.Lock() | ||
ep.stringBuffers = append(ep.stringBuffers, sb) | ||
ep.stringBufferLock.Unlock() | ||
} | ||
|
||
func (ep *ExportDataParser) ProcessByte(b uint8) { | ||
switch ep.state { | ||
case StateWaitForSync: | ||
|
||
case StateAddressLow: | ||
ep.addressBuffer[0] = b | ||
ep.state = StateAddressHigh | ||
|
||
case StateAddressHigh: | ||
ep.addressBuffer[1] = b | ||
if ep.addressBuffer.AsUint16() != 0x555 { | ||
ep.state = StateCountLow | ||
} else { | ||
ep.state = StateWaitForSync | ||
} | ||
|
||
case StateCountLow: | ||
ep.countBuffer[0] = b | ||
ep.state = StateCountHigh | ||
|
||
case StateCountHigh: | ||
ep.countBuffer[1] = b | ||
ep.state = StateDataLow | ||
|
||
case StateDataLow: | ||
ep.dataBuffer[0] = b | ||
ep.state = StateDataHigh | ||
ep.countBuffer.SetUint16(ep.countBuffer.AsUint16() - 1) | ||
ep.state = StateDataHigh | ||
|
||
case StateDataHigh: | ||
ep.dataBuffer[1] = b | ||
ep.countBuffer.SetUint16(ep.countBuffer.AsUint16() - 1) | ||
ep.totalBuffer[ep.addressBuffer.AsUint16()] = ep.dataBuffer[0] | ||
ep.totalBuffer[ep.addressBuffer.AsUint16()+1] = ep.dataBuffer[1] | ||
|
||
if ep.addressBuffer.AsUint16() == 0xfffe { | ||
// end of update | ||
ep.notify() | ||
} | ||
|
||
ep.addressBuffer.SetUint16(ep.addressBuffer.AsUint16() + 2) | ||
|
||
if ep.countBuffer.AsUint16() == 0 { | ||
ep.state = StateAddressLow | ||
} else { | ||
ep.state = StateDataLow | ||
} | ||
|
||
} | ||
|
||
if b == 0x55 { | ||
ep.syncByteCount++ | ||
} else { | ||
ep.syncByteCount = 0 | ||
} | ||
|
||
if ep.syncByteCount == 4 { | ||
ep.state = StateAddressLow | ||
ep.syncByteCount = 0 | ||
} | ||
} | ||
|
||
func (ep *ExportDataParser) notify() { | ||
ep.stringBufferLock.Lock() | ||
for _, sb := range ep.stringBuffers { | ||
for i := range sb.data { | ||
sb.data[i] = ep.totalBuffer[sb.address+i] | ||
} | ||
|
||
nullTerminatorPos := bytes.IndexByte(sb.data, 0) | ||
if nullTerminatorPos == -1 { | ||
nullTerminatorPos = 0 | ||
} | ||
|
||
sb.callback(sb.data[:nullTerminatorPos]) | ||
} | ||
ep.stringBufferLock.Unlock() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Package inputmapping manages a translation table | ||
package inputmapping | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"strings" | ||
|
||
"dcs-bios.a10c.de/dcs-bios-hub/configstore" | ||
) | ||
|
||
type CommandMatch struct { | ||
CommandMatch string | ||
ArgumentMatch string | ||
CommandReplacement string | ||
ArgumentReplacement string | ||
} | ||
|
||
type InputMap map[string][]CommandMatch | ||
|
||
type InputRemapper struct { | ||
unittypeMappings map[string]InputMap | ||
activeUnittype string | ||
} | ||
|
||
func (ir *InputRemapper) SetActiveAircraft(name string) { | ||
ir.activeUnittype = name | ||
} | ||
|
||
func (ir *InputRemapper) LoadFromConfigStore() { | ||
file, err := configstore.OpenFile("inputmap.txt") | ||
if err != nil { | ||
fmt.Printf("could not load inputmap.txt: %v\n", err.Error()) | ||
return | ||
} | ||
defer file.Close() | ||
|
||
ir.unittypeMappings = make(map[string]InputMap) | ||
|
||
scanner := bufio.NewScanner(file) | ||
for scanner.Scan() { | ||
line := scanner.Text() | ||
parts := strings.Split(line, ",") | ||
cm := &CommandMatch{} | ||
unittype := parts[0] | ||
if len(parts) == 3 { | ||
cm.CommandMatch = parts[1] | ||
cm.CommandReplacement = parts[2] | ||
} else if len(parts) == 5 { | ||
cm.CommandMatch = parts[1] | ||
cm.ArgumentMatch = parts[2] | ||
cm.CommandReplacement = parts[3] | ||
cm.ArgumentReplacement = parts[4] | ||
} else { | ||
continue | ||
} | ||
|
||
if _, ok := ir.unittypeMappings[unittype]; !ok { | ||
ir.unittypeMappings[unittype] = make(InputMap) | ||
} | ||
ir.unittypeMappings[unittype][cm.CommandMatch] = append(ir.unittypeMappings[unittype][cm.CommandMatch], *cm) | ||
} | ||
} | ||
|
||
func (ir *InputRemapper) Remap(line string) string { | ||
mapping, ok := ir.unittypeMappings[ir.activeUnittype] | ||
if !ok { | ||
return line | ||
} | ||
parts := strings.Split(line, " ") | ||
if len(parts) != 2 { | ||
return line | ||
} | ||
msg, arg := parts[0], parts[1] | ||
|
||
for _, cmdMatch := range mapping[msg] { | ||
if cmdMatch.ArgumentMatch == arg || cmdMatch.ArgumentMatch == "" { | ||
argRep := arg | ||
if cmdMatch.ArgumentReplacement != "" { | ||
argRep = cmdMatch.ArgumentReplacement | ||
} | ||
// found replacement | ||
return cmdMatch.CommandReplacement + " " + argRep | ||
} | ||
} | ||
return line | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters