327 lines
7.9 KiB
GDScript
327 lines
7.9 KiB
GDScript
class_name ParserKLE extends AbstractParser
|
|
|
|
const LABEL_TO_KEYCODE_MAP: Dictionary[String, Key] = {
|
|
"`": KEY_QUOTELEFT,
|
|
"-": KEY_MINUS,
|
|
"=": KEY_EQUAL,
|
|
"[": KEY_BRACKETLEFT,
|
|
"]": KEY_BRACKETRIGHT,
|
|
"\\": KEY_BACKSLASH,
|
|
";": KEY_SEMICOLON,
|
|
"'": KEY_APOSTROPHE,
|
|
",": KEY_COMMA,
|
|
".": KEY_PERIOD,
|
|
"/": KEY_SLASH,
|
|
"#": KEY_NUMBERSIGN,
|
|
"Return": KEY_ENTER,
|
|
"Esc": KEY_ESCAPE,
|
|
"esc": KEY_ESCAPE,
|
|
"Bksp": KEY_BACKSPACE,
|
|
"Back Space": KEY_BACKSPACE,
|
|
"Back<br>Space": KEY_BACKSPACE,
|
|
"Caps Lock": KEY_CAPSLOCK,
|
|
"Caps<br>Lock": KEY_CAPSLOCK,
|
|
"caps lock": KEY_CAPSLOCK,
|
|
"control": KEY_CTRL,
|
|
"Win": KEY_META,
|
|
"Cmd": KEY_META,
|
|
"super": KEY_META,
|
|
"⌘": KEY_META,
|
|
"command": KEY_META,
|
|
"Meta": KEY_META,
|
|
"AltGr": KEY_ALT,
|
|
"PrtSc": KEY_PRINT,
|
|
"PrintScr SysReq": KEY_PRINT,
|
|
"Scroll Lock": KEY_SCROLLLOCK,
|
|
"Scroll<br>lock": KEY_SCROLLLOCK,
|
|
"PgUp": KEY_PAGEUP,
|
|
"Page Up": KEY_PAGEUP,
|
|
"Page<br>Up": KEY_PAGEUP,
|
|
"PgDn": KEY_PAGEDOWN,
|
|
"Page<br>Down": KEY_PAGEDOWN,
|
|
"Pause Break": KEY_PAUSE,
|
|
"Page Down": KEY_PAGEDOWN,
|
|
"Num Lock": KEY_NUMLOCK,
|
|
"↑": KEY_UP,
|
|
"⇧": KEY_UP,
|
|
"↑": KEY_UP,
|
|
"←": KEY_LEFT,
|
|
"⇦": KEY_LEFT,
|
|
"←": KEY_LEFT,
|
|
"↓": KEY_DOWN,
|
|
"⇩": KEY_DOWN,
|
|
"↓": KEY_DOWN,
|
|
"→": KEY_RIGHT,
|
|
"⇨": KEY_RIGHT,
|
|
"→": KEY_RIGHT,
|
|
}
|
|
|
|
const LABEL_TO_NUMPAD_KEYCODE_MAP: Dictionary[String, Key] = {
|
|
"/": KEY_KP_DIVIDE,
|
|
"*": KEY_KP_MULTIPLY,
|
|
"-": KEY_KP_SUBTRACT,
|
|
"+": KEY_KP_ADD,
|
|
".": KEY_KP_PERIOD,
|
|
}
|
|
|
|
const NAME := "name"
|
|
|
|
const W := "w"
|
|
const H := "h"
|
|
const X := "x"
|
|
const Y := "y"
|
|
|
|
const W2 := "w2"
|
|
const H2 := "h2"
|
|
const X2 := "x2"
|
|
const Y2 := "y2"
|
|
|
|
const R := "r"
|
|
const RX := "rx"
|
|
const RY := "ry"
|
|
|
|
const N := "n"
|
|
|
|
const KEY_DICT := "key_dict"
|
|
const POS := "pos"
|
|
|
|
var _name: String
|
|
var _rows: Array[Array]
|
|
var _file_name: String
|
|
var _has_errors: bool
|
|
|
|
|
|
func _init(data: Array, file_name: String) -> void:
|
|
_file_name = file_name
|
|
|
|
var key_pos_dicts: Dictionary[Key, Array] = {}
|
|
var pos: Vector2 = Vector2.ZERO
|
|
var pivot := Vector2.ZERO
|
|
var angle: float = 0
|
|
|
|
for data_row: Variant in data:
|
|
if data_row is Dictionary and (data_row as Dictionary).has(NAME):
|
|
_name = (data_row as Dictionary)[NAME]
|
|
|
|
if data_row is Array:
|
|
var result := _deserialize_row(
|
|
data_row as Array, key_pos_dicts, pos, pivot, angle
|
|
)
|
|
var layout_row := result[0] as Array[Dictionary]
|
|
if layout_row:
|
|
_rows.append(layout_row)
|
|
pos = result[1]
|
|
pos.y += 1
|
|
pivot = result[2]
|
|
angle = result[3]
|
|
|
|
_get_key_locations(key_pos_dicts)
|
|
|
|
|
|
func get_name() -> String:
|
|
return _name
|
|
|
|
|
|
func get_rows() -> Array[Array]:
|
|
return _rows
|
|
|
|
|
|
func has_errors() -> bool:
|
|
return _has_errors
|
|
|
|
|
|
func _deserialize_row(
|
|
data_row: Array,
|
|
key_pos_dicts: Dictionary[Key, Array],
|
|
pos: Vector2,
|
|
pivot: Vector2,
|
|
angle: float,
|
|
) -> Array:
|
|
var layout_row: Array[Dictionary] = []
|
|
|
|
pos.x = pivot.x
|
|
|
|
var data_key: Dictionary = {}
|
|
var prev_keycode: Key = KEY_NONE
|
|
for item: Variant in data_row:
|
|
if item is Dictionary:
|
|
data_key = item as Dictionary
|
|
|
|
if item is String:
|
|
var legend := (item as String).split("\n")
|
|
var keycode := _get_keycode_from_legend(legend, data_key, prev_keycode)
|
|
var key_dict := {KeyProps.KEY: keycode}
|
|
key_dict.merge(_deserialize_key(data_key))
|
|
layout_row.append(key_dict)
|
|
|
|
if data_key.has(R):
|
|
angle = -deg_to_rad(data_key[R] as float)
|
|
if data_key.has(RX):
|
|
pivot.x = data_key[RX]
|
|
if data_key.has(RY):
|
|
pivot.y = data_key[RY]
|
|
if data_key.has(RX) or data_key.has(RY):
|
|
pos = pivot
|
|
|
|
pos.x += data_key[X] if data_key.has(X) else 0.0
|
|
pos.y += data_key[Y] if data_key.has(Y) else 0.0
|
|
|
|
var key_pos_rotated := KeyHelper.get_rotated_key_pos(
|
|
Vector3(pos.x, 0, pos.y), pivot, angle
|
|
)
|
|
var key_pos_dict := {
|
|
KEY_DICT: key_dict, POS: Vector2(key_pos_rotated.x, key_pos_rotated.z)
|
|
}
|
|
|
|
if key_pos_dicts.has(keycode):
|
|
key_pos_dicts[keycode].append(key_pos_dict)
|
|
else:
|
|
key_pos_dicts[keycode] = [key_pos_dict] as Array[Dictionary]
|
|
pos.x += data_key[W] if data_key.has(W) else 1.0
|
|
|
|
data_key = {}
|
|
prev_keycode = keycode
|
|
|
|
return [layout_row, pos, pivot, angle]
|
|
|
|
|
|
func _deserialize_key(data_key: Dictionary) -> Dictionary:
|
|
var key_dict: Dictionary = {}
|
|
|
|
if data_key.has(W):
|
|
key_dict[KeyProps.W] = data_key[W]
|
|
if data_key.has(H):
|
|
key_dict[KeyProps.H] = data_key[H]
|
|
if data_key.has(X):
|
|
key_dict[KeyProps.X] = data_key[X]
|
|
if data_key.has(Y):
|
|
key_dict[KeyProps.Y] = data_key[Y]
|
|
|
|
if data_key.has(W2):
|
|
key_dict[KeyProps.W2] = data_key[W2]
|
|
if data_key.has(H2):
|
|
key_dict[KeyProps.H2] = data_key[H2]
|
|
if data_key.has(X2):
|
|
key_dict[KeyProps.X2] = data_key[X2]
|
|
if data_key.has(Y2):
|
|
key_dict[KeyProps.Y2] = data_key[Y2]
|
|
|
|
if data_key.has(R):
|
|
key_dict[KeyProps.R] = data_key[R]
|
|
if data_key.has(RX):
|
|
key_dict[KeyProps.PX] = data_key[RX]
|
|
if data_key.has(RY):
|
|
key_dict[KeyProps.PY] = data_key[RY]
|
|
|
|
if data_key.has(N):
|
|
key_dict[KeyProps.NUB] = data_key[N]
|
|
|
|
return key_dict
|
|
|
|
|
|
func _get_keycode_from_legend(
|
|
legend: Array[String], data_key: Dictionary, prev_keycode: Key
|
|
) -> Key:
|
|
if legend.size() == 1 and legend[0] == "" and data_key.has(W) and data_key[W] > 1:
|
|
return KEY_SPACE
|
|
|
|
var keycode := KEY_NONE
|
|
|
|
keycode = _get_numpad_keycode_from_legend(legend, prev_keycode)
|
|
|
|
if keycode == KEY_NONE:
|
|
keycode = OS.find_keycode_from_string(legend[0])
|
|
|
|
if keycode == KEY_NONE and legend.size() >= 2:
|
|
keycode = OS.find_keycode_from_string(legend[1])
|
|
|
|
if keycode == KEY_NONE and legend.size() >= 2:
|
|
if LABEL_TO_KEYCODE_MAP.has(legend[1]):
|
|
keycode = LABEL_TO_KEYCODE_MAP[legend[1]]
|
|
elif LABEL_TO_KEYCODE_MAP.has(legend[0]):
|
|
keycode = LABEL_TO_KEYCODE_MAP[legend[0]]
|
|
|
|
if (
|
|
keycode == KEY_NONE
|
|
and legend.size() == 1
|
|
and LABEL_TO_KEYCODE_MAP.has(legend[0])
|
|
):
|
|
keycode = LABEL_TO_KEYCODE_MAP[legend[0]]
|
|
|
|
if keycode == KEY_NONE and legend.size() > 2:
|
|
for i in range(2, legend.size()):
|
|
if not legend[i]:
|
|
continue
|
|
keycode = OS.find_keycode_from_string(legend[i])
|
|
if keycode == KEY_NONE and LABEL_TO_KEYCODE_MAP.has(legend[i]):
|
|
keycode = LABEL_TO_KEYCODE_MAP[legend[i]]
|
|
if keycode != KEY_NONE:
|
|
break
|
|
|
|
if keycode == KEY_NONE:
|
|
push_warning("%s: could not recognize key label %s" % [_file_name, str(legend)])
|
|
_has_errors = true
|
|
|
|
return keycode
|
|
|
|
|
|
func _get_numpad_keycode_from_legend(legend: Array[String], prev_keycode: Key) -> Key:
|
|
if legend.size() == 1 or legend.size() >= 2:
|
|
if legend[0].length() == 1 and legend[0].is_valid_int():
|
|
return KEY_KP_0 + int(legend[0]) as Key
|
|
if (
|
|
LABEL_TO_NUMPAD_KEYCODE_MAP.has(legend[0])
|
|
and not (legend.size() >= 2 and legend[1].length() == 1)
|
|
):
|
|
return LABEL_TO_NUMPAD_KEYCODE_MAP[legend[0]]
|
|
|
|
for label in legend:
|
|
if OS.find_keycode_from_string(label) == KEY_ENTER:
|
|
if prev_keycode >= KEY_KP_MULTIPLY and prev_keycode <= KEY_KP_9:
|
|
return KEY_KP_ENTER
|
|
break
|
|
|
|
return KEY_NONE
|
|
|
|
|
|
func _get_key_locations(key_pos_dicts: Dictionary[Key, Array]) -> void:
|
|
for keycode in key_pos_dicts:
|
|
var dicts := key_pos_dicts[keycode] as Array[Dictionary]
|
|
|
|
if (
|
|
keycode == KEY_NUMBERSIGN
|
|
and key_pos_dicts.has(KEY_BACKSLASH)
|
|
and key_pos_dicts[KEY_BACKSLASH][0][POS].x < dicts[0][POS].x
|
|
):
|
|
dicts[0][KEY_DICT][KeyProps.KEY] = KEY_BACKSLASH
|
|
key_pos_dicts[KEY_BACKSLASH][0][KEY_DICT][KeyProps.KEY] = KEY_SECTION
|
|
continue
|
|
|
|
if keycode == KEY_NONE or dicts.size() == 1:
|
|
continue
|
|
|
|
var key_pos_dict_left: Dictionary
|
|
var key_pos_dict_right: Dictionary
|
|
for key_pos_dict in dicts:
|
|
var key_pos := key_pos_dict[POS] as Vector2
|
|
if (
|
|
not key_pos_dict_left
|
|
or key_pos.x < (key_pos_dict_left[POS] as Vector2).x
|
|
):
|
|
key_pos_dict_left = key_pos_dict
|
|
if (
|
|
not key_pos_dict_right
|
|
or key_pos.x > (key_pos_dict_right[POS] as Vector2).x
|
|
):
|
|
key_pos_dict_right = key_pos_dict
|
|
|
|
if key_pos_dict_left == key_pos_dict_right:
|
|
continue
|
|
|
|
if keycode == KEY_BACKSLASH:
|
|
key_pos_dict_left[KEY_DICT][KeyProps.KEY] = KEY_SECTION
|
|
continue
|
|
|
|
key_pos_dict_left[KEY_DICT][KeyProps.LOC] = KEY_LOCATION_LEFT
|
|
key_pos_dict_right[KEY_DICT][KeyProps.LOC] = KEY_LOCATION_RIGHT
|