Merge pull request #4978 from Web-eWorks/input-frame-2.0

Input Frame 2.0
master
Webster Sheets 2020-11-11 19:27:31 -05:00 committed by GitHub
commit 10006ebfc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
137 changed files with 3129 additions and 2764 deletions

View File

@ -49,6 +49,7 @@ if (APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu")
endif(APPLE)
option(USE_LLD_LINKER "Use the LLVM lld linker instead of gcc's linker" OFF)
if (CMAKE_COMPILER_IS_GNUCXX)
if (NOT IS_TRAVIS)
add_compile_options(
@ -63,6 +64,9 @@ if (CMAKE_COMPILER_IS_GNUCXX)
-Wno-implicit-fallthrough
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
if (USE_LLD_LINKER)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
endif(USE_LLD_LINKER)
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og")
endif (CMAKE_COMPILER_IS_GNUCXX)

View File

@ -103,10 +103,6 @@
"description": "",
"message": "بقايا جسم كوكب بني قزم شبه ممتازة"
},
"BUTTON": {
"description": "",
"message": "\" زر \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "الكاميرا السفلية"
@ -327,10 +323,6 @@
"description": "",
"message": "مكان الوصول"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "البعد: %distance{f.2} سنة ضوئية"
@ -495,10 +487,6 @@
"description": "",
"message": "Entirely Capitalist - no government welfare provision"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" قبعة\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "اعادة"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "اعادة التوجية و التكبير"
},
"ROBOTS": {
"description": "",
"message": "الي"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" لا يوجد غلاف جوي\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "انعراج"
@ -1895,10 +1871,6 @@
"description": "",
"message": "مستعمرة زراعة صغيرة"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "تقريب"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Кафяво джудже"
},
"BUTTON": {
"description": "",
"message": "\" Бутон \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Долна камера"
@ -327,10 +323,6 @@
"description": "",
"message": "Дестинация"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Пос \""
},
"DISTANCE_LY": {
"description": "",
"message": "Разстояние: %distance{f.2} сг"
@ -495,10 +487,6 @@
"description": "",
"message": "Изцяло капиталистическа - без намеса от правителството"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Задръж {target} анти-нормално"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Нулиране"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Нулирай Ориентацията и Мащабирането"
},
"ROBOTS": {
"description": "",
"message": "Роботи"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" незначителна атмосфера\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Отклонение"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Млада фермерска колония."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Приближи"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Nan marró (objecte subestel·lar)"
},
"BUTTON": {
"description": "",
"message": "\" botó \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Càmera inferior"
@ -327,10 +323,6 @@
"description": "",
"message": "Destinació"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distància: %distance{f.2} al"
@ -495,10 +487,6 @@
"description": "",
"message": "Capitalisme salvatge. Cap prestació social del govern."
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Bolet\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Orientació anti-normal respecte a {target}"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reiniciar"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reiniciar orientació i zoom"
},
"ROBOTS": {
"description": "",
"message": "Robots"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" sense atmosfera significativa\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Guinyada"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Colònia agrícola recent."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Apropar"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Hnědý trpaslík (podhvězda)"
},
"BUTTON": {
"description": "",
"message": "\" klávesa \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Pohled zdola"
@ -327,10 +323,6 @@
"description": "",
"message": "Destinace"
},
"DIRECTION": {
"description": "Direction",
"message": "\" směr \""
},
"DISTANCE_LY": {
"description": "",
"message": "Vzdálenost: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Naprostý kapitalismus - žádný státní sociální systém"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" klobouk\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset orientace a zoomu"
},
"ROBOTS": {
"description": "",
"message": "Roboti"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" bez výrazné atmosféry\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Zatáčení"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Nová zemědělská kolonie."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zvětšit"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brun dværg sub-stjerneobjekt"
},
"BUTTON": {
"description": "",
"message": "\" Knap \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Underkamera"
@ -327,10 +323,6 @@
"description": "",
"message": "Destinatio"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Retning \""
},
"DISTANCE_LY": {
"description": "",
"message": "Afstand: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Ren kapitalisme - ingen offentlige velfærdsydelser"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Nulstil"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Nulstil Synspunkt og Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robotter"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" uden nogen betydningsfuld atmosfære\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Sideror"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Ung landbrugskoloni."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom ind"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brauner Zwerg (substellares Objekt)"
},
"BUTTON": {
"description": "",
"message": "\"-Taste \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Untere Ansicht"
@ -327,10 +323,6 @@
"description": "",
"message": "Reiseziel"
},
"DIRECTION": {
"description": "Direction",
"message": "\"-Richtung \""
},
"DISTANCE_LY": {
"description": "",
"message": "Entfernung: %distance{f.2} Lj"
@ -495,10 +487,6 @@
"description": "",
"message": "Rein kapitalistisch kein staatliches Sozialsystem"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\"-Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "{target} anti-normal halten"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Zurücksetzen"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Ansicht und Zoom zurücksetzen"
},
"ROBOTS": {
"description": "",
"message": "Roboter"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" ohne signifikante Atmosphäre\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Gieren"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Neu gegründete landwirtschaftliche Kolonie."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Vergrößern"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brown dwarf sub-stellar object"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Bottom camera"
@ -327,10 +323,6 @@
"description": "",
"message": "Destination"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distance: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Entirely Capitalist - no government welfare provision"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"ROBOTS": {
"description": "",
"message": "Ρομπότ"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" with no significant atmosphere\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Yaw"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Young farming colony."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brown dwarf sub-stellar object"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Bottom camera"
@ -327,10 +323,6 @@
"description": "",
"message": "Destination"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distance: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Entirely Capitalist - no government welfare provision"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -651,10 +639,6 @@
"description": "",
"message": "Joystick input"
},
"JOY_AXIS": {
"description": "Regarding joystick",
"message": "%{sign}%joyname %axis Axis"
},
"L4L5_DISPLAY_MODE_TOGGLE": {
"description": "Either show L4/L5 points or don't",
"message": "Switch between Lagrange L4/L5 point display modes."
@ -751,70 +735,6 @@
"description": "",
"message": "Manual control mode"
},
"MAP_LOCK_HYPERSPACE_TARGET": {
"description": "",
"message": "Lock Hyperspace Target"
},
"MAP_TOGGLE_INFO_PANEL": {
"description": "",
"message": "Toggle Info Panel"
},
"MAP_TOGGLE_SELECTION_FOLLOW_VIEW": {
"description": "",
"message": "Toggle Selection Following View"
},
"MAP_VIEW_ROTATE_DOWN": {
"description": "",
"message": "Rotate View Down"
},
"MAP_VIEW_ROTATE_LEFT": {
"description": "",
"message": "Rotate View Left"
},
"MAP_VIEW_ROTATE_RIGHT": {
"description": "",
"message": "Rotate View Right"
},
"MAP_VIEW_ROTATE_UP": {
"description": "",
"message": "Rotate View Up"
},
"MAP_VIEW_SHIFT_BACKWARD": {
"description": "",
"message": "Shift View Backwards"
},
"MAP_VIEW_SHIFT_DOWN": {
"description": "",
"message": "Shift View Down"
},
"MAP_VIEW_SHIFT_FORWARD": {
"description": "",
"message": "Shift View Forwards"
},
"MAP_VIEW_SHIFT_LEFT": {
"description": "",
"message": "Shift View Left"
},
"MAP_VIEW_SHIFT_RIGHT": {
"description": "",
"message": "Shift View Right"
},
"MAP_VIEW_SHIFT_UP": {
"description": "",
"message": "Shift View Up"
},
"MAP_WARP_TO_CURRENT_SYSTEM": {
"description": "",
"message": "Warp to Current System"
},
"MAP_WARP_TO_HYPERSPACE_TARGET": {
"description": "",
"message": "Warp to Hyperspace Target"
},
"MAP_WARP_TO_SELECTED_SYSTEM": {
"description": "",
"message": "Warp to Selected System"
},
"MASS": {
"description": "",
"message": "Mass"
@ -1231,10 +1151,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robots"
@ -1707,10 +1623,6 @@
"description": "",
"message": "Toggle HUD mode"
},
"TOGGLE_LUA_CONSOLE": {
"description": "",
"message": "Toggle Lua console"
},
"TOGGLE_RADAR_MODE": {
"description": "",
"message": "Toggle radar mode"
@ -1871,14 +1783,6 @@
"description": "",
"message": "\" with no significant atmosphere\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Yaw"
@ -1895,10 +1799,6 @@
"description": "",
"message": "Young farming colony."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brown dwarf sub-stellar object"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Bottom camera"
@ -327,10 +323,6 @@
"description": "",
"message": "Destination"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distance: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Entirely Capitalist - no government welfare provision"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robots"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" with no significant atmosphere\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Yaw"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Young farming colony."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Enana marrón (objeto subestelar)"
},
"BUTTON": {
"description": "",
"message": "\" Botón \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Cámara inferior"
@ -327,10 +323,6 @@
"description": "",
"message": "Destino"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distancia: %distance{f.2} AL"
@ -495,10 +487,6 @@
"description": "",
"message": "Capitalista puro - sin intervencion del estado"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Seta\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Fijar anti-normal con {target}"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reiniciar"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reiniciar orientación y zoom"
},
"ROBOTS": {
"description": "",
"message": "Robots"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" sin atmósfera significativa\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Guiñada"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Colonia agrícola joven."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Acercar"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Naine brune sous-stellaire."
},
"BUTTON": {
"description": "",
"message": "\"bouton\""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Vue Inférieure"
@ -327,10 +323,6 @@
"description": "",
"message": "Destination"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Doc \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distance: %distance{f.2} al"
@ -495,10 +487,6 @@
"description": "",
"message": "Entièrement capitaliste - pas de gouvernement réel"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\"Couv\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Maintenir {target} en direction anti-normale"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Réinitialise l'orientation et le zoom"
},
"ROBOTS": {
"description": "",
"message": "Robots"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" sans atmosphère significative\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Lacets"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Jeune colonie agricole."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom avant"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Abhac donn (rinn fo-réaltach)"
},
"BUTTON": {
"description": "",
"message": "\" Cnaipe \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Ceamara íochtarach"
@ -327,10 +323,6 @@
"description": "",
"message": "Ceann scríbe"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Treo \""
},
"DISTANCE_LY": {
"description": "",
"message": "Fad: %distance{f.2} sbh"
@ -495,10 +487,6 @@
"description": "",
"message": "Caipitlíoch amach is amach - gan aon chóras leasa shóisialaigh"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hata\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Athshocraigh"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Athshocraigh an Treoshuíomh agus an Zúmáil"
},
"ROBOTS": {
"description": "",
"message": "Róbait"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" gan atmaisféar arbh fhiú trácht air\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Luascáil"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Coilíneacht óg feirmeoireachta."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zúmáil isteach"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Troich dhonn - nì fo-reultach"
},
"BUTTON": {
"description": "",
"message": "\" Putan \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Camara a' bhuinn"
@ -327,10 +323,6 @@
"description": "",
"message": "Ceann-uidhe"
},
"DIRECTION": {
"description": "Direction",
"message": "\"Comhair\""
},
"DISTANCE_LY": {
"description": "",
"message": "Astar: %distance{f.2} bl-shol"
@ -495,10 +487,6 @@
"description": "",
"message": "Calpach gu tur - gun riaghaltas no sochair"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Ad\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Cum {target} gu h-an àbhaisteach"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Ath-shuidhich"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Ath-shuidhich a' chomhair agus an sùm"
},
"ROBOTS": {
"description": "",
"message": "Robotairean"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" gun àile ceart\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Claonadh"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Tuineachadh àiteachais òg."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Sùm a-steach"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Smeđi patuljak pod-zvijezdani objekt"
},
"BUTTON": {
"description": "",
"message": "\" Tipka \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Bottom camera"
@ -327,10 +323,6 @@
"description": "",
"message": "Cilj"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Smjer \""
},
"DISTANCE_LY": {
"description": "",
"message": "Udaljenost: %distance{f.2} sg"
@ -495,10 +487,6 @@
"description": "",
"message": "Potpuni kapitalizam - bez vladinih socijalnih davanja"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"ROBOTS": {
"description": "",
"message": "Roboti"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" sa beznačajnom atmosferom\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Skretanje"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Mlada poljoprivredna kolonija."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Povećaj"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Barna törpe objektum"
},
"BUTTON": {
"description": "",
"message": "\" Gomb \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Alsó kamera"
@ -327,10 +323,6 @@
"description": "",
"message": "Célállomás"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Irány \""
},
"DISTANCE_LY": {
"description": "",
"message": "Távolság: %distance{f.2} fényév"
@ -495,10 +487,6 @@
"description": "",
"message": "Teljesen kapitalista - kormányintézkedések nélkül"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Antinormál irány tartása"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Alaphelyzet"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Nézet alaphelyzetbe"
},
"ROBOTS": {
"description": "",
"message": "Robotok"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" számottevő atmoszféra nélkül\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Kitér"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Fiatal farmkolónia"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Közelítés"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brown dwarf sub-stellar object"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Kamera bawah"
@ -327,10 +323,6 @@
"description": "",
"message": "Tujuan"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Arah \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distance: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Entirely Capitalist - no government welfare provision"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robot"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" tanpa atmosfer signifikan\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Yaw"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Koloni pertanian muda."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Nana Bruna (oggetto substellare)"
},
"BUTTON": {
"description": "",
"message": "\" Pulsante \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Camera inferiore"
@ -327,10 +323,6 @@
"description": "",
"message": "Destinazione"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distanza: %distance{f.2} AL"
@ -495,10 +487,6 @@
"description": "",
"message": "Capitalismo perfetto - nessun intervento dello Stato in economia"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Mantieni {target} anti-normale"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Azzera Zoom"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reimposta Orientamento e Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robot"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" con atmosfera insignificante\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Imbardata"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Giovane colonia agricola."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom avanti"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Rudasis nykštukas - subžvaigždinis objektas"
},
"BUTTON": {
"description": "",
"message": "\" Mygtukas \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Kamera iš apačios"
@ -327,10 +323,6 @@
"description": "",
"message": "Paskirties vieta"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Katalogas \""
},
"DISTANCE_LY": {
"description": "",
"message": "Atstumas: %distance{f.2} šviesm."
@ -495,10 +487,6 @@
"description": "",
"message": "Visiškai kapitalistinė - nėra valstybinės socialinės paramos"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Kepurė \""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Perkrauti"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Atitaisyti kryptį ir priartinimą"
},
"ROBOTS": {
"description": "",
"message": "Robotai"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" neturi reikšmingos atmosferos\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Nuokrypis"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Jauna žemės ūkio kolonija."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Priartinti"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brown dwarf sub-stellar object"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Bottom camera"
@ -327,10 +323,6 @@
"description": "",
"message": "Destinasjon"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distance: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Entirely Capitalist - no government welfare provision"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"ROBOTS": {
"description": "",
"message": "Roboter"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" with no significant atmosphere\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Yaw"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Young farming colony."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Bruine dwerg, sub-stellair object"
},
"BUTTON": {
"description": "",
"message": "\" Knop \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Onderste camera"
@ -327,10 +323,6 @@
"description": "",
"message": "Bestemming"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Richting \""
},
"DISTANCE_LY": {
"description": "",
"message": "Afstand: %distance{f.2} lj"
@ -495,10 +487,6 @@
"description": "",
"message": "Volkomen kapitalistisch - geen overheids-gesubsidieerde welzijnsvoorzieningen"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hoed\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Behoud {target} anti-normaal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Herinstellen Oriëntatie en Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robots"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" zonder significante atmosfeer\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Gier"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Jonge agrarische kolonie."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brązowy karzeł"
},
"BUTTON": {
"description": "",
"message": "\" przycisk \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Dolna kamera"
@ -327,10 +323,6 @@
"description": "",
"message": "Punkt docelowy"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Dystans: %distance{f.2} lś"
@ -495,10 +487,6 @@
"description": "",
"message": "Całkowity Kapitalizm - bez opieki społecznej"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Utrzymuj się wzdłuż antynormalnej do {target}"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset orientacji i zbliżenia"
},
"ROBOTS": {
"description": "",
"message": "Roboty"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" bez znaczącej atmosfery\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Odchylenie poziome"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Młoda kolonia rolnicza."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zbliż"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Objeto sub-estelar anã castanha"
},
"BUTTON": {
"description": "",
"message": "\" Botão \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Câmara inferior"
@ -327,10 +323,6 @@
"description": "",
"message": "Destino"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distância: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Completamente Capitalista - não há segurança social do estado"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reiniciar"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robôs"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" sem atmosfera significativa\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Yaw"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Colónia agrícola jovem."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zoom in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Objeto sub-estelar anã marrom"
},
"BUTTON": {
"description": "",
"message": "\" Botão \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Câmera inferior"
@ -327,10 +323,6 @@
"description": "",
"message": "Destino"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distância: %distance{f.2} al"
@ -495,10 +487,6 @@
"description": "",
"message": "Completamente Capitalista - governo não faz provisões para o bem-estar"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Chapéu\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reiniciar Orientação e Zoom"
},
"ROBOTS": {
"description": "",
"message": "Robôs"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" sem atmosfera significativa\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Guinada"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Jovem colônia agricultora."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Aproximar zoom"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Obiect sub-stelar pitică cenușie"
},
"BUTTON": {
"description": "",
"message": "\" Buton \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Vedere de jos"
@ -327,10 +323,6 @@
"description": "",
"message": "Destinație"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distanța: %distance{f.2} al"
@ -495,10 +487,6 @@
"description": "",
"message": "Complet Capitalist - nici o dispoziție pentru prosperitatea guvernului"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Buton vizualizare\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Menține {target} înclinația anti-normală"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Resetare"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Resetează Orientare și Focalizare"
},
"ROBOTS": {
"description": "",
"message": "Roboți"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" fără atmosferă semnificativă\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Girare"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Colonie proaspătă de agricultură."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Focalizează"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Коричневый карлик - субзвёздный объект"
},
"BUTTON": {
"description": "",
"message": "\" Кнопка \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Нижний экран"
@ -327,10 +323,6 @@
"description": "",
"message": "Пункт назначения"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Напр. \""
},
"DISTANCE_LY": {
"description": "",
"message": "Расстояние: %distance{f.2} СвЛ"
@ -495,10 +487,6 @@
"description": "",
"message": "Ультракапитализм - отсутствие соцгарантий."
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Удерживать {target} против нормали"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Сброс"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Камера по умолчанию"
},
"ROBOTS": {
"description": "",
"message": "Роботы"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" с разрежённой атмосферой\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Управление рысканьем"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Молодая сельскохозяйственная колония."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Приблизить камеру"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Brunt dvärgstjärnobjekt"
},
"BUTTON": {
"description": "",
"message": "\" Knapp \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Nedre kamera"
@ -327,10 +323,6 @@
"description": "",
"message": "Destination"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"DISTANCE_LY": {
"description": "",
"message": "Distans: %distance{f.2} ly"
@ -495,10 +487,6 @@
"description": "",
"message": "Helt kapitalistiskt - ingen välfärd tillhandahållen från regeringen"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hatt\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Hold {target} anti-normal"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Återställ"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Återställ orientering och zoom"
},
"ROBOTS": {
"description": "",
"message": "Robotar"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" utan någon nämnbar atmosfär\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Gira"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Ung jordbrukskoloni."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Zooma in"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "Kahverengi cüce alt-yıldız cismi"
},
"BUTTON": {
"description": "",
"message": "\" Düğme \""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "Alt kamera"
@ -327,10 +323,6 @@
"description": "",
"message": "Hedef"
},
"DIRECTION": {
"description": "Direction",
"message": "\" Yön \""
},
"DISTANCE_LY": {
"description": "",
"message": "Uzaklık: %distance{f.2} Iy"
@ -495,10 +487,6 @@
"description": "",
"message": "Tamamen Kapitalist - yönetim mal varlığını düzenlemiyor"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Üst düğme\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "Ters-dikey yönelimde {target} sabitle"
@ -1231,10 +1219,6 @@
"description": "",
"message": "Yeniden başlat"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Yönelim ve Yakınlaştırmayı Sıfırla"
},
"ROBOTS": {
"description": "",
"message": "Robotlar"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\" belli bir atmosferi yok\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "Sapma"
@ -1895,10 +1871,6 @@
"description": "",
"message": "Genç tarım kolonisi."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "Yakınlaştır"

View File

@ -103,10 +103,6 @@
"description": "",
"message": "褐矮星亚恒星体"
},
"BUTTON": {
"description": "",
"message": "\"按钮\""
},
"CAMERA_BOTTOM_VIEW": {
"description": "",
"message": "底部摄像机"
@ -327,10 +323,6 @@
"description": "",
"message": "目的地"
},
"DIRECTION": {
"description": "Direction",
"message": "\"目录\""
},
"DISTANCE_LY": {
"description": "",
"message": "距离: %distance{f.2} 光年"
@ -495,10 +487,6 @@
"description": "",
"message": "完全资本主义 - 政府不提供福利"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\"帽子\""
},
"HEADING_LOCK_ANTINORMAL": {
"description": "Autopilot direction (perpendicular, down), relative to plane of orbit",
"message": "保持{target}反法线"
@ -1231,10 +1219,6 @@
"description": "",
"message": "重置"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "重置方向和缩放"
},
"ROBOTS": {
"description": "",
"message": "机器人"
@ -1871,14 +1855,6 @@
"description": "",
"message": "\"没有明显大气\""
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"YAW": {
"description": "",
"message": "偏航"
@ -1895,10 +1871,6 @@
"description": "",
"message": "新兴的农业殖民地."
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
},
"ZOOM_IN": {
"description": "",
"message": "放大"

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" زر \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "تحكم الروئية الرئيسي"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "اسلحة"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" قبعة\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Увеличение на Изглед"
},
"BUTTON": {
"description": "",
"message": "\" Бутон \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Пос \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Общи Контроли за Изглед"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Оръжия"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Общи Контроли"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Увеличение:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" botó \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Controls de vista general"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Armes"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Bolet\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" klávesa \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" směr \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Ovládací prvky celkového pohledu"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Zbraně"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" klobouk\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Knap \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Retning \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Generel synspunktsstyring"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Våben"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Ansicht zoomen"
},
"BUTTON": {
"description": "",
"message": "\"-Taste \""
},
"DIRECTION": {
"description": "Direction",
"message": "\"-Richtung \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Allgemeine Ansichtssteuerung"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Waffen"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\"-Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Allgemeine Steuerung"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positiv:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "General View Controls"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Weapons"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -1,4 +1,8 @@
{
"AXIS": {
"description": "Cardinal name used to compose Joystick <X> Button <Y>",
"message": " Axis "
},
"BIND_AXIS_PITCH": {
"description": "Descriptive name for the Pitch axis.",
"message": "Pitch"
@ -91,6 +95,18 @@
"description": "Axis binding",
"message": "Map Yaw"
},
"BIND_MAP_WARP_TO_CURRENT_SYSTEM": {
"description": "Descriptive name for the MapWarpToCurrentSystem action.",
"message": "Warp to Current System"
},
"BIND_MAP_WARP_TO_SELECTED_SYSTEM": {
"description": "Descriptive name for the MapWarpToSelectedSystem action.",
"message": "Warp to Selected System"
},
"BIND_MAP_TOGGLE_SELECTION_FOLLOW_VIEW": {
"description": "Descriptive name for the MapToggleSelectionFollowView action.",
"message": "Toggle Selection Following View"
},
"BIND_PRIMARY_FIRE": {
"description": "Descriptive name for the PrimaryFire action.",
"message": "Primary Fire"
@ -103,6 +119,10 @@
"description": "Descriptive name for the ResetCamera action.",
"message": "Reset Camera View to Default"
},
"BIND_RESET_ORIENTATION_AND_ZOOM": {
"description": "Descriptive name for the ResetOrientationAndZoom action.",
"message": "Reset Orientation and Zoom"
},
"BIND_RIGHT_CAMERA": {
"description": "Descriptive name for the RightCamera action.",
"message": "Switch to Right Camera"
@ -127,6 +147,10 @@
"description": "Descriptive name for the ToggleHudMode action.",
"message": "Toggle HUD Mode"
},
"BIND_TOGGLE_LUA_CONSOLE": {
"description": "Descriptive name for the ToggleLuaConsole action.",
"message": "Toggle Lua console"
},
"BIND_TOGGLE_ROTATION_DAMPING": {
"description": "Descriptive name for the ToggleRotationDamping action.",
"message": "Toggle Rotation Damping"
@ -143,6 +167,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "General View Controls"
@ -170,6 +202,26 @@
"description": "Header for the Weapons input group.",
"message": "Weapons"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"MOUSE": {
"description": "A computer mouse, used to create the name for a mouse button binding",
"message": "Mouse "
},
"MOUSE_LMB": {
"description": "An acronym for the left mouse button",
"message": "LMB"
},
"MOUSE_MMB": {
"description": "An acronym for the middle mouse button",
"message": "MMB"
},
"MOUSE_RMB": {
"description": "An acronym for the right mouse button",
"message": "RMB"
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +269,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "General View Controls"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Weapons"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Botón \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Vista General"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Armamento"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Seta\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Controles Generales"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positivo:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Zoom vue"
},
"BUTTON": {
"description": "",
"message": "\"bouton\""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Doc \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Contrôles de vue généraux"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Armes"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\"Couv\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Contrôles généraux"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positif:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Cnaipe \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Treo \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Rialtáin Ghinearálta Radhairc"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Airm"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hata\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Putan \""
},
"DIRECTION": {
"description": "Direction",
"message": "\"Comhair\""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Uidheaman-smachd coitcheann"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Airm"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Ad\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Tipka \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Smjer \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "General View Controls"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Oružja"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Gomb \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Irány \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Általános nézet vezérlők"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Fegyverek"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Általános"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Pozitív:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Arah \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "General View Controls"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Senjata"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Zoom Vista"
},
"BUTTON": {
"description": "",
"message": "\" Pulsante \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Controlli Generali della Visuale"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Armamenti"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Controlli Generici"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positivo:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Mygtukas \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Katalogas \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Bendras Vaizdo Valdymas"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Ginklai"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Kepurė \""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Button \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "General View Controls"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Weapons"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Knop \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Richting \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Algemeen zicht beheer"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Wapens"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hoed\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Powiększ widok"
},
"BUTTON": {
"description": "",
"message": "\" przycisk \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Kontrolki widoku głównego"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Bronie"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Kontrolki ogólne"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Botão \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "General View Controls"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Armas"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Botão \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Controles de vista geral"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Armas"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Chapéu\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Buton \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Controale Generale Vizionare"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Arme"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Buton vizualizare\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "View Zoom"
},
"BUTTON": {
"description": "",
"message": "\" Кнопка \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Напр. \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Управление камерой"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Управление оружием:"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hat\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "General Controls"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positive:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Zoom-vy"
},
"BUTTON": {
"description": "",
"message": "\" Knapp \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Dir \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Generella vykontroller"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Vapen"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Hatt\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Generella kontroller"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Positiv:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "Görüntü Yakınlaştırma"
},
"BUTTON": {
"description": "",
"message": "\" Düğme \""
},
"DIRECTION": {
"description": "Direction",
"message": "\" Yön \""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "Genel Görünüm Kontrolleri"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "Silahlar"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\" Üst düğme\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "Genel Kontroller"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "Pozitif:"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -143,6 +143,14 @@
"description": "Descriptive name for the View Zoom axis",
"message": "视图缩放"
},
"BUTTON": {
"description": "",
"message": "\"按钮\""
},
"DIRECTION": {
"description": "Direction",
"message": "\"目录\""
},
"GROUP_GENERAL_VIEW_CONTROLS": {
"description": "Header for the GeneralViewControls input group.",
"message": "通用视角控制"
@ -170,6 +178,10 @@
"description": "Header for the Weapons input group.",
"message": "武器"
},
"HAT": {
"description": "Hat switch: Is the top button on a joystick",
"message": "\"帽子\""
},
"PAGE_GENERAL": {
"description": "Header for the General input page.",
"message": "常规控制"
@ -217,5 +229,17 @@
"TEXT_KEY_POSITIVE": {
"description": "Indicates the positive half of a key-binding pair.",
"message": "正面"
},
"X": {
"description": "keybinding: x axis",
"message": "X"
},
"Y": {
"description": "keybinding: y axis",
"message": "Y"
},
"Z": {
"description": "keybinding: z axis",
"message": "Z"
}
}

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "اعادة"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "اعادة التوجية و التكبير"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Нулиране"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Нулирай Ориентацията и Мащабирането"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Върни се в играта"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reiniciar orientació i zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset orientace a zoomu"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Návrat do hry"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Nulstil"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Nulstil Synspunkt og Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Zurücksetzen"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Ansicht und Zoom zurücksetzen"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Zurück zum Spiel"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reiniciar"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reiniciar orientación y zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Volver al juego"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Réinitialise l'orientation et le zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Reprendre la partie"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Athshocraigh"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Athshocraigh an Treoshuíomh agus an Zúmáil"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Fill ar an gcluiche"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Ath-shuidhich"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Ath-shuidhich a' chomhair agus an sùm"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Till dhan gheama"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Alaphelyzet"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Nézet alaphelyzetbe"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Vissza"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Azzera"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reimposta Orientamento e Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Torna al gioco"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Perkrauti"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Atitaisyti kryptį ir priartinimą"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Grįžti į žaidimą"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Herinstellen Oriëntatie en Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Terug naar spel"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset orientacji i zbliżenia"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Powrót do gry"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reiniciar"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reset Orientation and Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Return to game"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Reset"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Reiniciar Orientação e Zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Voltar ao jogo"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Resetare"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Resetează Orientare și Focalizare"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Întoarcere în joc"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Сброс"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Камера по умолчанию"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Вернуться к игре"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Återställ"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Återställ orientering och zoom"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Återgå till spelet"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "Yeniden başlat"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "Yönelim ve Yakınlaştırmayı Sıfırla"
},
"RETURN_TO_GAME": {
"description": "",
"message": "Oyuna dön"

View File

@ -1643,6 +1643,10 @@
"description": "",
"message": "重置"
},
"RESET_ORIENTATION_AND_ZOOM": {
"description": "",
"message": "重置方向和缩放"
},
"RETURN_TO_GAME": {
"description": "",
"message": "返回游戏"

View File

@ -276,7 +276,7 @@ end
function Windows.edgeButtons.Show()
-- view control buttons
if mainMenuButton(icons.reset_view, lc.RESET_ORIENTATION_AND_ZOOM) then
if mainMenuButton(icons.reset_view, lui.RESET_ORIENTATION_AND_ZOOM) then
sectorView:ResetView()
end
mainMenuButton(icons.rotate_view, lui.ROTATE_VIEW)

View File

@ -15,12 +15,45 @@ local linput = Lang.GetResource("input-core")
local ui = require 'pigui'
local ModalWindow = require 'pigui.libs.modal-win'
local function l18n_key_from_id(str)
return str:gsub("([^A-Z0-9_])([A-Z0-9])", "%1_%2"):upper()
end
-- convert an axis binding style ID to a translation resource identifier
local function localize_binding_id(str)
-- TODO: avoid reading lines from the "Core" resource (lc)
-- it's here to reuse old strings (keyboard bindings for maps in KeyBindings.inc.h)
local jsonIndex = str:gsub("([^A-Z0-9_])([A-Z0-9])", "%1_%2"):upper()
return rawget(linput, jsonIndex) or rawget(lc, jsonIndex) or error("NO_JSON: " .. jsonIndex)
return rawget(linput, jsonIndex) or '[NO_JSON] '..jsonIndex
end
local function get_binding_desc(bind)
if not bind then return end
local axis_names = { linput.X, linput.Y, linput.Z }
local mouse_names = { linput.MOUSE_LMB, linput.MOUSE_MMB, linput.MOUSE_RMB }
if bind.key then
return Input.GetKeyName(bind.key)
elseif bind.joystick and bind.hat then
return Input.GetJoystickName(bind.joystick) .. linput.HAT .. bind.hat .. linput.DIRECTION .. bind.dir
elseif bind.joystick and bind.button then
return Input.GetJoystickName(bind.joystick) .. linput.BUTTON .. bind.button
elseif bind.joystick and bind.axis then
return (bind.direction < 0 and "-" or "") .. Input.GetJoystickName(bind.joystick) .. linput.AXIS .. (axis_names[bind.axis + 1] or tostring(bind.axis))
elseif bind.mouse then
return linput.MOUSE .. (mouse_names[bind.mouse + 1] or tostring(bind.mouse))
end
end
-- Get a localized name for a key chord to display on a binding
local function get_chord_desc(chord)
if not chord.enabled then return "" end
local str = get_binding_desc(chord.activator)
local mod1 = chord.modifier1
local mod2 = chord.modifier2
if mod1 then str = str .. " + " .. get_binding_desc(mod1) end
if mod2 then str = str .. " + " .. get_binding_desc(mod2) end
return str
end
local player = nil
@ -41,7 +74,7 @@ local optionsWinSize = Vector2(ui.screenWidth * 0.4, ui.screenHeight * 0.6)
local showTab = 'video'
local binding_pages
local keyCaptureId
local keyCaptureBind
local keyCaptureNum
local function combo(label, selected, items, tooltip)
@ -278,66 +311,46 @@ end
local captureBindingWindow
captureBindingWindow = ModalWindow.New("CaptureBinding", function()
local info
for _,page in pairs(binding_pages) do
for _,group in pairs(page) do
if group.id then
for _,i in pairs(group) do
if i.id == keyCaptureId then
info = i
end
end
end
end
end
local info = keyCaptureBind
ui.text(localize_binding_id(info.id))
ui.text(lui.PRESS_A_KEY_OR_CONTROLLER_BUTTON)
if info.type == 'action' then
local desc
if keyCaptureNum == 1 then desc = info.bindingDescription1
else desc = info.bindingDescription2 end
desc = desc or '<None>'
ui.text(desc)
if info.type == 'Action' then
local desc = keyCaptureNum == 1 and info.binding or info.binding2
ui.text(desc.enabled and get_chord_desc(desc) or '<None>')
local bindingKey = Engine.pigui.GetKeyBinding()
local setBinding = false
if(bindingKey and keyCaptureNum==1 and bindingKey~=info.binding1) or (bindingKey and keyCaptureNum==2 and bindingKey~=info.binding2) then setBinding = true end
if setBinding and keyCaptureNum == 1 then Input.SetActionBinding(info.id, bindingKey, info.binding2)
elseif setBinding and keyCaptureNum==2 then Input.SetActionBinding(info.id, info.binding1, bindingKey)
local set, bindingKey = Engine.pigui.GetKeyBinding()
if set then
if keyCaptureNum == 1 then info.binding = bindingKey
else info.binding2 = bindingKey end
end
elseif info.type == 'axis' then
elseif info.type == 'Axis' then
local desc
if keyCaptureNum == 1 then desc = info.axisDescription
elseif keyCaptureNum == 2 then desc = info.positiveDescription
else desc = info.negativeDescription end
desc = desc or '<None>'
if keyCaptureNum == 1 then
desc = get_binding_desc(info.axis) or '<None>'
else
desc = keyCaptureNum == 2 and info.positive or info.negative
desc = desc.enabled and get_chord_desc(desc) or '<None>'
end
ui.text(desc)
if keyCaptureNum == 1 then
local bindingAxis = Engine.pigui.GetAxisBinding()
if bindingAxis and bindingAxis~=info.axis then
Input.SetAxisBinding(info.id, bindingAxis, info.positive, info.negative)
end
local set, bindingAxis = Engine.pigui.GetAxisBinding()
if set then info.axis = bindingAxis end
elseif keyCaptureNum == 2 then
local bindingKey = Engine.pigui.GetKeyBinding()
if bindingKey and bindingKey ~= info.positive then
Input.SetAxisBinding(info.id, info.axis, bindingKey, info.negative)
end
local set, bindingKey = Engine.pigui.GetKeyBinding()
if set then info.positive = bindingKey end
else
local bindingKey = Engine.pigui.GetKeyBinding()
if bindingKey and bindingKey ~= info.negative then
Input.SetAxisBinding(info.id, info.axis, info.positive, bindingKey)
end
local set, bindingKey = Engine.pigui.GetKeyBinding()
if set then info.negative = bindingKey end
end
end
optionTextButton(lui.OK, nil, true, function() captureBindingWindow:close() end)
optionTextButton(lui.OK, nil, true, function()
Input.SaveBinding(info)
captureBindingWindow:close()
end)
end, function (self, drawPopupFn)
ui.setNextWindowPosCenter('Always')
ui.withStyleColorsAndVars({["PopupBg"] = Color(20, 20, 80, 230)}, {WindowBorderSize = 1}, drawPopupFn)
@ -394,22 +407,24 @@ local function showLanguageOptions()
end
local function actionBinding(info)
local bindings = { info.binding1, info.binding2 }
local descs = { info.bindingDescription1, info.bindingDescription2 }
local descs = {
get_chord_desc(info.binding),
get_chord_desc(info.binding2)
}
if (ui.collapsingHeader(localize_binding_id(info.id), {})) then
ui.columns(3,"##bindings",false)
ui.nextColumn()
ui.text(linput.TEXT_BINDING)
bindingTextButton((descs[1] or '')..'##'..info.id..'1', (descs[1] or ''), true, function()
keyCaptureId = info.id
keyCaptureBind = info
keyCaptureNum = 1
captureBindingWindow:open()
end)
ui.nextColumn()
ui.text(linput.TEXT_ALT_BINDING)
bindingTextButton((descs[2] or '')..'##'..info.id..'2', (descs[2] or ''), true, function()
keyCaptureId = info.id
keyCaptureBind = info
keyCaptureNum = 2
captureBindingWindow:open()
end)
@ -418,51 +433,38 @@ local function actionBinding(info)
end
local function axisBinding(info)
local bindings = { info.axis, info.positive, info.negative }
local descs = { info.axisDescription, info.positiveDescription, info.negativeDescription }
local axis, positive, negative = info.axis, info.positive, info.negative
local descs = { get_binding_desc(axis), get_chord_desc(positive), get_chord_desc(negative) }
if (ui.collapsingHeader(localize_binding_id(info.id), {})) then
ui.columns(3,"##axisjoybindings",false)
ui.text("Axis:")
ui.nextColumn()
bindingTextButton((descs[1] or '')..'##'..info.id..'axis', (descs[1] or ''), true, function()
keyCaptureId = info.id
keyCaptureBind = info
keyCaptureNum = 1
captureBindingWindow:open()
end)
ui.nextColumn()
if info.axis then
local c, inverted, deadzone, sensitivity = nil, info.axis:sub(1,1) == "-",
tonumber(info.axis:match"/DZ(%d+%.%d*)" or 0) * 100,
tonumber(info.axis:match"/E(%d+%.%d*)" or 1) * 100
local axis = info.axis:match("Joy[0-9a-f]+/Axis%d+")
local function set_axis()
local _ax = (inverted and "-" or "") .. axis .. "/DZ" .. deadzone / 100.0 .. "/E" .. sensitivity / 100.0
Input.SetAxisBinding(info.id, _ax, info.positive, info.negative)
end
if axis then
local c, inverted = nil, axis.direction < 0
c,inverted = ui.checkbox("Inverted##"..info.id, inverted, linput.TEXT_INVERT_AXIS)
set_axis()
ui.nextColumn()
ui.nextColumn()
c, deadzone = slider("Deadzone##"..info.id, deadzone, 0, 100, linput.TEXT_AXIS_DEADZONE)
set_axis()
ui.nextColumn()
c, sensitivity = slider("Sensitivity##"..info.id, sensitivity, 0, 100, linput.TEXT_AXIS_SENSITIVITY)
set_axis()
if c then axis.direction = inverted and -1 or 1; info.axis = axis end
end
-- new row
ui.nextColumn()
ui.columns(3,"##axiskeybindings",false)
ui.text(linput.TEXT_KEY_BINDINGS)
ui.nextColumn()
ui.text(linput.TEXT_KEY_POSITIVE)
bindingTextButton((descs[2] or '')..'##'..info.id..'positive', (descs[2] or ''), true, function()
keyCaptureId = info.id
keyCaptureBind = info
keyCaptureNum = 2
captureBindingWindow:open()
end)
ui.nextColumn()
ui.text(linput.TEXT_KEY_NEGATIVE)
bindingTextButton((descs[3] or '')..'##'..info.id..'negative', (descs[3] or ''), true, function()
keyCaptureId = info.id
keyCaptureBind = info
keyCaptureNum = 3
captureBindingWindow:open()
end)
@ -475,7 +477,7 @@ local function showControlsOptions()
local mouseYInvert = Input.GetMouseYInverted()
local joystickEnabled = Input.GetJoystickEnabled()
binding_pages = Input.GetBindings()
binding_pages = Input.GetBindingPages()
local c
c,mouseYInvert = checkbox(lui.INVERT_MOUSE_Y, mouseYInvert)
@ -490,22 +492,26 @@ local function showControlsOptions()
ui.text(localize_binding_id("Page" .. page.id))
end)
ui.separator()
Engine.pigui.PushID(page.id)
for _,group in ipairs(page) do
if group.id then
Engine.pigui.PushID(group.id)
if _ > 1 then ui.text '' end
ui.withFont(pionillium.medium.name, bindingGroupFontSize, function()
ui.text(localize_binding_id("Group" .. group.id))
end)
ui.separator()
for _,info in ipairs(group) do
if info.type == 'action' then
actionBinding(info)
elseif info.type == 'axis' then
axisBinding(info)
for _,binding in ipairs(group) do
if binding.type == 'Action' then
actionBinding(binding)
elseif binding.type == 'Axis' then
axisBinding(binding)
end
end
Engine.pigui.PopID()
end
end
Engine.pigui.PopID()
end
end

View File

@ -181,7 +181,7 @@ local Windows = {
function Windows.edgeButtons.Show()
-- view control buttons
if ui.coloredSelectedIconButton(icons.reset_view, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_ACTIVE, svColor.BUTTON_INK, lc.RESET_ORIENTATION_AND_ZOOM) then
if ui.coloredSelectedIconButton(icons.reset_view, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_ACTIVE, svColor.BUTTON_INK, luc.RESET_ORIENTATION_AND_ZOOM) then
systemView:SetVisibility("RESET_VIEW")
end
ui.coloredSelectedIconButton(icons.rotate_view, mainButtonSize, false, mainButtonFramePadding, svColor.BUTTON_ACTIVE, svColor.BUTTON_INK, luc.ROTATE_VIEW)

View File

@ -298,7 +298,7 @@ ui.registerHandler('game', function(delta_t)
if not ui.optionsWindow.isOpen then
Game.SetTimeAcceleration("paused")
ui.optionsWindow:open()
Input.DisableBindings()
Input.EnableBindings(false)
else
ui.optionsWindow:close()
if not ui.optionsWindow.isOpen then

View File

@ -15,8 +15,8 @@ def write_translation_file(path, data):
with open(path, 'w', encoding='utf-8') as fl:
json.dump(data, fl,
ensure_ascii=False,
indent=3,
separators=(',',' : '),
indent=2,
separators=(',',': '),
sort_keys=True)
fl.write('\n')

View File

@ -58,6 +58,33 @@ namespace AnimationCurves {
return 0.5 * (1.0 - std::cos(p * M_PI));
}
// Based on http://blog.moagrius.com/actionscript/jsas-understanding-easing/
// and observations from Godot Engine and Star Citizen
// This supports four different easing functions encoded in a single float:
// e == 1.0|-1.0: linear easing, returns p
// e > 1.0: in-quadratic, in-cubic etc. for e = 2.0, e = 3.0 ...
// e < 1.0: out-quadratic, out-cubic etc. for e = 0.5, e = 0.33_ ...
// e == 0.0: returns zero
// e > -1.0: reverse inout-quadratic, inout-cubic for e = -0.5, e = -0.33_ ...
// e < -1.0: inout-quadratic, inout-cubic etc. for e = -2.0, e = -3.0 ...
inline float SmoothEasing(double p, double e)
{
// e > 0.0 = ease in or out / e < 0.0 = ease in-out
if (e > 0.0) {
// e < 1.0 = ease out / e > 1.0 = ease in
return e < 1.0 ? (1.0 - pow(1.0 - p, 1.0 / e)) : (pow(p, e));
} else if (e < 0) {
// Ease in-out at arbirary exponents (the e term is negated to get positive exponent)
float m = (p - 0.5) * 2.0;
float t = p * 2.0;
if (t < 1)
return pow(t, -e) * 0.5;
else
return (1.0 - pow(1.0 - m, -e)) * 0.5 + 0.5;
} else // completely flat at 0.0
return 0.0;
}
} // namespace AnimationCurves
#endif

View File

@ -3,7 +3,6 @@
#include "GameConfig.h"
#include "FileSystem.h"
#include "KeyBindings.h"
GameConfig::GameConfig(const map_string &override_)
{
@ -13,8 +12,8 @@ GameConfig::GameConfig(const map_string &override_)
map["AMD_MESA_HACKS"] = "0";
map["DisableSound"] = "0";
map["StartFullscreen"] = "0";
map["ScrWidth"] = "800";
map["ScrHeight"] = "600";
map["ScrWidth"] = "1280";
map["ScrHeight"] = "720";
map["UIScaleFactor"] = "1";
map["DetailCities"] = "1";
map["DetailPlanets"] = "1";
@ -51,7 +50,7 @@ GameConfig::GameConfig(const map_string &override_)
map["EnableGPUJobs"] = "1";
map["GL3ForwardCompatible"] = "1";
Load();
Read(FileSystem::userFiles, "config.ini");
for (auto i = override_.begin(); i != override_.end(); ++i) {
const std::string &key = (*i).first;
@ -59,13 +58,3 @@ GameConfig::GameConfig(const map_string &override_)
map[key] = val;
}
}
void GameConfig::Load()
{
Read(FileSystem::userFiles, "config.ini");
}
bool GameConfig::Save()
{
return Write(FileSystem::userFiles, "config.ini");
}

View File

@ -10,9 +10,6 @@ class GameConfig : public IniConfig {
public:
typedef std::map<std::string, std::string> map_string;
GameConfig(const map_string &override_ = map_string());
void Load();
bool Save();
};
#endif

View File

@ -2,44 +2,442 @@
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#include "Input.h"
#include "AnimationCurves.h"
#include "GameConfig.h"
#include "InputBindings.h"
#include "Pi.h"
#include "SDL.h"
#include "SDL_events.h"
#include "SDL_joystick.h"
#include "ui/Context.h"
#include <array>
#include <regex>
#include <sstream>
#include <type_traits>
Input::Input(IniConfig *config) :
using namespace Input;
namespace Input {
std::vector<sigc::slot<void(Input::Manager *)>> *m_registrations;
std::vector<sigc::slot<void(Input::Manager *)>> &GetBindingRegistration()
{
return *m_registrations;
}
bool AddBindingRegistrar(sigc::slot<void(Input::Manager *)> &&fn)
{
static std::vector<sigc::slot<void(Input::Manager *)>> registrations;
m_registrations = &registrations;
registrations.push_back(fn);
return true;
}
} // namespace Input
/*
STATIC JOYSTICK HANDLING
*/
namespace Input {
std::map<SDL_JoystickID, JoystickInfo> m_joysticks;
InputBindings::Action nullAction;
InputBindings::Axis nullAxis;
} // namespace Input
std::string Input::JoystickName(int joystick)
{
return m_joysticks[joystick].name;
}
std::string Input::JoystickGUIDString(int joystick)
{
const int guidBufferLen = 33; // as documented by SDL
char guidBuffer[guidBufferLen];
SDL_JoystickGetGUIDString(m_joysticks[joystick].guid, guidBuffer, guidBufferLen);
return std::string(guidBuffer);
}
// conveniance version of JoystickFromGUID below that handles the string mangling.
int Input::JoystickFromGUIDString(const std::string &guid)
{
return JoystickFromGUIDString(guid.c_str());
}
// conveniance version of JoystickFromGUID below that handles the string mangling.
int Input::JoystickFromGUIDString(const char *guid)
{
return JoystickFromGUID(SDL_JoystickGetGUIDFromString(guid));
}
// return the internal ID of the stated joystick guid.
// returns -1 if we couldn't find the joystick in question.
int Input::JoystickFromGUID(SDL_JoystickGUID guid)
{
const int guidLength = 16; // as defined
for (auto pair : m_joysticks) {
JoystickInfo &state = pair.second;
if (0 == memcmp(state.guid.data, guid.data, guidLength)) {
return static_cast<int>(pair.first);
}
}
return -1;
}
SDL_JoystickGUID Input::JoystickGUID(int joystick)
{
return m_joysticks[joystick].guid;
}
static std::string saveAxisConfig(const Input::JoystickInfo::Axis &axis)
{
return fmt::format("DZ{:.1f} CV{:.1f}{}", axis.deadzone, axis.curve, (axis.zeroToOne ? " Half" : ""));
}
static void loadAxisConfig(const std::string &str, Input::JoystickInfo::Axis &outAxis)
{
std::regex matcher("DZ([\\d\\.]+)\\s*(?:CV(-?[\\d\\.]+))?\\s*(Half)?", std::regex::icase);
std::smatch match_results;
if (std::regex_search(str, match_results, matcher)) {
outAxis.deadzone = std::stof(match_results[1].str());
outAxis.curve = match_results[2].matched ? std::stof(match_results[2].str()) : 1.0;
outAxis.zeroToOne = match_results[3].matched;
}
outAxis.value = 0;
}
void Input::InitJoysticks(IniConfig *config)
{
SDL_Init(SDL_INIT_JOYSTICK);
int joy_count = SDL_NumJoysticks();
Output("Initializing joystick subsystem.\n");
for (int n = 0; n < joy_count; n++) {
JoystickInfo state;
state.joystick = SDL_JoystickOpen(n);
if (!state.joystick) {
Warning("SDL_JoystickOpen(%i): %s\n", n, SDL_GetError());
continue;
}
state.name = SDL_JoystickName(state.joystick);
state.guid = SDL_JoystickGetGUID(state.joystick);
state.axes.resize(SDL_JoystickNumAxes(state.joystick));
state.buttons.resize(SDL_JoystickNumButtons(state.joystick));
state.hats.resize(SDL_JoystickNumHats(state.joystick));
std::array<char, 33> joystickGUIDName;
SDL_JoystickGetGUIDString(state.guid, joystickGUIDName.data(), joystickGUIDName.size());
Output("Found joystick '%s' (GUID: %s)\n", SDL_JoystickName(state.joystick), joystickGUIDName.data());
Output(" - %ld axes, %ld buttons, %ld hats\n", state.axes.size(), state.buttons.size(), state.hats.size());
std::string joystickName = "Joystick." + std::string(joystickGUIDName.data());
config->SetString(joystickName, "Name", state.name);
for (size_t i = 0; i < state.axes.size(); i++) {
std::string axisName = "Axis" + std::to_string(i);
if (!config->HasEntry(joystickName, axisName)) {
config->SetString(joystickName, axisName, saveAxisConfig(state.axes[i]));
continue;
}
loadAxisConfig(config->String(joystickName, axisName, ""), state.axes[i]);
Output(" - axis %ld: deadzone %.2f, curve: %.2f, half-axis mode: %b\n",
i, state.axes[i].deadzone, state.axes[i].curve, state.axes[i].zeroToOne);
}
SDL_JoystickID joyID = SDL_JoystickInstanceID(state.joystick);
m_joysticks[joyID] = state;
}
config->Save();
}
std::map<SDL_JoystickID, JoystickInfo> &Input::GetJoysticks()
{
return m_joysticks;
}
/*
INPUT MANAGER INITIALIZATION
*/
Manager::Manager(IniConfig *config) :
m_config(config),
keyModState(0),
mouseButton(),
mouseMotion(),
m_capturingMouse(false),
joystickEnabled(true),
mouseYInvert(false)
mouseYInvert(false),
m_enableBindings(true)
{
joystickEnabled = (m_config->Int("EnableJoystick")) ? true : false;
mouseYInvert = (m_config->Int("InvertMouseY")) ? true : false;
InitJoysticks();
Input::InitJoysticks(m_config);
}
void Input::InitGame()
void Manager::InitGame()
{
//reset input states
keyState.clear();
keyModState = 0;
mouseButton.fill(0);
mouseMotion.fill(0);
for (std::map<SDL_JoystickID, JoystickState>::iterator stick = joysticks.begin(); stick != joysticks.end(); ++stick) {
JoystickState &state = stick->second;
// Force a rebuild of key chords and modifier state
m_frameListChanged = true;
for (auto &pair : Input::GetJoysticks()) {
JoystickInfo &state = pair.second;
std::fill(state.buttons.begin(), state.buttons.end(), false);
std::fill(state.hats.begin(), state.hats.end(), 0);
std::fill(state.axes.begin(), state.axes.end(), 0.f);
for (auto &ax : state.axes) {
ax.value = 0.0;
}
}
}
void Input::NewFrame()
/*
BINDING AND INPUT FRAME HANDLING
*/
InputBindings::Action *InputFrame::AddAction(std::string id)
{
auto *action = manager->GetActionBinding(id);
if (!action)
throw std::runtime_error("Adding unknown action binding to InputFrame, id: " + id);
actions.push_back(action);
return action;
}
InputBindings::Axis *InputFrame::AddAxis(std::string id)
{
auto *axis = manager->GetAxisBinding(id);
if (!axis)
throw std::runtime_error("Adding unknown axis binding to an InputFrame, id: " + id);
axes.push_back(axis);
return axis;
}
bool Manager::PushInputFrame(InputFrame *frame)
{
if (HasInputFrame(frame)) {
return false;
}
m_inputFrames.push_back(frame);
frame->active = true;
frame->onFrameAdded.emit(frame);
m_frameListChanged = true;
return true;
}
InputFrame *Manager::PopInputFrame()
{
if (m_inputFrames.size() > 0) {
auto frame = m_inputFrames.back();
m_inputFrames.pop_back();
frame->active = false;
frame->onFrameRemoved.emit(frame);
m_frameListChanged = true;
return frame;
}
return nullptr;
}
void Manager::RemoveInputFrame(InputFrame *frame)
{
auto it = std::find(m_inputFrames.begin(), m_inputFrames.end(), frame);
if (it != m_inputFrames.end()) {
m_inputFrames.erase(it);
// When an input frame is removed, its actions and axes are no longer active.
for (auto *action : frame->actions) {
if (action->m_active) {
action->m_active = false;
action->onReleased.emit();
}
}
for (auto *axis : frame->axes) {
if (axis->m_value != 0.0) {
axis->m_value = 0.0;
axis->onAxisValue.emit(0.0);
}
}
frame->active = false;
frame->onFrameRemoved.emit(frame);
m_frameListChanged = true;
}
}
InputBindings::Action *Manager::AddActionBinding(std::string id, BindingGroup *group, InputBindings::Action &&binding)
{
// throw an error if we attempt to bind an action onto an already-bound axis in the same group.
if (group->bindings.count(id) && group->bindings[id] != BindingGroup::ENTRY_ACTION)
Error("Attempt to bind already-registered axis %s as an action.\n", id.c_str());
group->bindings[id] = BindingGroup::ENTRY_ACTION;
// Load from the config
std::string config_str = m_config->String(id.c_str());
if (!config_str.empty()) {
nonstd::string_view str(config_str);
str >> binding;
}
return &(actionBindings[id] = binding);
}
InputBindings::Axis *Manager::AddAxisBinding(std::string id, BindingGroup *group, InputBindings::Axis &&binding)
{
// throw an error if we attempt to bind an axis onto an already-bound action in the same group.
if (group->bindings.count(id) && group->bindings[id] != BindingGroup::ENTRY_AXIS)
Error("Attempt to bind already-registered action %s as an axis.\n", id.c_str());
group->bindings[id] = BindingGroup::ENTRY_AXIS;
// Load from the config
std::string config_str = m_config->String(id.c_str());
if (!config_str.empty()) {
nonstd::string_view str(config_str);
str >> binding;
}
return &(axisBindings[id] = binding);
}
InputBindings::Action *Manager::GetActionBinding(std::string id)
{
return actionBindings.count(id) ? &actionBindings[id] : &Input::nullAction;
}
InputBindings::Axis *Manager::GetAxisBinding(std::string id)
{
return axisBindings.count(id) ? &axisBindings[id] : &Input::nullAxis;
}
/*
STATE MANAGEMENT
*/
bool Manager::GetBindingState(InputBindings::KeyBinding &key)
{
using Type = InputBindings::KeyBinding::Type;
switch (key.type) {
case Type::Disabled:
return false;
case Type::KeyboardKey:
return KeyState(key.keycode);
case Type::JoystickButton:
return JoystickButtonState(key.joystick.id, key.joystick.button);
case Type::JoystickHat:
return (JoystickHatState(key.joystick.id, key.joystick.hat) & key.joystick.button) == key.joystick.button;
case Type::MouseButton:
return MouseButtonState(key.mouse.button);
default:
return false;
}
}
float Manager::GetAxisState(InputBindings::JoyAxis &axis)
{
if (axis.direction == 0)
return 0.0; // disabled
return JoystickAxisState(axis.joystickId, axis.axis) * float(axis.direction);
}
bool Manager::GetModifierState(InputBindings::KeyChord *chord)
{
bool mod1 = chord->modifier1.Enabled() ? m_modifiers[chord->modifier1] : true;
bool mod2 = chord->modifier2.Enabled() ? m_modifiers[chord->modifier2] : true;
return mod1 && mod2;
}
int Manager::JoystickButtonState(int joystick, int button)
{
if (!joystickEnabled) return 0;
if (joystick < 0 || joystick >= int(GetJoysticks().size()))
return 0;
if (button < 0 || button >= int(GetJoysticks()[joystick].buttons.size()))
return 0;
return GetJoysticks()[joystick].buttons[button];
}
int Manager::JoystickHatState(int joystick, int hat)
{
if (!joystickEnabled) return 0;
if (joystick < 0 || joystick >= int(GetJoysticks().size()))
return 0;
if (hat < 0 || hat >= int(GetJoysticks()[joystick].hats.size()))
return 0;
return GetJoysticks()[joystick].hats[hat];
}
float Manager::JoystickAxisState(int joystick, int axis)
{
if (!joystickEnabled) return 0;
if (joystick < 0 || joystick >= int(GetJoysticks().size()))
return 0;
if (axis < 0 || axis >= int(GetJoysticks()[joystick].axes.size()))
return 0;
return GetJoysticks()[joystick].axes[axis].value;
}
void Manager::SetJoystickEnabled(bool state)
{
joystickEnabled = state;
if (m_enableConfigSaving) {
m_config->SetInt("EnableJoystick", joystickEnabled);
m_config->Save();
}
}
void Manager::SetMouseYInvert(bool state)
{
mouseYInvert = state;
if (m_enableConfigSaving) {
m_config->SetInt("InvertMouseY", mouseYInvert);
m_config->Save();
}
}
/*
FRAME AND EVENT HANDLING
*/
void Manager::NewFrame()
{
mouseMotion.fill(0);
mouseWheel = 0;
@ -56,94 +454,83 @@ void Input::NewFrame()
break;
}
}
}
InputResponse Input::InputFrame::ProcessSDLEvent(SDL_Event &event)
{
bool matched = false;
for (KeyBindings::ActionBinding *action : actions) {
auto resp = action->CheckSDLEventAndDispatch(&event);
if (resp == RESPONSE_MATCHED) return resp;
matched = matched || resp > RESPONSE_NOMATCH;
}
for (KeyBindings::AxisBinding *axis : axes) {
auto resp = axis->CheckSDLEventAndDispatch(&event);
if (resp == RESPONSE_MATCHED) return resp;
matched = matched || resp > RESPONSE_NOMATCH;
}
return matched ? RESPONSE_PASSTHROUGH : RESPONSE_NOMATCH;
}
bool Input::PushInputFrame(Input::InputFrame *frame)
{
if (HasInputFrame(frame)) {
return false;
}
inputFrames.push_back(frame);
frame->active = true;
frame->onFrameAdded();
return true;
}
Input::InputFrame *Input::PopInputFrame()
{
if (inputFrames.size() > 0) {
auto frame = inputFrames.back();
inputFrames.pop_back();
frame->active = false;
frame->onFrameRemoved();
return frame;
}
return nullptr;
}
void Input::RemoveInputFrame(Input::InputFrame *frame)
{
auto it = std::find(inputFrames.begin(), inputFrames.end(), frame);
if (it != inputFrames.end()) {
inputFrames.erase(it);
frame->active = false;
frame->onFrameRemoved();
if (m_frameListChanged) {
RebuildInputFrames();
}
}
KeyBindings::ActionBinding *Input::AddActionBinding(std::string id, BindingGroup *group, KeyBindings::ActionBinding binding)
void Manager::RebuildInputFrames()
{
// throw an error if we attempt to bind an action onto an already-bound axis in the same group.
if (group->bindings.count(id) && group->bindings[id] != BindingGroup::ENTRY_ACTION)
Error("Attempt to bind already-registered axis %s as an action.\n", id.c_str());
// Reset the list of active chords.
m_chords.clear();
m_activeActions.clear();
m_activeAxes.clear();
group->bindings[id] = BindingGroup::ENTRY_ACTION;
for (const auto *frame : reverse_container(m_inputFrames)) {
// Load from the config
std::string config_str = m_config->String(id.c_str());
if (config_str.length() > 0) binding.SetFromString(config_str);
// Push all enabled key chords onto the key chord stack.
for (auto *action : frame->actions) {
if (!action->Enabled())
continue;
return &(actionBindings[id] = binding);
m_activeActions.push_back(action);
assert(m_activeActions.back() == action);
if (action->binding.Enabled())
m_chords.push_back(&action->binding);
if (action->binding2.Enabled())
m_chords.push_back(&action->binding2);
}
for (auto *axis : frame->axes) {
if (!axis->Enabled())
continue;
m_activeAxes.push_back(axis);
if (axis->positive.Enabled())
m_chords.push_back(&axis->positive);
if (axis->negative.Enabled())
m_chords.push_back(&axis->negative);
}
// If we have a modal frame, it prevents input from passing through it to frames below
if (frame->modal) { // modal frame blocks all inputs below it
break;
}
}
// Group all chords with the same number of modifiers together, in descending order.
std::sort(m_chords.begin(), m_chords.end(), [](const InputBindings::KeyChord *a, const InputBindings::KeyChord *b) { return *a < *b; });
// Reinitialize the modifier list, preserving key state.
m_modifiers.clear();
for (auto *chord : m_chords) {
m_modifiers.emplace(chord->modifier1, GetBindingState(chord->modifier1));
m_modifiers.emplace(chord->modifier2, GetBindingState(chord->modifier2));
}
}
KeyBindings::AxisBinding *Input::AddAxisBinding(std::string id, BindingGroup *group, KeyBindings::AxisBinding binding)
static int8_t keys_in_chord(InputBindings::KeyChord *chord)
{
// throw an error if we attempt to bind an axis onto an already-bound action in the same group.
if (group->bindings.count(id) && group->bindings[id] != BindingGroup::ENTRY_AXIS)
Error("Attempt to bind already-registered action %s as an axis.\n", id.c_str());
group->bindings[id] = BindingGroup::ENTRY_AXIS;
// Load from the config
std::string config_str = m_config->String(id.c_str());
if (config_str.length() > 0) binding.SetFromString(config_str);
return &(axisBindings[id] = binding);
return chord->activator.Enabled() + chord->modifier1.Enabled() + chord->modifier2.Enabled();
}
void Input::HandleSDLEvent(SDL_Event &event)
static float applyDeadzoneAndCurve(const JoystickInfo::Axis &axis, float value)
{
float absVal = std::fabs(value);
float sign = value < 0.0 ? 1.0 : -1.0;
if (absVal < axis.deadzone) return 0.0f;
// renormalize value to 0..1 after deadzone
absVal = (absVal - axis.deadzone) * (1.0 / (1.0 - axis.deadzone));
return AnimationCurves::SmoothEasing(absVal, axis.curve) * sign;
}
void Manager::HandleSDLEvent(SDL_Event &event)
{
using namespace InputBindings;
switch (event.type) {
case SDL_KEYDOWN:
// Set key state to "just pressed"
@ -179,146 +566,139 @@ void Input::HandleSDLEvent(SDL_Event &event)
mouseMotion[0] += event.motion.xrel;
mouseMotion[1] += event.motion.yrel;
break;
case SDL_JOYAXISMOTION:
if (!joysticks[event.jaxis.which].joystick)
case SDL_JOYAXISMOTION: {
if (!GetJoysticks()[event.jaxis.which].joystick)
break;
if (event.jaxis.value == -32768)
joysticks[event.jaxis.which].axes[event.jaxis.axis] = 1.f;
auto &axis = GetJoysticks()[event.jaxis.which].axes[event.jaxis.axis];
if (axis.zeroToOne)
// assume -32768 == 0.0 in half-axis mode (this is true for most controllers)
axis.value = applyDeadzoneAndCurve(axis, (event.jaxis.value + 32768) / 65535.f);
else
joysticks[event.jaxis.which].axes[event.jaxis.axis] = -event.jaxis.value / 32767.f;
break;
axis.value = applyDeadzoneAndCurve(axis, (event.jaxis.value == -32768 ? -1.f : event.jaxis.value / 32767.f));
} break;
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
if (!joysticks[event.jaxis.which].joystick)
if (!GetJoysticks()[event.jaxis.which].joystick)
break;
joysticks[event.jbutton.which].buttons[event.jbutton.button] = event.jbutton.state != 0;
GetJoysticks()[event.jbutton.which].buttons[event.jbutton.button] = event.jbutton.state != 0;
break;
case SDL_JOYHATMOTION:
if (!joysticks[event.jaxis.which].joystick)
if (!GetJoysticks()[event.jaxis.which].joystick)
break;
joysticks[event.jhat.which].hats[event.jhat.hat] = event.jhat.value;
GetJoysticks()[event.jhat.which].hats[event.jhat.hat] = event.jhat.value;
break;
default:
// Don't process non-input events any further.
return;
}
for (auto it = inputFrames.rbegin(); it != inputFrames.rend(); it++) {
auto *inputFrame = *it;
auto resp = inputFrame->ProcessSDLEvent(event);
if (resp == RESPONSE_MATCHED) break;
// if bindings are disabled, don't process the event any further
if (!m_enableBindings)
return;
// Update the modifier status from this event
for (auto &pair : m_modifiers) {
auto r = pair.first.Matches(event);
if (r != Response::Ignored) {
pair.second = r == Response::Pressed ? true : false;
}
}
}
void Input::InitJoysticks()
{
SDL_Init(SDL_INIT_JOYSTICK);
int joy_count = SDL_NumJoysticks();
Output("Initializing joystick subsystem.\n");
for (int n = 0; n < joy_count; n++) {
JoystickState state;
state.joystick = SDL_JoystickOpen(n);
if (!state.joystick) {
Warning("SDL_JoystickOpen(%i): %s\n", n, SDL_GetError());
// If the event matches one of the key chords we care about, update that chord
int num_keys_in_chord = 0;
for (auto *chord : m_chords) {
Response activator = chord->activator.Matches(event);
if (activator == Response::Ignored)
continue;
}
state.guid = SDL_JoystickGetGUID(state.joystick);
state.axes.resize(SDL_JoystickNumAxes(state.joystick));
state.buttons.resize(SDL_JoystickNumButtons(state.joystick));
state.hats.resize(SDL_JoystickNumHats(state.joystick));
if (chord->IsActive()) {
// Another press event came in for a key that's currently pressed right now.
// This should be sufficiently rare that it won't be happening.
if (activator == Response::Pressed)
break;
else { // clear the active state, continue processing the release event
chord->m_active = false;
// in case of a press-release sequence in the same frame, make sure to properly send updates.
chord->m_queuedEvents |= 2;
}
} else {
// Key-release event for a non-active chord. Don't handle it, but pass it on so
// another key chord (with fewer / different modifiers) can handle it.
if (activator == Response::Released)
continue;
std::array<char, 33> joystickGUIDName;
SDL_JoystickGetGUIDString(state.guid, joystickGUIDName.data(), joystickGUIDName.size());
Output("Found joystick '%s' (GUID: %s)\n", SDL_JoystickName(state.joystick), joystickGUIDName.data());
Output(" - %ld axes, %ld buttons, %ld hats\n", state.axes.size(), state.buttons.size(), state.hats.size());
// Break here to prevent CTRL+ALT+X from activating <CTRL>+X / <ALT>+X / <NONE>+X
// when there's a CTRL+ALT+X binding
if (keys_in_chord(chord) < num_keys_in_chord)
break;
SDL_JoystickID joyID = SDL_JoystickInstanceID(state.joystick);
joysticks[joyID] = state;
}
}
std::string Input::JoystickName(int joystick)
{
return std::string(SDL_JoystickName(joysticks[joystick].joystick));
}
std::string Input::JoystickGUIDString(int joystick)
{
const int guidBufferLen = 33; // as documented by SDL
char guidBuffer[guidBufferLen];
SDL_JoystickGetGUIDString(joysticks[joystick].guid, guidBuffer, guidBufferLen);
return std::string(guidBuffer);
}
// conveniance version of JoystickFromGUID below that handles the string mangling.
int Input::JoystickFromGUIDString(const std::string &guid)
{
return JoystickFromGUIDString(guid.c_str());
}
// conveniance version of JoystickFromGUID below that handles the string mangling.
int Input::JoystickFromGUIDString(const char *guid)
{
return JoystickFromGUID(SDL_JoystickGetGUIDFromString(guid));
}
// return the internal ID of the stated joystick guid.
// returns -1 if we couldn't find the joystick in question.
int Input::JoystickFromGUID(SDL_JoystickGUID guid)
{
const int guidLength = 16; // as defined
for (std::map<SDL_JoystickID, JoystickState>::iterator stick = joysticks.begin(); stick != joysticks.end(); ++stick) {
JoystickState &state = stick->second;
if (0 == memcmp(state.guid.data, guid.data, guidLength)) {
return static_cast<int>(stick->first);
bool mod1 = chord->modifier1.Enabled() ? m_modifiers[chord->modifier1] : true;
bool mod2 = chord->modifier2.Enabled() ? m_modifiers[chord->modifier2] : true;
if (mod1 && mod2) {
// Modifiers are pressed, we can activate the chord.
chord->m_active = true;
// in the case of a press-release in the same frame, make sure to properly send updates
chord->m_queuedEvents |= 1;
// all copies of this chord should be notified, but don't propagate to chords with fewer modifiers
num_keys_in_chord = keys_in_chord(chord);
}
}
}
return -1;
}
SDL_JoystickGUID Input::JoystickGUID(int joystick)
void Manager::DispatchEvents()
{
return joysticks[joystick].guid;
// Chords which have had their modifier keys released this frame get updated all at once
for (auto *chord : m_chords) {
if (chord->IsActive() && !GetModifierState(chord)) {
chord->m_active = false;
chord->m_queuedEvents |= 2;
}
}
for (auto *action : m_activeActions) {
// if we have queued events for this binding, make sure to
uint8_t queued = action->binding.m_queuedEvents | action->binding2.m_queuedEvents;
if (queued) {
bool wasActive = action->m_active;
action->m_active = action->binding.IsActive() || action->binding2.IsActive();
// if at least one of the bindings was pressed this frame and the action was not
// previously active, call the pressed event
if (queued & 1 && !wasActive)
action->onPressed.emit();
// if at least one of the bindings was released this frame but are not pressed currently,
// call the released event
if (queued & 2 && !action->m_active)
action->onReleased.emit();
// clear queued events
action->binding.m_queuedEvents = action->binding2.m_queuedEvents = 0;
}
}
for (auto *axis : m_activeAxes) {
float value = GetAxisState(axis->axis);
value += axis->positive.IsActive();
value -= axis->negative.IsActive();
value = Clamp(value, -1.0f, 1.0f);
if (value != 0.0 || axis->m_value != 0.0) {
axis->m_value = value;
axis->onAxisValue.emit(value);
}
}
}
int Input::JoystickButtonState(int joystick, int button)
{
if (!joystickEnabled) return 0;
if (joystick < 0 || joystick >= int(joysticks.size()))
return 0;
/*
if (button < 0 || button >= int(joysticks[joystick].buttons.size()))
return 0;
INPUT DEVICE MANAGEMENT ROUTINES
return joysticks[joystick].buttons[button];
}
*/
int Input::JoystickHatState(int joystick, int hat)
{
if (!joystickEnabled) return 0;
if (joystick < 0 || joystick >= int(joysticks.size()))
return 0;
if (hat < 0 || hat >= int(joysticks[joystick].hats.size()))
return 0;
return joysticks[joystick].hats[hat];
}
float Input::JoystickAxisState(int joystick, int axis)
{
if (!joystickEnabled) return 0;
if (joystick < 0 || joystick >= int(joysticks.size()))
return 0;
if (axis < 0 || axis >= int(joysticks[joystick].axes.size()))
return 0;
return joysticks[joystick].axes[axis];
}
void Input::SetCapturingMouse(bool grabbed)
void Manager::SetCapturingMouse(bool grabbed)
{
// early-out to avoid changing (possibly) expensive WM state
if (grabbed == m_capturingMouse)

View File

@ -4,7 +4,7 @@
#ifndef INPUT_H
#define INPUT_H
#include "KeyBindings.h"
#include "InputBindings.h"
#include "utils.h"
#include <algorithm>
@ -12,17 +12,23 @@
class IniConfig;
class Input {
public:
Input(IniConfig *config);
void InitGame();
void HandleSDLEvent(SDL_Event &ev);
void NewFrame();
// Macro to simplify registering input bindings in the codebase
// TODO: evaluate if registering key bindings via lua / json file works better
#define REGISTER_INPUT_BINDING(name) \
namespace name##Input \
{ \
void Register(Input::Manager *input); \
bool name##Registered = Input::AddBindingRegistrar(&Register); \
} \
void name##Input::Register(Input::Manager *input)
namespace Input {
class Manager;
// The Page->Group->Binding system serves as a thin veneer for the UI to make
// sane reasonings about how to structure the Options dialog.
struct BindingGroup {
enum EntryType {
enum EntryType : uint8_t {
ENTRY_ACTION,
ENTRY_AXIS
};
@ -36,28 +42,99 @@ public:
std::map<std::string, BindingGroup> groups;
};
BindingPage *GetBindingPage(std::string id) { return &bindingPages[id]; }
std::map<std::string, BindingPage> GetBindingPages() { return bindingPages; }
struct InputFrame {
std::vector<KeyBindings::ActionBinding *> actions;
std::vector<KeyBindings::AxisBinding *> axes;
using Axis = InputBindings::Axis;
using Action = InputBindings::Action;
bool active;
InputFrame(Input::Manager *man, bool modal = false) :
manager(man),
modal(modal)
{}
std::vector<Action *> actions;
std::vector<Axis *> axes;
// Must set this to a valid Input::Manager instance before using AddAction / AddAxis
Manager *manager = nullptr;
bool active = false;
bool modal = false;
// Call this at startup to register all the bindings associated with the frame.
virtual void RegisterBindings(){};
// Called when the frame is added to the stack.
virtual void onFrameAdded(){};
sigc::signal<void(InputFrame *)> onFrameAdded;
// Called when the frame is removed from the stack.
virtual void onFrameRemoved(){};
sigc::signal<void(InputFrame *)> onFrameRemoved;
// Check the event against all the inputs in this frame.
InputResponse ProcessSDLEvent(SDL_Event &event);
Action *AddAction(std::string id);
Axis *AddAxis(std::string id);
};
struct JoystickInfo {
struct Axis {
float value = 0.0;
float deadzone = 0.0;
float curve = 1.0;
bool zeroToOne = false;
};
SDL_Joystick *joystick;
SDL_JoystickGUID guid;
std::string name;
std::vector<bool> buttons;
std::vector<int> hats;
std::vector<Axis> axes;
};
void InitJoysticks(IniConfig *config);
std::map<SDL_JoystickID, JoystickInfo> &GetJoysticks();
// User display name for the joystick from the API/OS.
std::string JoystickName(int joystick);
// fetch the GUID for the named joystick
SDL_JoystickGUID JoystickGUID(int joystick);
std::string JoystickGUIDString(int joystick);
// reverse map a JoystickGUID to the actual internal ID.
int JoystickFromGUIDString(const std::string &guid);
int JoystickFromGUIDString(const char *guid);
int JoystickFromGUID(SDL_JoystickGUID guid);
// We use SDL's joystick IDs because they're stable enough for the job.
inline int JoystickFromID(SDL_JoystickID id) { return id; }
// An adapter to decouple input frame creation from input binding registration.
// The functions registered via AddBindingRegistrar should be thread-safe and
// should not depend on anything but the manager object being passed in.
// The registrars are guaranteed to be called after static initialization has finished.
std::vector<sigc::slot<void(Input::Manager *)>> &GetBindingRegistration();
bool AddBindingRegistrar(sigc::slot<void(Input::Manager *)> &&fn);
} // namespace Input
class Input::Manager {
public:
Manager(IniConfig *config);
void InitGame();
// Call this at the start of a frame, before passing SDL events in
void NewFrame();
// Call once per SDL event, handles updating all internal state
void HandleSDLEvent(SDL_Event &ev);
// Call immediately after processing events, dispatches events to Action / Axis bindings.
void DispatchEvents();
// When enable is false, this prevents the input system from writing to the config file.
void EnableConfigSaving(bool enable) { m_enableConfigSaving = enable; }
BindingPage *GetBindingPage(std::string id) { return &bindingPages[id]; }
std::map<std::string, BindingPage> GetBindingPages() { return bindingPages; }
// Pushes an InputFrame onto the input stack.
bool PushInputFrame(InputFrame *frame);
@ -65,32 +142,33 @@ public:
InputFrame *PopInputFrame();
// Get a read-only list of input frames.
const std::vector<InputFrame *> &GetInputFrames() { return inputFrames; }
const std::vector<InputFrame *> &GetInputFrames() { return m_inputFrames; }
// Check if a specific input frame is currently on the stack.
bool HasInputFrame(InputFrame *frame)
{
return std::count(inputFrames.begin(), inputFrames.end(), frame) > 0;
return std::count(m_inputFrames.begin(), m_inputFrames.end(), frame) > 0;
}
// Remove an arbitrary input frame from the input stack.
void RemoveInputFrame(InputFrame *frame);
// Inform the input system that a binding or frame was changed this frame.
void MarkBindingsDirty() { m_frameListChanged = true; }
// Creates a new action binding, copying the provided binding.
// The returned binding pointer points to the actual binding.
KeyBindings::ActionBinding *AddActionBinding(std::string id, BindingGroup *group, KeyBindings::ActionBinding binding);
KeyBindings::ActionBinding *GetActionBinding(std::string id)
{
return actionBindings.count(id) ? &actionBindings[id] : nullptr;
}
InputBindings::Action *AddActionBinding(std::string id, BindingGroup *group, InputBindings::Action &&binding);
InputBindings::Action *GetActionBinding(std::string id);
// Creates a new axis binding, copying the provided binding.
// The returned binding pointer points to the actual binding.
KeyBindings::AxisBinding *AddAxisBinding(std::string id, BindingGroup *group, KeyBindings::AxisBinding binding);
KeyBindings::AxisBinding *GetAxisBinding(std::string id)
{
return axisBindings.count(id) ? &axisBindings[id] : nullptr;
}
InputBindings::Axis *AddAxisBinding(std::string id, BindingGroup *group, InputBindings::Axis &&binding);
InputBindings::Axis *GetAxisBinding(std::string id);
// Call EnableBindings() to temporarily disable handling input bindings while
// you're recording a new input binding or are in a modal window.
void EnableBindings(bool enabled) { m_enableBindings = enabled; }
bool KeyState(SDL_Keycode k) { return IsKeyDown(k); }
@ -110,30 +188,10 @@ public:
float JoystickAxisState(int joystick, int axis);
bool IsJoystickEnabled() { return joystickEnabled; }
void SetJoystickEnabled(bool state) { joystickEnabled = state; }
void SetJoystickEnabled(bool state);
struct JoystickState {
SDL_Joystick *joystick;
SDL_JoystickGUID guid;
std::vector<bool> buttons;
std::vector<int> hats;
std::vector<float> axes;
};
std::map<SDL_JoystickID, JoystickState> GetJoysticksState() { return joysticks; }
// User display name for the joystick from the API/OS.
std::string JoystickName(int joystick);
// fetch the GUID for the named joystick
SDL_JoystickGUID JoystickGUID(int joystick);
std::string JoystickGUIDString(int joystick);
// reverse map a JoystickGUID to the actual internal ID.
int JoystickFromGUIDString(const std::string &guid);
int JoystickFromGUIDString(const char *guid);
int JoystickFromGUID(SDL_JoystickGUID guid);
void SetMouseYInvert(bool state) { mouseYInvert = state; }
bool IsMouseYInvert() { return mouseYInvert; }
void SetMouseYInvert(bool state);
int MouseButtonState(int button) { return mouseButton[button]; }
void SetMouseButtonState(int button, bool state) { mouseButton[button] = state; }
@ -162,9 +220,13 @@ public:
sigc::signal<void, bool> onMouseWheel;
private:
void InitJoysticks();
void RebuildInputFrames();
bool GetModifierState(InputBindings::KeyChord *key);
bool GetBindingState(InputBindings::KeyBinding &key);
float GetAxisState(InputBindings::JoyAxis &axis);
IniConfig *m_config;
bool m_enableConfigSaving;
std::map<SDL_Keycode, uint8_t> keyState;
int keyModState;
@ -175,13 +237,20 @@ private:
bool joystickEnabled;
bool mouseYInvert;
std::map<SDL_JoystickID, JoystickState> joysticks;
std::map<std::string, BindingPage> bindingPages;
std::map<std::string, KeyBindings::ActionBinding> actionBindings;
std::map<std::string, KeyBindings::AxisBinding> axisBindings;
std::map<std::string, InputBindings::Action> actionBindings;
std::map<std::string, InputBindings::Axis> axisBindings;
bool m_enableBindings;
std::vector<InputFrame *> inputFrames;
std::vector<InputFrame *> m_inputFrames;
bool m_frameListChanged;
std::vector<InputBindings::Action *> m_activeActions;
std::vector<InputBindings::Axis *> m_activeAxes;
std::map<InputBindings::KeyBinding, bool> m_modifiers;
std::vector<InputBindings::KeyChord *> m_chords;
};
#endif

380
src/InputBindings.cpp Normal file
View File

@ -0,0 +1,380 @@
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#include "InputBindings.h"
#include "Input.h"
#include "SDL_events.h"
#include "SDL_joystick.h"
#include "utils.h"
#include <regex>
using namespace InputBindings;
namespace Input {
int JoystickFromGUIDString(const std::string &guid);
std::string JoystickGUIDString(int joystickID);
} // namespace Input
// Helper function to early-out in Matches()
Response MatchType(const KeyBinding &k, const SDL_Event &ev)
{
using Type = KeyBinding::Type;
bool p = false;
bool r = false;
switch (k.type) {
case Type::Disabled:
return Response::Ignored;
case Type::KeyboardKey:
p = ev.type == SDL_KEYDOWN;
r = ev.type == SDL_KEYUP;
break;
case Type::JoystickButton:
p = ev.type == SDL_JOYBUTTONDOWN;
r = ev.type == SDL_JOYBUTTONUP;
break;
case Type::JoystickHat:
if (ev.type == SDL_JOYHATMOTION) {
p = (ev.jhat.value & k.joystick.button) == k.joystick.button;
r = !p;
}
break;
case Type::MouseButton:
p = ev.type == SDL_MOUSEBUTTONDOWN;
r = ev.type == SDL_MOUSEBUTTONUP;
break;
}
return p ? Response::Pressed : r ? Response::Released : Response::Ignored;
}
Response KeyBinding::Matches(const SDL_Event &ev) const
{
Response r = MatchType(*this, ev);
if (r == Response::Ignored)
return r;
if (type == Type::KeyboardKey) {
return (ev.key.keysym.sym == keycode) ? r : Response::Ignored;
} else if (type == Type::JoystickButton) {
bool cond = (joystick.id == ev.jbutton.which && joystick.button == ev.jbutton.button);
return cond ? r : Response::Ignored;
} else if (type == Type::JoystickHat) {
bool cond = (joystick.id == ev.jhat.which && joystick.hat == ev.jhat.hat);
return cond ? r : Response::Ignored;
} else if (type == Type::MouseButton) {
return (mouse.button == ev.button.button) ? r : Response::Ignored;
}
return Response::Ignored;
}
bool KeyBinding::operator==(const KeyBinding &rhs) const
{
if (type != rhs.type)
return false;
if (type == Type::KeyboardKey)
return keycode == rhs.keycode;
else if (type == Type::JoystickButton)
return joystick.id == rhs.joystick.id && joystick.button == rhs.joystick.button;
else if (type == Type::JoystickHat)
return joystick.id == rhs.joystick.id && joystick.hat == rhs.joystick.hat && joystick.button == rhs.joystick.button;
else if (type == Type::MouseButton)
return mouse.button == rhs.mouse.button;
else
return true;
}
#define ret_if_different(val) \
if (val != rhs.val) return val < rhs.val
bool KeyBinding::operator<(const KeyBinding &rhs) const
{
ret_if_different(type);
switch (type) {
case Type::KeyboardKey:
ret_if_different(keycode);
break;
case Type::JoystickButton:
ret_if_different(joystick.id);
ret_if_different(joystick.button);
break;
case Type::JoystickHat:
ret_if_different(joystick.id);
ret_if_different(joystick.hat);
ret_if_different(joystick.button);
break;
case Type::MouseButton:
ret_if_different(mouse.button);
break;
default:
break;
}
return this < &rhs;
}
#undef ret_if_different
Action &Action::operator=(const Action &rhs)
{
binding = rhs.binding;
binding2 = rhs.binding2;
return *this;
}
Axis &Axis::operator=(const Axis &rhs)
{
axis = rhs.axis;
positive = rhs.positive;
negative = rhs.negative;
return *this;
}
// ============================================================================
//
// Config Loading
//
// ============================================================================
using smatch = std::match_results<nonstd::string_view::const_iterator>;
static std::regex disabled_matcher("^disabled", std::regex::icase);
// Handle the fiddly bits of matching a regex and advancing the beginning of a string
bool consumeMatch(nonstd::string_view &str, smatch &match_results, std::regex &reg)
{
if (!std::regex_search(str.cbegin(), str.cend(), match_results, reg))
return false;
str.remove_prefix(std::distance(str.cbegin(), match_results[0].second));
return true;
}
// Key54 | JoyGUID/B3 JoyGUID/H4/2 | Mouse5
// Less awful than iostreams, but still not elegant. That's C++ for you.
// TODO: save joystick id->GUID mapping separately in the config file and
// don't write them here to save space
nonstd::string_view &InputBindings::operator>>(nonstd::string_view &str, KeyBinding &out)
{
static std::regex key_matcher("^Key(\\d+)");
static std::regex joystick_matcher("^Joy([^/]{32})");
static std::regex joystick_button("^/B(\\d+)");
static std::regex joystick_hat("^/H(\\d+)/(\\d+)");
static std::regex mouse_matcher("^Mouse(\\d+)");
const auto begin = str.cbegin();
const auto end = str.cend();
// match_results[0].second should always point to the character after the
// parsed key binding unless the value present could not be parsed.
smatch match_results;
if (std::regex_search(begin, end, match_results, key_matcher)) {
out.type = KeyBinding::Type::KeyboardKey;
out.keycode = std::stoi(match_results[1]);
} else if (std::regex_search(begin, end, match_results, joystick_matcher)) {
out.joystick.id = Input::JoystickFromGUIDString(match_results[1]);
const auto start = match_results[0].second;
if (std::regex_search(start, end, match_results, joystick_button)) {
out.type = KeyBinding::Type::JoystickButton;
out.joystick.button = std::stoi(match_results[1]);
out.joystick.hat = 0;
} else if (std::regex_search(start, end, match_results, joystick_hat)) {
out.type = KeyBinding::Type::JoystickHat;
out.joystick.hat = std::stoi(match_results[1]);
out.joystick.button = std::stoi(match_results[2]);
}
} else if (std::regex_search(begin, end, match_results, mouse_matcher)) {
out.type = KeyBinding::Type::MouseButton;
out.mouse.button = std::stoi(match_results[1]);
} else {
out.type = KeyBinding::Type::Disabled;
// consume the disabled text if present.
std::regex_search(begin, end, match_results, disabled_matcher);
}
// return a string view containing the rest of the string
if (!match_results.empty())
str.remove_prefix(std::distance(begin, match_results[0].second));
return str;
}
// Serialize a KeyBinding into the output stream.
// Writes nothing if the binding is disabled
std::ostream &InputBindings::operator<<(std::ostream &str, KeyBinding &in)
{
switch (in.type) {
case KeyBinding::Type::KeyboardKey:
return str << "Key" << in.keycode;
case KeyBinding::Type::JoystickButton:
return str << "Joy" << Input::JoystickGUIDString(in.joystick.id)
<< "/B" << int(in.joystick.button);
case KeyBinding::Type::JoystickHat:
return str << "Joy" << Input::JoystickGUIDString(in.joystick.id)
<< "/H" << int(in.joystick.hat) << "/" << int(in.joystick.button);
case KeyBinding::Type::MouseButton:
return str << "Mouse" << int(in.mouse.button);
default:
return str;
}
}
// Match [-]JoyGUID/A4
nonstd::string_view &InputBindings::operator>>(nonstd::string_view &str, JoyAxis &out)
{
static std::regex joy_matcher("^Joy([^/]{32})/A(\\d+)");
auto begin = str.cbegin();
bool reverse = !str.empty() && str[0] == '-';
if (reverse)
++begin;
smatch match_results;
if (std::regex_search(begin, str.cend(), match_results, joy_matcher)) {
out.joystickId = Input::JoystickFromGUIDString(match_results[1]);
out.axis = std::stoi(match_results[2]);
out.direction = reverse ? -1 : 1;
} else {
std::regex_search(str.cbegin(), str.cend(), match_results, std::regex("^disabled"));
out.direction = 0;
}
if (!match_results.empty())
str.remove_prefix(std::distance(str.cbegin(), match_results[0].second));
return str;
}
// [-]JoyGUID/A4
std::ostream &InputBindings::operator<<(std::ostream &str, JoyAxis &in)
{
if (!in.Enabled())
return str << "disabled";
return str << (in.direction < 0.0 ? "-Joy" : "Joy")
<< Input::JoystickGUIDString(in.joystickId)
<< "/A" << int(in.axis);
}
// find a close paren, copy str into ret str, and return retstr
// (for one-line failure case returns)
nonstd::string_view &findCloseParen(nonstd::string_view &str, nonstd::string_view &retstr, smatch &match_results)
{
if (std::regex_search(str.cbegin(), str.cend(), match_results, std::regex("\\)")))
str.remove_prefix(std::distance(str.cbegin(), match_results[0].second));
retstr = str;
return retstr;
}
// Parse KeyChord(Key53 + JoyGUID/B3 + Mouse1) | KeyChord(Mouse5)
nonstd::string_view &InputBindings::operator>>(nonstd::string_view &str, KeyChord &out)
{
static std::regex key_chord("^KeyChord\\(\\s*");
static std::regex plus_sign("^\\s*\\+\\s*");
smatch match_results;
// Early-out for disabled key chord
if (consumeMatch(str, match_results, disabled_matcher))
return str;
// make a copy of the string view so we can nondestructively consume matches.
nonstd::string_view iterstr = str;
// ensure we read the KeyChord( opening
if (!consumeMatch(iterstr, match_results, key_chord))
return str;
// read the activator KeyBinding
iterstr >> out.activator;
// if the activator is disabled, early-out here.
// if we don't have a following plus sign, discard everything to the next close-paren
if (!out.activator.Enabled() || !consumeMatch(iterstr, match_results, plus_sign))
return findCloseParen(iterstr, str, match_results);
// read the first modifier
iterstr >> out.modifier1;
// ditto for the second modifier
if (!out.modifier1.Enabled() || !consumeMatch(iterstr, match_results, plus_sign))
return findCloseParen(iterstr, str, match_results);
iterstr >> out.modifier2;
return findCloseParen(iterstr, str, match_results);
}
// KeyChord(Key54 + JoyGUID/B4 + JoyGUID/H1/3)
std::ostream &InputBindings::operator<<(std::ostream &str, KeyChord &in)
{
if (!in.Enabled())
return str << "disabled";
str << "KeyChord(" << in.activator;
if (in.modifier1.Enabled()) {
str << " + " << in.modifier1;
if (in.modifier2.Enabled())
str << " + " << in.modifier2;
}
str << ")";
return str;
}
nonstd::string_view &InputBindings::operator>>(nonstd::string_view &str, Axis &out)
{
static std::regex input_axis("^InputAxis\\(\\s*");
static std::regex comma_sep("^\\s*,\\s*");
smatch match_results;
auto iterstr = str;
if (!consumeMatch(iterstr, match_results, input_axis))
return str;
iterstr >> out.axis;
if (!consumeMatch(iterstr, match_results, comma_sep))
return findCloseParen(iterstr, str, match_results);
iterstr >> out.negative;
if (!consumeMatch(iterstr, match_results, comma_sep))
return findCloseParen(iterstr, str, match_results);
iterstr >> out.positive;
return findCloseParen(iterstr, str, match_results);
}
// InputAxis(-JoyGUID/A3, KeyChord(Key32), KeyChord(Mouse5 + JoyGUID/H1/1))
// InputAxis(disabled, disabled, disabled)
std::ostream &InputBindings::operator<<(std::ostream &str, Axis &in)
{
return str << "InputAxis(" << in.axis << ", " << in.negative << ", " << in.positive << ")";
}
nonstd::string_view &InputBindings::operator>>(nonstd::string_view &str, Action &out)
{
static std::regex input_action("^InputAction\\(\\s*");
static std::regex comma_sep("^\\s*,\\s*");
smatch match_results;
auto iterstr = str;
if (!consumeMatch(iterstr, match_results, input_action))
return str;
iterstr >> out.binding;
if (!consumeMatch(iterstr, match_results, comma_sep))
return findCloseParen(iterstr, str, match_results);
iterstr >> out.binding2;
return findCloseParen(iterstr, str, match_results);
}
// InputAction(KeyChord(Key53 + Mouse4), KeyChord(Mouse5 + JoyGUID/H1/1))
// InputAction(disabled, disabled)
std::ostream &InputBindings::operator<<(std::ostream &str, Action &in)
{
return str << "InputAction(" << in.binding << ", " << in.binding2 << ")";
}

216
src/InputBindings.h Normal file
View File

@ -0,0 +1,216 @@
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#pragma once
#include "DeleteEmitter.h"
#include "nonstd/string_view.hpp"
#include <SDL_events.h>
#include <SDL_keycode.h>
#include <sigc++/sigc++.h>
#include <cstdint>
#include <iostream>
namespace InputBindings {
enum class Response {
Ignored = 0,
Pressed,
Released
};
struct KeyBinding {
enum class Type : uint8_t {
Disabled,
KeyboardKey,
JoystickButton,
JoystickHat,
MouseButton
};
Type type = Type::Disabled;
union {
SDL_Keycode keycode = 0;
struct {
// 65536 possible IDs should be more than plenty, even with lots of hot-plug noise.
uint16_t id;
// if type = JoystickHat, this is the hat direction; otherwise it's the button index
uint8_t button;
uint8_t hat;
} joystick;
struct {
uint8_t button;
} mouse;
};
KeyBinding() = default;
KeyBinding(SDL_Keycode k) :
type(Type::KeyboardKey), keycode(k) {}
static KeyBinding JoystickButton(uint8_t joystickID, uint8_t button)
{
KeyBinding t;
t.type = Type::JoystickButton;
t.joystick = { joystickID, button, 0 };
return t;
}
static KeyBinding JoystickHat(uint8_t joystickID, uint8_t hat, uint8_t direction)
{
KeyBinding t;
t.type = Type::JoystickHat;
t.joystick = { joystickID, direction, hat };
return t;
}
static KeyBinding MouseButton(uint8_t mouseButton)
{
KeyBinding t;
t.type = Type::MouseButton;
t.mouse.button = mouseButton;
return t;
}
static KeyBinding FromEvent(SDL_Event &event);
bool Enabled() const { return type != Type::Disabled; }
Response Matches(const SDL_Event &ev) const;
bool operator==(const KeyBinding &rhs) const;
bool operator<(const KeyBinding &rhs) const;
// serialization
friend nonstd::string_view &operator>>(nonstd::string_view &, KeyBinding &);
friend std::ostream &operator<<(std::ostream &, KeyBinding &);
};
struct JoyAxis {
uint8_t joystickId;
uint8_t axis;
int8_t direction; // if 0, the axis is disabled
bool Enabled() const { return direction != 0; }
bool operator==(const JoyAxis &rhs) const
{
if (!direction && !rhs.direction)
return true;
return joystickId == rhs.joystickId && axis == rhs.axis && direction == rhs.direction;
}
// serialization
friend nonstd::string_view &operator>>(nonstd::string_view &, JoyAxis &);
friend std::ostream &operator<<(std::ostream &, JoyAxis &);
};
struct KeyChord {
KeyBinding activator;
KeyBinding modifier1;
KeyBinding modifier2;
KeyChord() = default;
KeyChord(KeyBinding a, KeyBinding m1 = {}, KeyBinding m2 = {}) :
activator(a),
modifier1(m1),
modifier2(m2)
{}
bool IsActive() const { return Enabled() && m_active; }
bool Enabled() const { return activator.Enabled(); }
bool operator==(const KeyChord &rhs) const
{
return activator == rhs.activator && modifier1 == rhs.modifier1 && modifier2 == rhs.modifier2;
}
bool operator!=(const KeyChord &rhs) const { return !(*this == rhs); }
// Groups chords by number of modifiers in descending order
bool operator<(const KeyChord &rhs) const
{
return (modifier2.Enabled() && !rhs.modifier2.Enabled()) || (modifier1.Enabled() && !rhs.modifier2.Enabled());
}
bool m_active = false;
uint8_t m_queuedEvents = 0;
// serialization
friend nonstd::string_view &operator>>(nonstd::string_view &, KeyChord &);
friend std::ostream &operator<<(std::ostream &, KeyChord &);
};
struct Action : public DeleteEmitter {
KeyChord binding;
KeyChord binding2;
Action() = default;
Action(KeyChord b1, KeyChord b2 = {}) :
binding(b1),
binding2(b2)
{}
// NOTE: sigc::signals cannot be copied, this function is for convenience to copy bindings only
Action &operator=(const Action &rhs);
bool IsActive() { return m_active; }
bool Enabled() { return binding.Enabled() || binding2.Enabled(); }
bool m_active = false;
sigc::signal<void> onPressed;
sigc::signal<void> onReleased;
// serialization
friend nonstd::string_view &operator>>(nonstd::string_view &, Action &);
friend std::ostream &operator<<(std::ostream &, Action &);
};
struct Axis : public DeleteEmitter {
JoyAxis axis;
KeyChord positive;
KeyChord negative;
Axis() = default;
Axis(JoyAxis a, KeyChord p = {}, KeyChord n = {}) :
axis(a),
positive(p),
negative(n)
{}
Axis(KeyChord p, KeyChord n = {}) :
axis{},
positive(p),
negative(n)
{}
// NOTE: sigc::signals cannot be copied, this function is for convenience to copy bindings only
Axis &operator=(const Axis &rhs);
bool IsActive() { return m_value != 0.0 || positive.IsActive() || negative.IsActive(); }
float GetValue() { return m_value; }
bool Enabled() { return axis.Enabled() || positive.Enabled() || negative.Enabled(); }
float m_value;
sigc::signal<void(float)> onAxisValue;
// serialization
friend nonstd::string_view &operator>>(nonstd::string_view &, Axis &);
friend std::ostream &operator<<(std::ostream &, Axis &);
};
nonstd::string_view &operator>>(nonstd::string_view &, KeyBinding &);
std::ostream &operator<<(std::ostream &, KeyBinding &);
nonstd::string_view &operator>>(nonstd::string_view &, JoyAxis &);
std::ostream &operator<<(std::ostream &, JoyAxis &);
nonstd::string_view &operator>>(nonstd::string_view &, KeyChord &);
std::ostream &operator<<(std::ostream &, KeyChord &);
nonstd::string_view &operator>>(nonstd::string_view &, Action &);
std::ostream &operator<<(std::ostream &, Action &);
nonstd::string_view &operator>>(nonstd::string_view &, Axis &);
std::ostream &operator<<(std::ostream &, Axis &);
}; // namespace InputBindings

View File

@ -1,712 +0,0 @@
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#include "KeyBindings.h"
#include "GameConfig.h"
#include "Input.h"
#include "Lang.h"
#include "Pi.h"
#include "StringF.h"
#include <sstream>
#include <string>
static bool m_disableBindings = 0;
namespace KeyBindings {
#define KEY_BINDING(name, a, b, c, d) ActionBinding name;
#define AXIS_BINDING(name, a, b, c) JoyAxisBinding name;
#include "KeyBindings.inc.h"
// create the BindingPrototype sets for use by the UI
#define BINDING_PAGE(name) const BindingPrototype BINDING_PROTOS_##name[] = {
#define BINDING_PAGE_END() \
{ \
0, 0, 0, 0 \
} \
} \
;
#define BINDING_GROUP(ui_name) \
{ ui_name, 0, 0, 0 },
#define KEY_BINDING(name, config_name, ui_name, def1, def2) \
{ ui_name, config_name, &KeyBindings::name, 0 },
#define AXIS_BINDING(name, config_name, ui_name, default_value) \
{ ui_name, config_name, 0, &KeyBindings::name },
#include "KeyBindings.inc.h"
// static binding object lists for use by the dispatch function
static ActionBinding *const s_KeyBindings[] = {
#define KEY_BINDING(name, a, b, c, d) &KeyBindings::name,
#include "KeyBindings.inc.h"
0
};
bool KeyBinding::IsActive() const
{
if (type == BINDING_DISABLED) {
return false;
} else if (type == KEYBOARD_KEY) {
if (!Pi::input->KeyState(u.keyboard.key))
return false;
if (u.keyboard.mod == KMOD_NONE)
return true;
else {
int mod = Pi::input->KeyModState();
if (mod & KMOD_CTRL) {
mod |= KMOD_CTRL;
}
if (mod & KMOD_SHIFT) {
mod |= KMOD_SHIFT;
}
if (mod & KMOD_ALT) {
mod |= KMOD_ALT;
}
if (mod & KMOD_GUI) {
mod |= KMOD_GUI;
}
return ((mod & u.keyboard.mod) == u.keyboard.mod);
}
} else if (type == JOYSTICK_BUTTON) {
return Pi::input->JoystickButtonState(u.joystickButton.joystick, u.joystickButton.button) != 0;
} else if (type == JOYSTICK_HAT) {
// SDL_HAT generates diagonal directions by ORing two cardinal directions.
int hatState = Pi::input->JoystickHatState(u.joystickHat.joystick, u.joystickHat.hat);
return (hatState & u.joystickHat.direction) == u.joystickHat.direction;
} else
abort();
return false;
}
bool KeyBinding::Matches(const SDL_Keysym *sym) const
{
int mod = sym->mod;
if (mod & KMOD_CTRL) {
mod |= KMOD_CTRL;
}
if (mod & KMOD_SHIFT) {
mod |= KMOD_SHIFT;
}
if (mod & KMOD_ALT) {
mod |= KMOD_ALT;
}
if (mod & KMOD_GUI) {
mod |= KMOD_GUI;
}
return (type == KEYBOARD_KEY) &&
(sym->sym == u.keyboard.key) &&
((mod & u.keyboard.mod) == u.keyboard.mod);
}
bool KeyBinding::Matches(const SDL_JoyButtonEvent *joy) const
{
return (type == JOYSTICK_BUTTON) &&
(joy->which == u.joystickButton.joystick) &&
(joy->button == u.joystickButton.button);
}
bool KeyBinding::Matches(const SDL_JoyHatEvent *joy) const
{
return (type == JOYSTICK_HAT) &&
(joy->which == u.joystickHat.joystick) &&
(joy->hat == u.joystickHat.hat) &&
(joy->value == u.joystickHat.direction);
}
std::string KeyBinding::Description() const
{
std::ostringstream oss;
if (type == BINDING_DISABLED) {
// blank
} else if (type == KEYBOARD_KEY) {
if (u.keyboard.mod & KMOD_SHIFT) oss << Lang::SHIFT << " + ";
if (u.keyboard.mod & KMOD_CTRL) oss << Lang::CTRL << " + ";
if (u.keyboard.mod & KMOD_ALT) oss << Lang::ALT << " + ";
if (u.keyboard.mod & KMOD_GUI) oss << Lang::META << " + ";
oss << SDL_GetKeyName(u.keyboard.key);
} else if (type == JOYSTICK_BUTTON) {
oss << Pi::input->JoystickName(u.joystickButton.joystick);
oss << Lang::BUTTON << int(u.joystickButton.button);
} else if (type == JOYSTICK_HAT) {
oss << Pi::input->JoystickName(u.joystickHat.joystick);
oss << Lang::HAT << int(u.joystickHat.hat);
oss << Lang::DIRECTION << int(u.joystickHat.direction);
} else
assert(0 && "invalid key binding type");
return oss.str();
}
/**
* In a C string pointed to by the string pointer pointed to by p, scan for
* the character token tok, copying the bytes on the way to bufOut which is at most buflen long.
*
* returns true on success, returns false if the end of the input string was reached,
* or the buffer would be overfilled without encountering the token.
*
* upon return, the pointer pointed to by p will refer to the character AFTER the tok.
*/
static bool ReadToTok(char tok, const char **p, char *bufOut, size_t buflen)
{
unsigned int idx;
for (idx = 0; idx < buflen; idx++) {
if (**p == '\0' || **p == tok) {
break;
}
bufOut[idx] = *((*p)++);
}
// if, after that, we're not pointing at the tok, we must have hit
// the terminal or run out of buffer.
if (**p != tok) {
return false;
}
// otherwise, skip over the tok.
(*p)++;
// if there is sufficient space in the buffer, NUL terminate.
if (idx < buflen) {
bufOut[idx] = '\0';
}
return true;
}
/**
* Example strings:
* Key55
* Joy{uuid}/Button2
* Joy{uuid}/Hat0Dir3
*/
bool KeyBinding::FromString(const char *str, KeyBinding &kb)
{
const char *digits = "1234567890";
const char *p = str;
if (strcmp(p, "disabled") == 0) {
kb.Clear();
} else if (strncmp(p, "Key", 3) == 0) {
kb.type = KEYBOARD_KEY;
p += 3;
kb.u.keyboard.key = SDL_Keycode(atoi(p));
p += strspn(p, digits);
if (strncmp(p, "Mod", 3) == 0) {
p += 3;
kb.u.keyboard.mod = SDL_Keymod(atoi(p));
} else {
kb.u.keyboard.mod = KMOD_NONE;
}
} else if (strncmp(p, "Joy", 3) == 0) {
p += 3;
const int JoyUUIDLength = 33;
char joyUUIDBuf[JoyUUIDLength];
// read the UUID
if (!ReadToTok('/', &p, joyUUIDBuf, JoyUUIDLength)) {
return false;
}
// force terminate
joyUUIDBuf[JoyUUIDLength - 1] = '\0';
// now, locate the internal ID.
int joy = Pi::input->JoystickFromGUIDString(joyUUIDBuf);
if (joy == -1) {
return false;
}
if (strncmp(p, "Button", 6) == 0) {
p += 6;
kb.type = JOYSTICK_BUTTON;
kb.u.joystickButton.joystick = joy;
kb.u.joystickButton.button = atoi(p);
} else if (strncmp(p, "Hat", 3) == 0) {
p += 3;
kb.type = JOYSTICK_HAT;
kb.u.joystickHat.joystick = joy;
kb.u.joystickHat.hat = atoi(p);
p += strspn(p, digits);
if (strncmp(p, "Dir", 3) != 0)
return false;
p += 3;
kb.u.joystickHat.direction = atoi(p);
} else
return false;
}
return true;
}
KeyBinding KeyBinding::FromString(const char *str)
{
KeyBinding kb;
if (!KeyBinding::FromString(str, kb))
kb.Clear();
return kb;
}
std::ostream &operator<<(std::ostream &oss, const KeyBinding &kb)
{
if (kb.type == BINDING_DISABLED) {
oss << "disabled";
} else if (kb.type == KEYBOARD_KEY) {
oss << "Key" << int(kb.u.keyboard.key);
if (kb.u.keyboard.mod != 0) {
oss << "Mod" << int(kb.u.keyboard.mod);
}
} else if (kb.type == JOYSTICK_BUTTON) {
oss << "Joy" << Pi::input->JoystickGUIDString(kb.u.joystickButton.joystick);
oss << "/Button" << int(kb.u.joystickButton.button);
} else if (kb.type == JOYSTICK_HAT) {
oss << "Joy" << Pi::input->JoystickGUIDString(kb.u.joystickButton.joystick);
oss << "/Hat" << int(kb.u.joystickHat.hat);
oss << "Dir" << int(kb.u.joystickHat.direction);
} else {
assert(0 && "KeyBinding type field is invalid");
}
return oss;
}
std::string KeyBinding::ToString() const
{
std::ostringstream oss;
oss << *this;
return oss.str();
}
KeyBinding KeyBinding::FromKeyMod(SDL_Keycode key, SDL_Keymod mod)
{
KeyBinding kb;
kb.type = KEYBOARD_KEY;
kb.u.keyboard.key = key;
// expand the modifier to cover both left & right variants
int imod = mod;
if (imod & KMOD_CTRL) {
imod |= KMOD_CTRL;
}
if (imod & KMOD_SHIFT) {
imod |= KMOD_SHIFT;
}
if (imod & KMOD_ALT) {
imod |= KMOD_ALT;
}
if (imod & KMOD_GUI) {
imod |= KMOD_GUI;
}
kb.u.keyboard.mod = static_cast<SDL_Keymod>(imod);
return kb;
}
KeyBinding KeyBinding::FromJoystickButton(Uint8 joystick, Uint8 button)
{
KeyBinding kb;
kb.type = JOYSTICK_BUTTON;
kb.u.joystickButton.joystick = joystick;
kb.u.joystickButton.button = button;
return kb;
}
KeyBinding KeyBinding::FromJoystickHat(Uint8 joystick, Uint8 hat, Uint8 direction)
{
KeyBinding kb;
kb.type = JOYSTICK_HAT;
kb.u.joystickHat.joystick = joystick;
kb.u.joystickHat.hat = hat;
kb.u.joystickHat.direction = direction;
return kb;
}
void ActionBinding::SetFromString(const char *str)
{
const size_t BUF_SIZE = 64;
const size_t len = strlen(str);
if (len >= BUF_SIZE) {
Output("invalid ActionBinding string\n");
binding1 = KeyBinding::FromString(str);
binding2.Clear();
} else {
const char *sep = strchr(str, ',');
if (sep) {
char buf[BUF_SIZE];
const size_t len1 = sep - str;
const size_t len2 = len - len1 - 1;
memcpy(buf, str, len1);
buf[len1] = '\0';
binding1 = KeyBinding::FromString(buf);
memcpy(buf, sep + 1, len2);
buf[len2] = '\0';
binding2 = KeyBinding::FromString(buf);
} else {
binding1 = KeyBinding::FromString(str);
binding2.Clear();
}
}
}
std::string ActionBinding::ToString() const
{
std::ostringstream oss;
if (binding1.Enabled() && binding2.Enabled()) {
oss << binding1 << "," << binding2;
} else if (binding1.Enabled()) {
oss << binding1;
} else if (binding2.Enabled()) {
oss << binding2;
} else {
oss << "disabled";
}
return oss.str();
}
bool ActionBinding::IsActive() const
{
return binding1.IsActive() || binding2.IsActive();
}
bool ActionBinding::Matches(const SDL_Keysym *sym) const
{
return binding1.Matches(sym) || binding2.Matches(sym);
}
InputResponse ActionBinding::CheckSDLEventAndDispatch(const SDL_Event *event)
{
if (m_disableBindings) return RESPONSE_NOMATCH;
switch (event->type) {
case SDL_KEYDOWN:
case SDL_KEYUP: {
if (Matches(&event->key.keysym)) {
if (event->key.state == SDL_PRESSED)
onPress.emit();
else if (event->key.state == SDL_RELEASED)
onRelease.emit();
return RESPONSE_MATCHED;
}
break;
}
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP: {
if (binding1.Matches(&event->jbutton) || binding2.Matches(&event->jbutton)) {
if (event->jbutton.state == SDL_PRESSED)
onPress.emit();
else if (event->jbutton.state == SDL_RELEASED)
onRelease.emit();
return RESPONSE_MATCHED;
}
break;
}
case SDL_JOYHATMOTION: {
if (binding1.Matches(&event->jhat) || binding2.Matches(&event->jhat)) {
onPress.emit();
// XXX to emit onRelease, we need to have access to the state of the joystick hat prior to this event,
// so that we can detect the case of switching from a direction that matches the binding to some other direction
return RESPONSE_MATCHED;
}
break;
}
default: break;
}
return RESPONSE_NOMATCH;
}
bool JoyAxisBinding::IsActive() const
{
// If the stick is within the deadzone, it's not active.
return fabs(Pi::input->JoystickAxisState(joystick, axis)) > deadzone;
}
float JoyAxisBinding::GetValue() const
{
if (!Enabled()) return 0.0f;
const float o_val = Pi::input->JoystickAxisState(joystick, axis);
// Deadzone with normalisation
float value = fabs(o_val);
if (value < deadzone) {
return 0.0f;
} else {
// subtract deadzone and re-normalise to full range
value = (value - deadzone) / (1.0f - deadzone);
}
// Apply sensitivity scaling and clamp.
value = fmax(fmin(value * sensitivity, 1.0f), 0.0f);
value = copysign(value, o_val);
// Invert as necessary.
return direction == POSITIVE ? value : 0.0f - value;
}
bool JoyAxisBinding::Matches(const SDL_Event *event) const
{
if (event->type != SDL_JOYAXISMOTION) return false;
return event->jaxis.which == joystick && event->jaxis.axis == axis;
}
std::string JoyAxisBinding::Description() const
{
if (!Enabled()) return std::string();
const char *axis_names[] = { Lang::X, Lang::Y, Lang::Z };
std::ostringstream ossaxisnum;
ossaxisnum << int(axis);
return stringf(Lang::JOY_AXIS,
formatarg("sign", direction == KeyBindings::NEGATIVE ? "-" : ""), // no + sign if positive
formatarg("signp", direction == KeyBindings::NEGATIVE ? "-" : "+"), // optional with + sign
formatarg("joynum", joystick),
formatarg("joyname", Pi::input->JoystickName(joystick)),
formatarg("axis", axis < 3 ? axis_names[axis] : ossaxisnum.str()));
}
bool JoyAxisBinding::FromString(const char *str, JoyAxisBinding &ab)
{
if (strcmp(str, "disabled") == 0) {
ab.Clear();
return true;
}
const char *p = str;
if (p[0] == '-') {
ab.direction = NEGATIVE;
p++;
} else
ab.direction = POSITIVE;
if (strncmp(p, "Joy", 3) != 0)
return false;
p += 3;
const int JoyUUIDLength = 33;
char joyUUIDBuf[JoyUUIDLength];
// read the UUID
if (!ReadToTok('/', &p, joyUUIDBuf, JoyUUIDLength)) {
return false;
}
// force terminate
joyUUIDBuf[JoyUUIDLength - 1] = '\0';
// now, map the GUID to a joystick number
const int joystick = Pi::input->JoystickFromGUIDString(joyUUIDBuf);
if (joystick == -1) {
return false;
}
// found a joystick
assert(joystick < 256);
ab.joystick = Uint8(joystick);
if (strncmp(p, "Axis", 4) != 0)
return false;
p += 4;
ab.axis = atoi(p);
// Skip past the axis integer
if (!(p = strstr(p, "/DZ")))
return true; // deadzone is optional
p += 3;
ab.deadzone = atof(p);
// Skip past the deadzone float
if (!(p = strstr(p, "/E")))
return true; // sensitivity is optional
p += 2;
ab.sensitivity = atof(p);
return true;
}
JoyAxisBinding JoyAxisBinding::FromString(const char *str)
{
JoyAxisBinding ab;
if (!JoyAxisBinding::FromString(str, ab))
ab.Clear();
return ab;
}
std::string JoyAxisBinding::ToString() const
{
std::ostringstream oss;
if (Enabled()) {
if (direction == NEGATIVE)
oss << '-';
oss << "Joy";
oss << Pi::input->JoystickGUIDString(joystick);
oss << "/Axis";
oss << int(axis);
oss << "/DZ" << deadzone;
oss << "/E" << sensitivity;
} else {
oss << "disabled";
}
return oss.str();
}
void AxisBinding::SetFromString(const std::string str)
{
size_t ofs = 0;
size_t nextpos = str.find(',');
if (nextpos == std::string::npos) return;
if (str.substr(ofs, 8) != "disabled")
axis = JoyAxisBinding::FromString(str.substr(0, nextpos).c_str());
ofs = nextpos + 1;
nextpos = str.find(',', ofs);
if (str.substr(ofs, 8) != "disabled")
positive = KeyBinding::FromString(str.substr(ofs, nextpos - ofs).c_str());
ofs = nextpos + 1;
if (str.substr(ofs, 8) != "disabled")
negative = KeyBinding::FromString(str.substr(ofs).c_str());
}
std::string AxisBinding::ToString() const
{
std::ostringstream oss;
oss << axis.ToString() << ',';
oss << positive.ToString() << ',';
oss << negative.ToString();
return oss.str();
}
bool AxisBinding::IsActive() const
{
return axis.IsActive() || positive.IsActive() || negative.IsActive();
}
float AxisBinding::GetValue() const
{
// Holding the positive and negative keys cancel each other out,
float value = 0.0f;
value += positive.IsActive() ? 1.0 : 0.0;
value -= negative.IsActive() ? 1.0 : 0.0;
// And input on the axis device supercedes both of them.
return axis.IsActive() ? axis.GetValue() : value;
}
InputResponse AxisBinding::CheckSDLEventAndDispatch(const SDL_Event *event)
{
if (m_disableBindings) return RESPONSE_NOMATCH;
float value = GetValue();
switch (event->type) {
case SDL_KEYDOWN:
case SDL_KEYUP: {
if (positive.Matches(&event->key.keysym) && negative.Matches(&event->key.keysym)) {
onAxis.emit(value);
return RESPONSE_MATCHED;
}
break;
}
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP: {
if (positive.Matches(&event->jbutton) || negative.Matches(&event->jbutton)) {
onAxis.emit(value);
return RESPONSE_MATCHED;
}
break;
}
case SDL_JOYHATMOTION: {
if (positive.Matches(&event->jhat) || positive.Matches(&event->jhat)) {
onAxis.emit(value);
// XXX to emit onRelease, we need to have access to the state of the joystick hat prior to this event,
// so that we can detect the case of switching from a direction that matches the binding to some other direction
return RESPONSE_MATCHED;
}
break;
}
case SDL_JOYAXISMOTION: {
if (axis.Matches(event)) {
onAxis.emit(value);
return RESPONSE_MATCHED;
}
}
default: break;
}
return RESPONSE_NOMATCH;
}
void DispatchSDLEvent(const SDL_Event *event)
{
switch (event->type) {
case SDL_KEYDOWN:
case SDL_KEYUP:
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
case SDL_JOYHATMOTION:
break;
default: return;
}
// simplest possible approach here: just check each binding and dispatch if it matches
for (ActionBinding *const *binding = s_KeyBindings; *binding; ++binding) {
(*binding)->CheckSDLEventAndDispatch(event);
}
}
void InitKeyBinding(ActionBinding &kb, const std::string &bindName, Uint32 defaultKey1, Uint32 defaultKey2)
{
std::string keyName = Pi::config->String(bindName.c_str());
if (keyName.length() == 0) {
if (defaultKey1 && defaultKey2) {
keyName = stringf("Key%0{u},Key%1{u}", defaultKey1, defaultKey2);
} else if (defaultKey1 || defaultKey2) {
Uint32 k = (defaultKey1 | defaultKey2); // only one of them is non-zero, so this gets the non-zero value
keyName = stringf("Key%0{u}", k);
}
Pi::config->SetString(bindName.c_str(), keyName.c_str());
}
// set the binding from the configured or default value
kb.SetFromString(keyName.c_str());
}
void InitAxisBinding(JoyAxisBinding &ab, const std::string &bindName, const std::string &defaultAxis)
{
std::string axisName = Pi::config->String(bindName.c_str());
if (axisName.length() == 0) {
axisName = defaultAxis;
Pi::config->SetString(bindName.c_str(), axisName.c_str());
}
// set the binding from the configured or default value
if (!JoyAxisBinding::FromString(axisName.c_str(), ab)) {
Output("invalid axis binding '%s' in config file for %s\n", axisName.c_str(), bindName.c_str());
ab.Clear();
}
}
void UpdateBindings()
{
#define KEY_BINDING(name, config_name, b, default_value_1, default_value_2) \
InitKeyBinding(KeyBindings::name, config_name, default_value_1, default_value_2);
#define AXIS_BINDING(name, config_name, b, default_value) \
InitAxisBinding(KeyBindings::name, config_name, default_value);
#include "KeyBindings.inc.h"
}
void InitBindings()
{
UpdateBindings();
Pi::config->Save();
}
void EnableBindings()
{
m_disableBindings = 0;
}
void DisableBindings()
{
m_disableBindings = 1;
}
} // namespace KeyBindings

View File

@ -1,229 +0,0 @@
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#ifndef KEYBINDINGS_H
#define KEYBINDINGS_H
#include "libs.h"
#include <iosfwd>
enum InputResponse {
// None of the inputs match the event.
RESPONSE_NOMATCH = 0,
// An input matched, but won't consume the event.
RESPONSE_PASSTHROUGH,
// An input matched and consumed the event.
RESPONSE_MATCHED
};
namespace KeyBindings {
enum Type {
BINDING_DISABLED,
KEYBOARD_KEY,
JOYSTICK_BUTTON,
JOYSTICK_HAT,
MOUSE_BUTTON // TODO: implementme!
};
struct KeyBinding {
public:
// constructors
static bool FromString(const char *str, KeyBinding &binding);
static KeyBinding FromString(const char *str);
static KeyBinding FromKeyMod(SDL_Keycode key, SDL_Keymod mod);
static KeyBinding FromJoystickButton(Uint8 joystick, Uint8 button);
static KeyBinding FromJoystickHat(Uint8 joystick, Uint8 hat, Uint8 direction);
KeyBinding() :
type(BINDING_DISABLED)
{
u.keyboard.key = SDLK_UNKNOWN;
u.keyboard.mod = KMOD_NONE;
}
KeyBinding(SDL_Keycode key, SDL_Keymod mod = KMOD_NONE) :
type(KEYBOARD_KEY)
{
u.keyboard.key = key;
u.keyboard.mod = mod;
}
std::string ToString() const; // for serialisation
std::string Description() const; // for display to the user
bool IsActive() const;
bool Matches(const SDL_Keysym *sym) const;
bool Matches(const SDL_JoyButtonEvent *joy) const;
bool Matches(const SDL_JoyHatEvent *joy) const;
void Clear() { memset(this, 0, sizeof(*this)); }
bool Enabled() const { return (type != BINDING_DISABLED); }
friend std::ostream &operator<<(std::ostream &oss, const KeyBinding &kb);
private:
Type type;
union {
struct {
SDL_Keycode key;
SDL_Keymod mod;
} keyboard;
struct {
Uint8 joystick;
Uint8 button;
} joystickButton;
struct {
Uint8 joystick;
Uint8 hat;
Uint8 direction;
} joystickHat;
/* TODO: implement binding mouse buttons.
struct {
Uint8 button;
// TODO: implement binding multiple clicks as their own action.
Uint8 clicks;
} mouseButton;
*/
} u;
};
struct ActionBinding {
KeyBinding binding1;
KeyBinding binding2;
sigc::signal<void> onPress;
sigc::signal<void> onRelease;
ActionBinding() {}
ActionBinding(KeyBinding b1, KeyBinding b2 = KeyBinding()) :
binding1(b1),
binding2(b2) {}
// This constructor is just a programmer shortcut.
ActionBinding(SDL_Keycode k1, SDL_Keycode k2 = SDLK_UNKNOWN)
{
binding1 = KeyBinding(k1);
if (k2 != SDLK_UNKNOWN) binding2 = KeyBinding(k2);
}
void SetFromString(const char *str);
void SetFromString(const std::string str) { return SetFromString(str.c_str()); }
std::string ToString() const;
bool IsActive() const;
InputResponse CheckSDLEventAndDispatch(const SDL_Event *event);
bool Matches(const SDL_Keysym *sym) const;
};
enum AxisDirection {
POSITIVE,
NEGATIVE
};
struct JoyAxisBinding {
public:
JoyAxisBinding() :
joystick(JOYSTICK_DISABLED),
axis(0),
direction(POSITIVE),
deadzone(0.0f),
sensitivity(1.0f) {}
JoyAxisBinding(Uint8 joystick_, Uint8 axis_, AxisDirection direction_, float deadzone_ = 0.0f, float sensitivity_ = 1.0f) :
joystick(joystick_),
axis(axis_),
direction(direction_),
deadzone(deadzone_),
sensitivity(sensitivity_) {}
float GetValue() const;
std::string Description() const;
void Clear()
{
joystick = JOYSTICK_DISABLED;
axis = 0;
direction = POSITIVE;
deadzone = 0.0f;
sensitivity = 1.0f;
}
bool Enabled() const { return (joystick != JOYSTICK_DISABLED); }
static bool FromString(const char *str, JoyAxisBinding &binding);
static JoyAxisBinding FromString(const char *str);
std::string ToString() const;
bool Matches(const SDL_Event *event) const;
bool IsActive() const;
bool IsInverted() { return direction == NEGATIVE; }
AxisDirection GetDirection() { return direction; }
void SetDirection(AxisDirection dir) { direction = dir; }
float GetDeadzone() { return deadzone; }
void SetDeadzone(float dz) { deadzone = dz; }
float GetSensitivity() { return sensitivity; }
void SetSensitivity(float sens) { sensitivity = sens; }
private:
enum { JOYSTICK_DISABLED = Uint8(-1) };
Uint8 joystick;
Uint8 axis;
AxisDirection direction;
float deadzone;
float sensitivity;
};
struct AxisBinding {
JoyAxisBinding axis;
KeyBinding positive;
KeyBinding negative;
AxisBinding() {}
AxisBinding(JoyAxisBinding ax, KeyBinding pos = KeyBinding(), KeyBinding neg = KeyBinding()) :
axis(ax),
positive(pos),
negative(neg) {}
// This constructor is just a programmer shortcut.
AxisBinding(SDL_Keycode k1, SDL_Keycode k2) :
positive(KeyBinding(k1)),
negative(KeyBinding(k2)) {}
sigc::signal<void, float> onAxis;
void SetFromString(const char *str) { return SetFromString(std::string(str)); }
void SetFromString(const std::string str);
std::string ToString() const;
bool IsActive() const;
float GetValue() const;
InputResponse CheckSDLEventAndDispatch(const SDL_Event *event);
};
struct BindingPrototype {
const char *label, *function;
ActionBinding *kb;
JoyAxisBinding *ab;
};
void InitBindings();
void UpdateBindings();
void EnableBindings();
void DisableBindings();
void DispatchSDLEvent(const SDL_Event *event);
#define KEY_BINDING(name, a, b, c, d) extern ActionBinding name;
#define AXIS_BINDING(name, a, b, c) extern JoyAxisBinding name;
#include "KeyBindings.inc.h"
#define BINDING_PAGE(name) extern const BindingPrototype BINDING_PROTOS_##name[];
#include "KeyBindings.inc.h"
} // namespace KeyBindings
#endif /* KEYBINDINGS_H */

View File

@ -1,56 +0,0 @@
// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#ifndef KEY_BINDING
#define KEY_BINDING(name, config_name, ui_name, default_value_1, default_value_2)
#endif
#ifndef AXIS_BINDING
#define AXIS_BINDING(name, config_name, ui_name, default_value)
#endif
#ifndef BINDING_GROUP
#define BINDING_GROUP(ui_name)
#endif
#ifndef BINDING_PAGE
#define BINDING_PAGE(ui_name)
#endif
#ifndef BINDING_PAGE_END
#define BINDING_PAGE_END()
#endif
BINDING_PAGE(CONTROLS)
BINDING_GROUP(Lang::MISCELLANEOUS)
KEY_BINDING(toggleLuaConsole, "BindToggleLuaConsole", Lang::TOGGLE_LUA_CONSOLE, SDLK_BACKQUOTE, 0)
BINDING_GROUP(Lang::RADAR_CONTROL)
KEY_BINDING(toggleScanMode, "BindToggleScanMode", Lang::TOGGLE_RADAR_MODE, SDLK_BACKSLASH, 0)
KEY_BINDING(increaseScanRange, "BindIncreaseScanRange", Lang::INCREASE_RADAR_RANGE, SDLK_RIGHTBRACKET, 0)
KEY_BINDING(decreaseScanRange, "BindDecreaseScanRange", Lang::DECREASE_RADAR_RANGE, SDLK_LEFTBRACKET, 0)
BINDING_PAGE_END()
BINDING_PAGE(VIEW)
BINDING_GROUP(Lang::INTERNAL_VIEW)
KEY_BINDING(frontCamera, "BindFrontCamera", Lang::CAMERA_FRONT_VIEW, SDLK_KP_8, SDLK_UP)
KEY_BINDING(rearCamera, "BindRearCamera", Lang::CAMERA_REAR_VIEW, SDLK_KP_2, SDLK_DOWN)
KEY_BINDING(leftCamera, "BindLeftCamera", Lang::CAMERA_LEFT_VIEW, SDLK_KP_4, SDLK_LEFT)
KEY_BINDING(rightCamera, "BindRightCamera", Lang::CAMERA_RIGHT_VIEW, SDLK_KP_6, SDLK_RIGHT)
KEY_BINDING(topCamera, "BindTopCamera", Lang::CAMERA_TOP_VIEW, SDLK_KP_9, 0)
KEY_BINDING(bottomCamera, "BindBottomCamera", Lang::CAMERA_BOTTOM_VIEW, SDLK_KP_3, 0)
BINDING_GROUP(Lang::EXTERNAL_VIEW)
KEY_BINDING(cameraRollLeft, "BindCameraRollLeft", Lang::ROLL_LEFT, SDLK_KP_1, 0)
KEY_BINDING(cameraRollRight, "BindCameraRollRight", Lang::ROLL_RIGHT, SDLK_KP_3, 0)
KEY_BINDING(cameraRotateDown, "BindCameraRotateDown", Lang::ROTATE_DOWN, SDLK_KP_2, SDLK_DOWN)
KEY_BINDING(cameraRotateUp, "BindCameraRotateUp", Lang::ROTATE_UP, SDLK_KP_8, SDLK_UP)
KEY_BINDING(cameraRotateLeft, "BindCameraRotateLeft", Lang::ROTATE_LEFT, SDLK_KP_4, SDLK_LEFT)
KEY_BINDING(cameraRotateRight, "BindCameraRotateRight", Lang::ROTATE_RIGHT, SDLK_KP_6, SDLK_RIGHT)
KEY_BINDING(resetCamera, "BindResetCamera", Lang::RESET, SDLK_HOME, 0)
BINDING_PAGE_END()
#undef KEY_BINDING
#undef AXIS_BINDING
#undef BINDING_GROUP
#undef BINDING_PAGE
#undef BINDING_PAGE_END

Some files were not shown because too many files have changed in this diff Show More