mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-24 13:39:11 +00:00

Also renamed most cases of SDL_GAMEPAD_TYPE_UNKNOWN to SDL_GAMEPAD_TYPE_STANDARD, and SDL_GetGamepadType() will return SDL_GAMEPAD_TYPE_UNKNOWN only if the gamepad is invalid.
151 lines
5 KiB
Python
Executable file
151 lines
5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
#
|
|
# Script to sort the game controller database entries in SDL_gamepad.c
|
|
|
|
import re
|
|
|
|
|
|
filename = "SDL_gamepad_db.h"
|
|
input = open(filename)
|
|
output = open(f"{filename}.new", "w")
|
|
parsing_controllers = False
|
|
controllers = []
|
|
controller_guids = {}
|
|
conditionals = []
|
|
split_pattern = re.compile(r'([^"]*")([^,]*,)([^,]*,)([^"]*)(".*)')
|
|
# BUS (1) CRC (3,2) VID (5,4) (6) PID (8,7) (9) VERSION (11,10) MISC (12)
|
|
standard_guid_pattern = re.compile(r'^([0-9a-fA-F]{4})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})(0000)([0-9a-fA-F]{2})([0-9a-fA-F]{2})(0000)([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{4},)$')
|
|
|
|
# These chipsets are used in multiple controllers with different mappings,
|
|
# without enough unique information to differentiate them. e.g.
|
|
# https://github.com/gabomdq/SDL_GameControllerDB/issues/202
|
|
invalid_controllers = (
|
|
('0079', '0006', '0000'), # DragonRise Inc. Generic USB Joystick
|
|
('0079', '0006', '6120'), # DragonRise Inc. Generic USB Joystick
|
|
('16c0', '05e1', '0000'), # Xinmotek Controller
|
|
)
|
|
|
|
def find_element(prefix, bindings):
|
|
i=0
|
|
for element in bindings:
|
|
if element.startswith(prefix):
|
|
return i
|
|
i=(i + 1)
|
|
|
|
return -1
|
|
|
|
def save_controller(line):
|
|
global controllers
|
|
match = split_pattern.match(line)
|
|
entry = [ match.group(1), match.group(2), match.group(3) ]
|
|
bindings = sorted(match.group(4).split(","))
|
|
if (bindings[0] == ""):
|
|
bindings.pop(0)
|
|
|
|
name = entry[2].rstrip(',')
|
|
|
|
crc = ""
|
|
pos = find_element("crc:", bindings)
|
|
if pos >= 0:
|
|
crc = bindings[pos] + ","
|
|
bindings.pop(pos)
|
|
|
|
guid_match = standard_guid_pattern.match(entry[1])
|
|
if guid_match:
|
|
groups = guid_match.groups()
|
|
crc_value = groups[2] + groups[1]
|
|
vid_value = groups[4] + groups[3]
|
|
pid_value = groups[7] + groups[6]
|
|
version_value = groups[10] + groups[9]
|
|
#print("CRC: %s, VID: %s, PID: %s, VERSION: %s" % (crc_value, vid_value, pid_value, version_value))
|
|
|
|
if crc_value == "0000":
|
|
if crc != "":
|
|
crc_value = crc[4:-1]
|
|
else:
|
|
print("Extracting CRC from GUID of " + name)
|
|
entry[1] = groups[0] + "0000" + "".join(groups[3:])
|
|
crc = "crc:" + crc_value + ","
|
|
|
|
if (vid_value, pid_value, crc_value) in invalid_controllers:
|
|
print("Controller '%s' not unique, skipping" % name)
|
|
return
|
|
|
|
pos = find_element("type", bindings)
|
|
if pos >= 0:
|
|
bindings.insert(0, bindings.pop(pos))
|
|
|
|
pos = find_element("platform", bindings)
|
|
if pos >= 0:
|
|
bindings.insert(0, bindings.pop(pos))
|
|
|
|
pos = find_element("sdk", bindings)
|
|
if pos >= 0:
|
|
bindings.append(bindings.pop(pos))
|
|
|
|
pos = find_element("hint:", bindings)
|
|
if pos >= 0:
|
|
bindings.append(bindings.pop(pos))
|
|
|
|
entry.extend(crc)
|
|
entry.extend(",".join(bindings) + ",")
|
|
entry.append(match.group(5))
|
|
controllers.append(entry)
|
|
|
|
entry_id = entry[1] + entry[3]
|
|
if ',sdk' in line or ',hint:' in line:
|
|
conditionals.append(entry_id)
|
|
|
|
def write_controllers():
|
|
global controllers
|
|
global controller_guids
|
|
# Check for duplicates
|
|
for entry in controllers:
|
|
entry_id = entry[1] + entry[3]
|
|
if (entry_id in controller_guids and entry_id not in conditionals):
|
|
current_name = entry[2]
|
|
existing_name = controller_guids[entry_id][2]
|
|
print("Warning: entry '%s' is duplicate of entry '%s'" % (current_name, existing_name))
|
|
|
|
if (not current_name.startswith("(DUPE)")):
|
|
entry[2] = f"(DUPE) {current_name}"
|
|
|
|
if (not existing_name.startswith("(DUPE)")):
|
|
controller_guids[entry_id][2] = f"(DUPE) {existing_name}"
|
|
|
|
controller_guids[entry_id] = entry
|
|
|
|
for entry in sorted(controllers, key=lambda entry: f"{entry[2]}-{entry[1]}"):
|
|
line = "".join(entry) + "\n"
|
|
line = line.replace("\t", " ")
|
|
if not line.endswith(",\n") and not line.endswith("*/\n") and not line.endswith(",\r\n") and not line.endswith("*/\r\n"):
|
|
print("Warning: '%s' is missing a comma at the end of the line" % (line))
|
|
output.write(line)
|
|
|
|
controllers = []
|
|
controller_guids = {}
|
|
|
|
for line in input:
|
|
if parsing_controllers:
|
|
if (line.startswith("{")):
|
|
output.write(line)
|
|
elif (line.startswith(" NULL")):
|
|
parsing_controllers = False
|
|
write_controllers()
|
|
output.write(line)
|
|
elif (line.startswith("#if")):
|
|
print(f"Parsing {line.strip()}")
|
|
output.write(line)
|
|
elif (line.startswith("#endif")):
|
|
write_controllers()
|
|
output.write(line)
|
|
else:
|
|
save_controller(line)
|
|
else:
|
|
if (line.startswith("static const char *")):
|
|
parsing_controllers = True
|
|
|
|
output.write(line)
|
|
|
|
output.close()
|
|
print(f"Finished writing {filename}.new")
|