CommandSet.cpp 83 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027
  1. /*
  2. * CommandSet.cpp
  3. * --------------
  4. * Purpose: Implementation of custom key handling.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "CommandSet.h"
  11. #include "resource.h"
  12. #include "Mptrack.h" // For ErrorBox
  13. #include "../soundlib/mod_specifications.h"
  14. #include "../soundlib/Tables.h"
  15. #include "../mptrack/Reporting.h"
  16. #include "../common/mptFileIO.h"
  17. #include <sstream>
  18. #include "TrackerSettings.h"
  19. OPENMPT_NAMESPACE_BEGIN
  20. namespace
  21. {
  22. // Version of the .mkb format
  23. constexpr int KEYMAP_VERSION = 1;
  24. constexpr std::tuple<InputTargetContext, CommandID, CommandID> NoteContexts[] =
  25. {
  26. {kCtxViewPatternsNote, kcVPStartNotes, kcVPStartNoteStops},
  27. {kCtxViewSamples, kcSampStartNotes, kcSampStartNoteStops},
  28. {kCtxViewInstruments, kcInstrumentStartNotes, kcInstrumentStartNoteStops},
  29. {kCtxViewTree, kcTreeViewStartNotes, kcTreeViewStartNoteStops},
  30. {kCtxInsNoteMap, kcInsNoteMapStartNotes, kcInsNoteMapStartNoteStops},
  31. {kCtxVSTGUI, kcVSTGUIStartNotes, kcVSTGUIStartNoteStops},
  32. {kCtxViewComments, kcCommentsStartNotes, kcCommentsStartNoteStops},
  33. };
  34. }; // namespace
  35. #ifdef MPT_ALL_LOGGING
  36. #define MPT_COMMANDSET_LOGGING
  37. #endif
  38. #ifdef MPT_COMMANDSET_LOGGING
  39. #define LOG_COMMANDSET(x) MPT_LOG_GLOBAL(LogDebug, "CommandSet", x)
  40. #else
  41. #define LOG_COMMANDSET(x) do { } while(0)
  42. #endif
  43. CCommandSet::CCommandSet()
  44. {
  45. // Which key binding rules to enforce?
  46. m_enforceRule[krPreventDuplicate] = true;
  47. m_enforceRule[krDeleteOldOnConflict] = true;
  48. m_enforceRule[krAllowNavigationWithSelection] = true;
  49. m_enforceRule[krAllowSelectionWithNavigation] = true;
  50. m_enforceRule[krAllowSelectCopySelectCombos] = true;
  51. m_enforceRule[krLockNotesToChords] = true;
  52. m_enforceRule[krNoteOffOnKeyRelease] = true;
  53. m_enforceRule[krPropagateNotes] = true;
  54. m_enforceRule[krReassignDigitsToOctaves] = false;
  55. m_enforceRule[krAutoSelectOff] = true;
  56. m_enforceRule[krAutoSpacing] = true;
  57. m_enforceRule[krCheckModifiers] = true;
  58. m_enforceRule[krPropagateSampleManipulation] = true;
  59. // enforceRule[krCheckContextHierarchy] = true;
  60. SetupCommands();
  61. SetupContextHierarchy();
  62. }
  63. // Setup
  64. KeyCommand::KeyCommand(uint32 uid, const TCHAR *message, std::vector<KeyCombination> keys)
  65. : kcList{std::move(keys)}
  66. , Message{message}
  67. , UID{uid}
  68. {
  69. }
  70. static constexpr struct
  71. {
  72. uint32 uid = 0; // ID | Hidden | Dummy
  73. CommandID cmd = kcNull;
  74. const TCHAR *description = nullptr;
  75. } CommandDefinitions[] =
  76. {
  77. {1001, kcPatternRecord, _T("Enable Recording")},
  78. {1002, kcPatternPlayRow, _T("Play Row")},
  79. {1003, kcCursorCopy, _T("Quick Copy")},
  80. {1004, kcCursorPaste, _T("Quick Paste")},
  81. {1005, kcChannelMute, _T("Mute Current Channel")},
  82. {1006, kcChannelSolo, _T("Solo Current Channel")},
  83. {1007, kcTransposeUp, _T("Transpose +1")},
  84. {1008, kcTransposeDown, _T("Transpose -1")},
  85. {1009, kcTransposeOctUp, _T("Transpose +1 Octave")},
  86. {1010, kcTransposeOctDown, _T("Transpose -1 Octave")},
  87. {1011, kcSelectChannel, _T("Select Channel / Select All")},
  88. {1012, kcPatternAmplify, _T("Amplify selection")},
  89. {1013, kcPatternSetInstrument, _T("Apply current instrument")},
  90. {1014, kcPatternInterpolateVol, _T("Interpolate Volume")},
  91. {1015, kcPatternInterpolateEffect, _T("Interpolate Effect")},
  92. {1016, kcPatternVisualizeEffect, _T("Open Effect Visualizer")},
  93. {1017, kcPatternJumpDownh1, _T("Jump down by measure")},
  94. {1018, kcPatternJumpUph1, _T("Jump up by measure")},
  95. {1019, kcPatternSnapDownh1, _T("Snap down to measure")},
  96. {1020, kcPatternSnapUph1, _T("Snap up to measure")},
  97. {1021, kcViewGeneral, _T("View General")},
  98. {1022, kcViewPattern, _T("View Pattern")},
  99. {1023, kcViewSamples, _T("View Samples")},
  100. {1024, kcViewInstruments, _T("View Instruments")},
  101. {1025, kcViewComments, _T("View Comments")},
  102. {1026, kcPlayPatternFromCursor, _T("Play Pattern from Cursor")},
  103. {1027, kcPlayPatternFromStart, _T("Play Pattern from Start")},
  104. {1028, kcPlaySongFromCursor, _T("Play Song from Cursor")},
  105. {1029, kcPlaySongFromStart, _T("Play Song from Start")},
  106. {1030, kcPlayPauseSong, _T("Play Song / Pause Song")},
  107. {1031, kcPauseSong, _T("Pause Song")},
  108. {1032, kcPrevInstrument, _T("Previous Instrument")},
  109. {1033, kcNextInstrument, _T("Next Instrument")},
  110. {1034, kcPrevOrder, _T("Previous Order")},
  111. {1035, kcNextOrder, _T("Next Order")},
  112. {1036, kcPrevOctave, _T("Previous Octave")},
  113. {1037, kcNextOctave, _T("Next Octave")},
  114. {1038, kcNavigateDown, _T("Navigate down by 1 row")},
  115. {1039, kcNavigateUp, _T("Navigate up by 1 row")},
  116. {1040, kcNavigateLeft, _T("Navigate left")},
  117. {1041, kcNavigateRight, _T("Navigate right")},
  118. {1042, kcNavigateNextChan, _T("Navigate to next channel")},
  119. {1043, kcNavigatePrevChan, _T("Navigate to previous channel")},
  120. {1044, kcHomeHorizontal, _T("Go to first channel")},
  121. {1045, kcHomeVertical, _T("Go to first row")},
  122. {1046, kcHomeAbsolute, _T("Go to first row of first channel")},
  123. {1047, kcEndHorizontal, _T("Go to last channel")},
  124. {1048, kcEndVertical, _T("Go to last row")},
  125. {1049, kcEndAbsolute, _T("Go to last row of last channel")},
  126. {1050, kcSelect, _T("Selection key")},
  127. {1051, kcCopySelect, _T("Copy select key")},
  128. {KeyCommand::Hidden, kcSelectOff, _T("Deselect")},
  129. {KeyCommand::Hidden, kcCopySelectOff, _T("Copy deselect key")},
  130. {1054, kcNextPattern, _T("Next Pattern")},
  131. {1055, kcPrevPattern, _T("Previous Pattern")},
  132. //{1056, kcClearSelection, _T("Wipe selection")},
  133. {1057, kcClearRow, _T("Clear row")},
  134. {1058, kcClearField, _T("Clear field")},
  135. {1059, kcClearRowStep, _T("Clear row and step")},
  136. {1060, kcClearFieldStep, _T("Clear field and step")},
  137. {1061, kcDeleteRow, _T("Delete Row(s)")},
  138. {1062, kcShowNoteProperties, _T("Show Note Properties")},
  139. {1063, kcShowEditMenu, _T("Show Context (Right-Click) Menu")},
  140. {1064, kcVPNoteC_0, _T("Base octave C")},
  141. {1065, kcVPNoteCS0, _T("Base octave C#")},
  142. {1066, kcVPNoteD_0, _T("Base octave D")},
  143. {1067, kcVPNoteDS0, _T("Base octave D#")},
  144. {1068, kcVPNoteE_0, _T("Base octave E")},
  145. {1069, kcVPNoteF_0, _T("Base octave F")},
  146. {1070, kcVPNoteFS0, _T("Base octave F#")},
  147. {1071, kcVPNoteG_0, _T("Base octave G")},
  148. {1072, kcVPNoteGS0, _T("Base octave G#")},
  149. {1073, kcVPNoteA_1, _T("Base octave A")},
  150. {1074, kcVPNoteAS1, _T("Base octave A#")},
  151. {1075, kcVPNoteB_1, _T("Base octave B")},
  152. {1076, kcVPNoteC_1, _T("Base octave +1 C")},
  153. {1077, kcVPNoteCS1, _T("Base octave +1 C#")},
  154. {1078, kcVPNoteD_1, _T("Base octave +1 D")},
  155. {1079, kcVPNoteDS1, _T("Base octave +1 D#")},
  156. {1080, kcVPNoteE_1, _T("Base octave +1 E")},
  157. {1081, kcVPNoteF_1, _T("Base octave +1 F")},
  158. {1082, kcVPNoteFS1, _T("Base octave +1 F#")},
  159. {1083, kcVPNoteG_1, _T("Base octave +1 G")},
  160. {1084, kcVPNoteGS1, _T("Base octave +1 G#")},
  161. {1085, kcVPNoteA_2, _T("Base octave +1 A")},
  162. {1086, kcVPNoteAS2, _T("Base octave +1 A#")},
  163. {1087, kcVPNoteB_2, _T("Base octave +1 B")},
  164. {1088, kcVPNoteC_2, _T("Base octave +2 C")},
  165. {1089, kcVPNoteCS2, _T("Base octave +2 C#")},
  166. {1090, kcVPNoteD_2, _T("Base octave +2 D")},
  167. {1091, kcVPNoteDS2, _T("Base octave +2 D#")},
  168. {1092, kcVPNoteE_2, _T("Base octave +2 E")},
  169. {1093, kcVPNoteF_2, _T("Base octave +2 F")},
  170. {1094, kcVPNoteFS2, _T("Base octave +2 F#")},
  171. {1095, kcVPNoteG_2, _T("Base octave +2 G")},
  172. {1096, kcVPNoteGS2, _T("Base octave +2 G#")},
  173. {1097, kcVPNoteA_3, _T("Base octave +2 A")},
  174. {KeyCommand::Hidden, kcVPNoteStopC_0, _T("Stop base octave C")},
  175. {KeyCommand::Hidden, kcVPNoteStopCS0, _T("Stop base octave C#")},
  176. {KeyCommand::Hidden, kcVPNoteStopD_0, _T("Stop base octave D")},
  177. {KeyCommand::Hidden, kcVPNoteStopDS0, _T("Stop base octave D#")},
  178. {KeyCommand::Hidden, kcVPNoteStopE_0, _T("Stop base octave E")},
  179. {KeyCommand::Hidden, kcVPNoteStopF_0, _T("Stop base octave F")},
  180. {KeyCommand::Hidden, kcVPNoteStopFS0, _T("Stop base octave F#")},
  181. {KeyCommand::Hidden, kcVPNoteStopG_0, _T("Stop base octave G")},
  182. {KeyCommand::Hidden, kcVPNoteStopGS0, _T("Stop base octave G#")},
  183. {KeyCommand::Hidden, kcVPNoteStopA_1, _T("Stop base octave +1 A")},
  184. {KeyCommand::Hidden, kcVPNoteStopAS1, _T("Stop base octave +1 A#")},
  185. {KeyCommand::Hidden, kcVPNoteStopB_1, _T("Stop base octave +1 B")},
  186. {KeyCommand::Hidden, kcVPNoteStopC_1, _T("Stop base octave +1 C")},
  187. {KeyCommand::Hidden, kcVPNoteStopCS1, _T("Stop base octave +1 C#")},
  188. {KeyCommand::Hidden, kcVPNoteStopD_1, _T("Stop base octave +1 D")},
  189. {KeyCommand::Hidden, kcVPNoteStopDS1, _T("Stop base octave +1 D#")},
  190. {KeyCommand::Hidden, kcVPNoteStopE_1, _T("Stop base octave +1 E")},
  191. {KeyCommand::Hidden, kcVPNoteStopF_1, _T("Stop base octave +1 F")},
  192. {KeyCommand::Hidden, kcVPNoteStopFS1, _T("Stop base octave +1 F#")},
  193. {KeyCommand::Hidden, kcVPNoteStopG_1, _T("Stop base octave +1 G")},
  194. {KeyCommand::Hidden, kcVPNoteStopGS1, _T("Stop base octave +1 G#")},
  195. {KeyCommand::Hidden, kcVPNoteStopA_2, _T("Stop base octave +2 A")},
  196. {KeyCommand::Hidden, kcVPNoteStopAS2, _T("Stop base octave +2 A#")},
  197. {KeyCommand::Hidden, kcVPNoteStopB_2, _T("Stop base octave +2 B")},
  198. {KeyCommand::Hidden, kcVPNoteStopC_2, _T("Stop base octave +2 C")},
  199. {KeyCommand::Hidden, kcVPNoteStopCS2, _T("Stop base octave +2 C#")},
  200. {KeyCommand::Hidden, kcVPNoteStopD_2, _T("Stop base octave +2 D")},
  201. {KeyCommand::Hidden, kcVPNoteStopDS2, _T("Stop base octave +2 D#")},
  202. {KeyCommand::Hidden, kcVPNoteStopE_2, _T("Stop base octave +2 E")},
  203. {KeyCommand::Hidden, kcVPNoteStopF_2, _T("Stop base octave +2 F")},
  204. {KeyCommand::Hidden, kcVPNoteStopFS2, _T("Stop base octave +2 F#")},
  205. {KeyCommand::Hidden, kcVPNoteStopG_2, _T("Stop base octave +2 G")},
  206. {KeyCommand::Hidden, kcVPNoteStopGS2, _T("Stop base octave +2 G#")},
  207. {KeyCommand::Hidden, kcVPNoteStopA_3, _T("Stop base octave +3 A")},
  208. {KeyCommand::Hidden, kcVPChordC_0, _T("Base octave chord C")},
  209. {KeyCommand::Hidden, kcVPChordCS0, _T("Base octave chord C#")},
  210. {KeyCommand::Hidden, kcVPChordD_0, _T("Base octave chord D")},
  211. {KeyCommand::Hidden, kcVPChordDS0, _T("Base octave chord D#")},
  212. {KeyCommand::Hidden, kcVPChordE_0, _T("Base octave chord E")},
  213. {KeyCommand::Hidden, kcVPChordF_0, _T("Base octave chord F")},
  214. {KeyCommand::Hidden, kcVPChordFS0, _T("Base octave chord F#")},
  215. {KeyCommand::Hidden, kcVPChordG_0, _T("Base octave chord G")},
  216. {KeyCommand::Hidden, kcVPChordGS0, _T("Base octave chord G#")},
  217. {KeyCommand::Hidden, kcVPChordA_1, _T("Base octave +1 chord A")},
  218. {KeyCommand::Hidden, kcVPChordAS1, _T("Base octave +1 chord A#")},
  219. {KeyCommand::Hidden, kcVPChordB_1, _T("Base octave +1 chord B")},
  220. {KeyCommand::Hidden, kcVPChordC_1, _T("Base octave +1 chord C")},
  221. {KeyCommand::Hidden, kcVPChordCS1, _T("Base octave +1 chord C#")},
  222. {KeyCommand::Hidden, kcVPChordD_1, _T("Base octave +1 chord D")},
  223. {KeyCommand::Hidden, kcVPChordDS1, _T("Base octave +1 chord D#")},
  224. {KeyCommand::Hidden, kcVPChordE_1, _T("Base octave +1 chord E")},
  225. {KeyCommand::Hidden, kcVPChordF_1, _T("Base octave +1 chord F")},
  226. {KeyCommand::Hidden, kcVPChordFS1, _T("Base octave +1 chord F#")},
  227. {KeyCommand::Hidden, kcVPChordG_1, _T("Base octave +1 chord G")},
  228. {KeyCommand::Hidden, kcVPChordGS1, _T("Base octave +1 chord G#")},
  229. {KeyCommand::Hidden, kcVPChordA_2, _T("Base octave +2 chord A")},
  230. {KeyCommand::Hidden, kcVPChordAS2, _T("Base octave +2 chord A#")},
  231. {KeyCommand::Hidden, kcVPChordB_2, _T("Base octave +2 chord B")},
  232. {KeyCommand::Hidden, kcVPChordC_2, _T("Base octave +2 chord C")},
  233. {KeyCommand::Hidden, kcVPChordCS2, _T("Base octave +2 chord C#")},
  234. {KeyCommand::Hidden, kcVPChordD_2, _T("Base octave +2 chord D")},
  235. {KeyCommand::Hidden, kcVPChordDS2, _T("Base octave +2 chord D#")},
  236. {KeyCommand::Hidden, kcVPChordE_2, _T("Base octave +2 chord E")},
  237. {KeyCommand::Hidden, kcVPChordF_2, _T("Base octave +2 chord F")},
  238. {KeyCommand::Hidden, kcVPChordFS2, _T("Base octave +2 chord F#")},
  239. {KeyCommand::Hidden, kcVPChordG_2, _T("Base octave +2 chord G")},
  240. {KeyCommand::Hidden, kcVPChordGS2, _T("Base octave +2 chord G#")},
  241. {KeyCommand::Hidden, kcVPChordA_3, _T("Base octave chord +3 A")},
  242. {KeyCommand::Hidden, kcVPChordStopC_0, _T("Stop base octave chord C")},
  243. {KeyCommand::Hidden, kcVPChordStopCS0, _T("Stop base octave chord C#")},
  244. {KeyCommand::Hidden, kcVPChordStopD_0, _T("Stop base octave chord D")},
  245. {KeyCommand::Hidden, kcVPChordStopDS0, _T("Stop base octave chord D#")},
  246. {KeyCommand::Hidden, kcVPChordStopE_0, _T("Stop base octave chord E")},
  247. {KeyCommand::Hidden, kcVPChordStopF_0, _T("Stop base octave chord F")},
  248. {KeyCommand::Hidden, kcVPChordStopFS0, _T("Stop base octave chord F#")},
  249. {KeyCommand::Hidden, kcVPChordStopG_0, _T("Stop base octave chord G")},
  250. {KeyCommand::Hidden, kcVPChordStopGS0, _T("Stop base octave chord G#")},
  251. {KeyCommand::Hidden, kcVPChordStopA_1, _T("Stop base octave +1 chord A")},
  252. {KeyCommand::Hidden, kcVPChordStopAS1, _T("Stop base octave +1 chord A#")},
  253. {KeyCommand::Hidden, kcVPChordStopB_1, _T("Stop base octave +1 chord B")},
  254. {KeyCommand::Hidden, kcVPChordStopC_1, _T("Stop base octave +1 chord C")},
  255. {KeyCommand::Hidden, kcVPChordStopCS1, _T("Stop base octave +1 chord C#")},
  256. {KeyCommand::Hidden, kcVPChordStopD_1, _T("Stop base octave +1 chord D")},
  257. {KeyCommand::Hidden, kcVPChordStopDS1, _T("Stop base octave +1 chord D#")},
  258. {KeyCommand::Hidden, kcVPChordStopE_1, _T("Stop base octave +1 chord E")},
  259. {KeyCommand::Hidden, kcVPChordStopF_1, _T("Stop base octave +1 chord F")},
  260. {KeyCommand::Hidden, kcVPChordStopFS1, _T("Stop base octave +1 chord F#")},
  261. {KeyCommand::Hidden, kcVPChordStopG_1, _T("Stop base octave +1 chord G")},
  262. {KeyCommand::Hidden, kcVPChordStopGS1, _T("Stop base octave +1 chord G#")},
  263. {KeyCommand::Hidden, kcVPChordStopA_2, _T("Stop base octave +2 chord A")},
  264. {KeyCommand::Hidden, kcVPChordStopAS2, _T("Stop base octave +2 chord A#")},
  265. {KeyCommand::Hidden, kcVPChordStopB_2, _T("Stop base octave +2 chord B")},
  266. {KeyCommand::Hidden, kcVPChordStopC_2, _T("Stop base octave +2 chord C")},
  267. {KeyCommand::Hidden, kcVPChordStopCS2, _T("Stop base octave +2 chord C#")},
  268. {KeyCommand::Hidden, kcVPChordStopD_2, _T("Stop base octave +2 chord D")},
  269. {KeyCommand::Hidden, kcVPChordStopDS2, _T("Stop base octave +2 chord D#")},
  270. {KeyCommand::Hidden, kcVPChordStopE_2, _T("Stop base octave +2 chord E")},
  271. {KeyCommand::Hidden, kcVPChordStopF_2, _T("Stop base octave +2 chord F")},
  272. {KeyCommand::Hidden, kcVPChordStopFS2, _T("Stop base octave +2 chord F#")},
  273. {KeyCommand::Hidden, kcVPChordStopG_2, _T("Stop base octave +2 chord G")},
  274. {KeyCommand::Hidden, kcVPChordStopGS2, _T("Stop base octave +2 chord G#")},
  275. {KeyCommand::Hidden, kcVPChordStopA_3, _T("Stop base octave +3 chord A")},
  276. {1200, kcNoteCut, _T("Note Cut")},
  277. {1201, kcNoteOff, _T("Note Off")},
  278. {1202, kcSetIns0, _T("Set instrument digit 0")},
  279. {1203, kcSetIns1, _T("Set instrument digit 1")},
  280. {1204, kcSetIns2, _T("Set instrument digit 2")},
  281. {1205, kcSetIns3, _T("Set instrument digit 3")},
  282. {1206, kcSetIns4, _T("Set instrument digit 4")},
  283. {1207, kcSetIns5, _T("Set instrument digit 5")},
  284. {1208, kcSetIns6, _T("Set instrument digit 6")},
  285. {1209, kcSetIns7, _T("Set instrument digit 7")},
  286. {1210, kcSetIns8, _T("Set instrument digit 8")},
  287. {1211, kcSetIns9, _T("Set instrument digit 9")},
  288. {1212, kcSetOctave0, _T("Set octave 0")},
  289. {1213, kcSetOctave1, _T("Set octave 1")},
  290. {1214, kcSetOctave2, _T("Set octave 2")},
  291. {1215, kcSetOctave3, _T("Set octave 3")},
  292. {1216, kcSetOctave4, _T("Set octave 4")},
  293. {1217, kcSetOctave5, _T("Set octave 5")},
  294. {1218, kcSetOctave6, _T("Set octave 6")},
  295. {1219, kcSetOctave7, _T("Set octave 7")},
  296. {1220, kcSetOctave8, _T("Set octave 8")},
  297. {1221, kcSetOctave9, _T("Set octave 9")},
  298. {1222, kcSetVolume0, _T("Set volume digit 0")},
  299. {1223, kcSetVolume1, _T("Set volume digit 1")},
  300. {1224, kcSetVolume2, _T("Set volume digit 2")},
  301. {1225, kcSetVolume3, _T("Set volume digit 3")},
  302. {1226, kcSetVolume4, _T("Set volume digit 4")},
  303. {1227, kcSetVolume5, _T("Set volume digit 5")},
  304. {1228, kcSetVolume6, _T("Set volume digit 6")},
  305. {1229, kcSetVolume7, _T("Set volume digit 7")},
  306. {1230, kcSetVolume8, _T("Set volume digit 8")},
  307. {1231, kcSetVolume9, _T("Set volume digit 9")},
  308. {1232, kcSetVolumeVol, _T("Volume Command - Volume")},
  309. {1233, kcSetVolumePan, _T("Volume Command - Panning")},
  310. {1234, kcSetVolumeVolSlideUp, _T("Volume Command - Volume Slide Up")},
  311. {1235, kcSetVolumeVolSlideDown, _T("Volume Command - Volume Slide Down")},
  312. {1236, kcSetVolumeFineVolUp, _T("Volume Command - Fine Volume Slide Up")},
  313. {1237, kcSetVolumeFineVolDown, _T("Volume Command - Fine Volume Slide Down")},
  314. {1238, kcSetVolumeVibratoSpd, _T("Volume Command - Vibrato Speed")},
  315. {1239, kcSetVolumeVibrato, _T("Volume Command - Vibrato Depth")},
  316. {1240, kcSetVolumeXMPanLeft, _T("Volume Command - XM Pan Slide Left")},
  317. {1241, kcSetVolumeXMPanRight, _T("Volume Command - XM Pan Slide Right")},
  318. {1242, kcSetVolumePortamento, _T("Volume Command - Tone Portamento")},
  319. {1243, kcSetVolumeITPortaUp, _T("Volume Command - Portamento Up")},
  320. {1244, kcSetVolumeITPortaDown, _T("Volume Command - Portamento Down")},
  321. {KeyCommand::Hidden, kcSetVolumeITUnused, _T("Volume Command - Unused")},
  322. {1246, kcSetVolumeITOffset, _T("Volume Command - Offset")},
  323. {1247, kcSetFXParam0, _T("Effect Parameter Digit 0")},
  324. {1248, kcSetFXParam1, _T("Effect Parameter Digit 1")},
  325. {1249, kcSetFXParam2, _T("Effect Parameter Digit 2")},
  326. {1250, kcSetFXParam3, _T("Effect Parameter Digit 3")},
  327. {1251, kcSetFXParam4, _T("Effect Parameter Digit 4")},
  328. {1252, kcSetFXParam5, _T("Effect Parameter Digit 5")},
  329. {1253, kcSetFXParam6, _T("Effect Parameter Digit 6")},
  330. {1254, kcSetFXParam7, _T("Effect Parameter Digit 7")},
  331. {1255, kcSetFXParam8, _T("Effect Parameter Digit 8")},
  332. {1256, kcSetFXParam9, _T("Effect Parameter Digit 9")},
  333. {1257, kcSetFXParamA, _T("Effect Parameter Digit A")},
  334. {1258, kcSetFXParamB, _T("Effect Parameter Digit B")},
  335. {1259, kcSetFXParamC, _T("Effect Parameter Digit C")},
  336. {1260, kcSetFXParamD, _T("Effect Parameter Digit D")},
  337. {1261, kcSetFXParamE, _T("Effect Parameter Digit E")},
  338. {1262, kcSetFXParamF, _T("Effect Parameter Digit F")},
  339. {KeyCommand::Hidden, kcSetFXarp, _T("FX Arpeggio")},
  340. {KeyCommand::Hidden, kcSetFXportUp, _T("FX Portamento Up")},
  341. {KeyCommand::Hidden, kcSetFXportDown, _T("FX Portamento Down")},
  342. {KeyCommand::Hidden, kcSetFXport, _T("FX Tone Portamento")},
  343. {KeyCommand::Hidden, kcSetFXvibrato, _T("FX Vibrato")},
  344. {KeyCommand::Hidden, kcSetFXportSlide, _T("FX Portamento + Volume Slide")},
  345. {KeyCommand::Hidden, kcSetFXvibSlide, _T("FX Vibrato + Volume Slide")},
  346. {KeyCommand::Hidden, kcSetFXtremolo, _T("FX Tremolo")},
  347. {KeyCommand::Hidden, kcSetFXpan, _T("FX Pan")},
  348. {KeyCommand::Hidden, kcSetFXoffset, _T("FX Offset")},
  349. {KeyCommand::Hidden, kcSetFXvolSlide, _T("FX Volume Slide")},
  350. {KeyCommand::Hidden, kcSetFXgotoOrd, _T("FX Pattern Jump")},
  351. {KeyCommand::Hidden, kcSetFXsetVol, _T("FX Set Volume")},
  352. {KeyCommand::Hidden, kcSetFXgotoRow, _T("FX Break To Row")},
  353. {KeyCommand::Hidden, kcSetFXretrig, _T("FX Retrigger")},
  354. {KeyCommand::Hidden, kcSetFXspeed, _T("FX Set Speed")},
  355. {KeyCommand::Hidden, kcSetFXtempo, _T("FX Set Tempo")},
  356. {KeyCommand::Hidden, kcSetFXtremor, _T("FX Tremor")},
  357. {KeyCommand::Hidden, kcSetFXextendedMOD, _T("FX Extended MOD Commands")},
  358. {KeyCommand::Hidden, kcSetFXextendedS3M, _T("FX Extended S3M Commands")},
  359. {KeyCommand::Hidden, kcSetFXchannelVol, _T("FX Set Channel Volume")},
  360. {KeyCommand::Hidden, kcSetFXchannelVols, _T("FX Channel Volume Slide")},
  361. {KeyCommand::Hidden, kcSetFXglobalVol, _T("FX Set Global Volume")},
  362. {KeyCommand::Hidden, kcSetFXglobalVols, _T("FX Global Volume Slide")},
  363. {KeyCommand::Hidden, kcSetFXkeyoff, _T("FX Key Off (XM)")},
  364. {KeyCommand::Hidden, kcSetFXfineVib, _T("FX Fine Vibrato")},
  365. {KeyCommand::Hidden, kcSetFXpanbrello, _T("FX Panbrello")},
  366. {KeyCommand::Hidden, kcSetFXextendedXM, _T("FX Extended XM Commands")},
  367. {KeyCommand::Hidden, kcSetFXpanSlide, _T("FX Pan Slide")},
  368. {KeyCommand::Hidden, kcSetFXsetEnvPos, _T("FX Set Envelope Position (XM)")},
  369. {KeyCommand::Hidden, kcSetFXmacro, _T("FX MIDI Macro")},
  370. {1294, kcSetFXmacroSlide, _T("Smooth MIDI Macro Slide")},
  371. {1295, kcSetFXdelaycut, _T("Combined Note Delay and Note Cut")},
  372. {KeyCommand::Hidden, kcPatternJumpDownh1Select, _T("kcPatternJumpDownh1Select")},
  373. {KeyCommand::Hidden, kcPatternJumpUph1Select, _T("kcPatternJumpUph1Select")},
  374. {KeyCommand::Hidden, kcPatternSnapDownh1Select, _T("kcPatternSnapDownh1Select")},
  375. {KeyCommand::Hidden, kcPatternSnapUph1Select, _T("kcPatternSnapUph1Select")},
  376. {KeyCommand::Hidden, kcNavigateDownSelect, _T("kcNavigateDownSelect")},
  377. {KeyCommand::Hidden, kcNavigateUpSelect, _T("kcNavigateUpSelect")},
  378. {KeyCommand::Hidden, kcNavigateLeftSelect, _T("kcNavigateLeftSelect")},
  379. {KeyCommand::Hidden, kcNavigateRightSelect, _T("kcNavigateRightSelect")},
  380. {KeyCommand::Hidden, kcNavigateNextChanSelect, _T("kcNavigateNextChanSelect")},
  381. {KeyCommand::Hidden, kcNavigatePrevChanSelect, _T("kcNavigatePrevChanSelect")},
  382. {KeyCommand::Hidden, kcHomeHorizontalSelect, _T("kcHomeHorizontalSelect")},
  383. {KeyCommand::Hidden, kcHomeVerticalSelect, _T("kcHomeVerticalSelect")},
  384. {KeyCommand::Hidden, kcHomeAbsoluteSelect, _T("kcHomeAbsoluteSelect")},
  385. {KeyCommand::Hidden, kcEndHorizontalSelect, _T("kcEndHorizontalSelect")},
  386. {KeyCommand::Hidden, kcEndVerticalSelect, _T("kcEndVerticalSelect")},
  387. {KeyCommand::Hidden, kcEndAbsoluteSelect, _T("kcEndAbsoluteSelect")},
  388. {KeyCommand::Hidden, kcSelectWithNav, _T("kcSelectWithNav")},
  389. {KeyCommand::Hidden, kcSelectOffWithNav, _T("kcSelectOffWithNav")},
  390. {KeyCommand::Hidden, kcCopySelectWithNav, _T("kcCopySelectWithNav")},
  391. {KeyCommand::Hidden, kcCopySelectOffWithNav, _T("kcCopySelectOffWithNav")},
  392. {1316 | KeyCommand::Dummy, kcChordModifier, _T("Chord Modifier")},
  393. {1317 | KeyCommand::Dummy, kcSetSpacing, _T("Set edit step on note entry")},
  394. {KeyCommand::Hidden, kcSetSpacing0, _T("")},
  395. {KeyCommand::Hidden, kcSetSpacing1, _T("")},
  396. {KeyCommand::Hidden, kcSetSpacing2, _T("")},
  397. {KeyCommand::Hidden, kcSetSpacing3, _T("")},
  398. {KeyCommand::Hidden, kcSetSpacing4, _T("")},
  399. {KeyCommand::Hidden, kcSetSpacing5, _T("")},
  400. {KeyCommand::Hidden, kcSetSpacing6, _T("")},
  401. {KeyCommand::Hidden, kcSetSpacing7, _T("")},
  402. {KeyCommand::Hidden, kcSetSpacing8, _T("")},
  403. {KeyCommand::Hidden, kcSetSpacing9, _T("")},
  404. {KeyCommand::Hidden, kcCopySelectWithSelect, _T("kcCopySelectWithSelect")},
  405. {KeyCommand::Hidden, kcCopySelectOffWithSelect, _T("kcCopySelectOffWithSelect")},
  406. {KeyCommand::Hidden, kcSelectWithCopySelect, _T("kcSelectWithCopySelect")},
  407. {KeyCommand::Hidden, kcSelectOffWithCopySelect, _T("kcSelectOffWithCopySelect")},
  408. /*
  409. {1332, kcCopy, _T("Copy pattern data")},
  410. {1333, kcCut, _T("Cut pattern data")},
  411. {1334, kcPaste, _T("Paste pattern data")},
  412. {1335, kcMixPaste, _T("Mix-paste pattern data")},
  413. {1336, kcSelectAll, _T("Select all pattern data")},
  414. {CommandStruct::Hidden, kcSelectCol, _T("Select Channel / Select All")},
  415. */
  416. {1338, kcPatternJumpDownh2, _T("Jump down by beat")},
  417. {1339, kcPatternJumpUph2, _T("Jump up by beat")},
  418. {1340, kcPatternSnapDownh2, _T("Snap down to beat")},
  419. {1341, kcPatternSnapUph2, _T("Snap up to beat")},
  420. {KeyCommand::Hidden, kcPatternJumpDownh2Select, _T("kcPatternJumpDownh2Select")},
  421. {KeyCommand::Hidden, kcPatternJumpUph2Select, _T("kcPatternJumpUph2Select")},
  422. {KeyCommand::Hidden, kcPatternSnapDownh2Select, _T("kcPatternSnapDownh2Select")},
  423. {KeyCommand::Hidden, kcPatternSnapUph2Select, _T("kcPatternSnapUph2Select")},
  424. {1346, kcFileOpen, _T("File/Open")},
  425. {1347, kcFileNew, _T("File/New")},
  426. {1348, kcFileClose, _T("File/Close")},
  427. {1349, kcFileSave, _T("File/Save")},
  428. {1350, kcFileSaveAs, _T("File/Save As")},
  429. {1351, kcFileSaveAsWave, _T("File/Stream Export")},
  430. {1352 | KeyCommand::Hidden, kcFileSaveAsMP3, _T("File/Stream Export")}, // Legacy
  431. {1353, kcFileSaveMidi, _T("File/Export as MIDI")},
  432. {1354, kcFileImportMidiLib, _T("File/Import MIDI Library")},
  433. {1355, kcFileAddSoundBank, _T("File/Add Sound Bank")},
  434. {1359, kcEditUndo, _T("Undo")},
  435. {1360, kcEditCut, _T("Cut")},
  436. {1361, kcEditCopy, _T("Copy")},
  437. {1362, kcEditPaste, _T("Paste")},
  438. {1363, kcEditMixPaste, _T("Mix Paste")},
  439. {1364, kcEditSelectAll, _T("Select All")},
  440. {1365, kcEditFind, _T("Find / Replace")},
  441. {1366, kcEditFindNext, _T("Find Next")},
  442. {1367, kcViewMain, _T("Toggle Main Toolbar")},
  443. {1368, kcViewTree, _T("Toggle Tree View")},
  444. {1369, kcViewOptions, _T("View Options")},
  445. {1370, kcHelp, _T("Help")},
  446. /*
  447. {1370, kcWindowNew, _T("New Window")},
  448. {1371, kcWindowCascade, _T("Cascade Windows")},
  449. {1372, kcWindowTileHorz, _T("Tile Windows Horizontally")},
  450. {1373, kcWindowTileVert, _T("Tile Windows Vertically")},
  451. */
  452. {1374, kcEstimateSongLength, _T("Estimate Song Length")},
  453. {1375, kcStopSong, _T("Stop Song")},
  454. {1376, kcMidiRecord, _T("Toggle MIDI Record")},
  455. {1377, kcDeleteWholeRow, _T("Delete Row(s) (All Channels)")},
  456. {1378, kcInsertRow, _T("Insert Row(s)")},
  457. {1379, kcInsertWholeRow, _T("Insert Row(s) (All Channels)")},
  458. {1380, kcSampleTrim, _T("Trim sample around loop points")},
  459. {1381, kcSampleReverse, _T("Reverse Sample")},
  460. {1382, kcSampleDelete, _T("Delete Sample Selection")},
  461. {1383, kcSampleSilence, _T("Silence Sample Selection")},
  462. {1384, kcSampleNormalize, _T("Normalize Sample")},
  463. {1385, kcSampleAmplify, _T("Amplify Sample")},
  464. {1386, kcSampleZoomUp, _T("Zoom In")},
  465. {1387, kcSampleZoomDown, _T("Zoom Out")},
  466. {1660, kcPatternGrowSelection, _T("Grow selection")},
  467. {1661, kcPatternShrinkSelection, _T("Shrink selection")},
  468. {1662, kcTogglePluginEditor, _T("Toggle channel's plugin editor")},
  469. {1663, kcToggleFollowSong, _T("Toggle follow song")},
  470. {1664, kcClearFieldITStyle, _T("Clear field (IT Style)")},
  471. {1665, kcClearFieldStepITStyle, _T("Clear field and step (IT Style)")},
  472. {1666, kcSetFXextension, _T("Parameter Extension Command")},
  473. {1667 | KeyCommand::Hidden, kcNoteCutOld, _T("Note Cut")}, // Legacy
  474. {1668 | KeyCommand::Hidden, kcNoteOffOld, _T("Note Off")}, // Legacy
  475. {1669, kcViewAddPlugin, _T("View Plugin Manager")},
  476. {1670, kcViewChannelManager, _T("View Channel Manager")},
  477. {1671, kcCopyAndLoseSelection, _T("Copy and lose selection")},
  478. {1672, kcNewPattern, _T("Insert new pattern")},
  479. {1673, kcSampleLoad, _T("Load Sample")},
  480. {1674, kcSampleSave, _T("Save Sample")},
  481. {1675, kcSampleNew, _T("New Sample")},
  482. //{CommandStruct::Hidden, kcSampleCtrlLoad, _T("Load Sample")},
  483. //{CommandStruct::Hidden, kcSampleCtrlSave, _T("Save Sample")},
  484. //{CommandStruct::Hidden, kcSampleCtrlNew, _T("New Sample")},
  485. {KeyCommand::Hidden, kcInstrumentLoad, _T("Load Instrument")},
  486. {KeyCommand::Hidden, kcInstrumentSave, _T("Save Instrument")},
  487. {KeyCommand::Hidden, kcInstrumentNew, _T("New Instrument")},
  488. {KeyCommand::Hidden, kcInstrumentCtrlLoad, _T("Load Instrument")},
  489. {KeyCommand::Hidden, kcInstrumentCtrlSave, _T("Save Instrument")},
  490. {KeyCommand::Hidden, kcInstrumentCtrlNew, _T("New Instrument")},
  491. {1685, kcSwitchToOrderList, _T("Switch to Order List")},
  492. {1686, kcEditMixPasteITStyle, _T("Mix Paste (IT Style)")},
  493. {1687, kcApproxRealBPM, _T("Show approx. real BPM")},
  494. {KeyCommand::Hidden, kcNavigateDownBySpacingSelect, _T("kcNavigateDownBySpacingSelect")},
  495. {KeyCommand::Hidden, kcNavigateUpBySpacingSelect, _T("kcNavigateUpBySpacingSelect")},
  496. {1691, kcNavigateDownBySpacing, _T("Navigate down by spacing")},
  497. {1692, kcNavigateUpBySpacing, _T("Navigate up by spacing")},
  498. {1693, kcPrevDocument, _T("Previous Document")},
  499. {1694, kcNextDocument, _T("Next Document")},
  500. {1763, kcVSTGUIPrevPreset, _T("Previous Plugin Preset")},
  501. {1764, kcVSTGUINextPreset, _T("Next Plugin Preset")},
  502. {1765, kcVSTGUIRandParams, _T("Randomize Plugin Parameters")},
  503. {1766, kcPatternGoto, _T("Go to row/channel/...")},
  504. {KeyCommand::Hidden, kcPatternOpenRandomizer, _T("Pattern Randomizer")}, // while there's not randomizer yet, let's just disable it for now
  505. {1768, kcPatternInterpolateNote, _T("Interpolate Note")},
  506. {KeyCommand::Hidden, kcViewGraph, _T("View Graph")}, // while there's no graph yet, let's just disable it for now
  507. {1770, kcToggleChanMuteOnPatTransition, _T("(Un)mute channel on pattern transition")},
  508. {1771, kcChannelUnmuteAll, _T("Unmute all channels")},
  509. {1772, kcShowPatternProperties, _T("Show Pattern Properties")},
  510. {1773, kcShowMacroConfig, _T("View Zxx Macro Configuration")},
  511. {1775, kcViewSongProperties, _T("View Song Properties")},
  512. {1776, kcChangeLoopStatus, _T("Toggle Loop Pattern")},
  513. {1777, kcFileExportCompat, _T("File/Compatibility Export")},
  514. {1778, kcUnmuteAllChnOnPatTransition, _T("Unmute all channels on pattern transition")},
  515. {1779, kcSoloChnOnPatTransition, _T("Solo channel on pattern transition")},
  516. {1780, kcTimeAtRow, _T("Show playback time at current row")},
  517. {1781, kcViewMIDImapping, _T("View MIDI Mapping")},
  518. {1782, kcVSTGUIPrevPresetJump, _T("Plugin preset backward jump")},
  519. {1783, kcVSTGUINextPresetJump, _T("Plugin preset forward jump")},
  520. {1784, kcSampleInvert, _T("Invert Sample Phase")},
  521. {1785, kcSampleSignUnsign, _T("Signed / Unsigned Conversion")},
  522. {1786, kcChannelReset, _T("Reset Channel")},
  523. {1787, kcToggleOverflowPaste, _T("Toggle overflow paste")},
  524. {1788, kcNotePC, _T("Parameter Control")},
  525. {1789, kcNotePCS, _T("Parameter Control (smooth)")},
  526. {1790, kcSampleRemoveDCOffset, _T("Remove DC Offset")},
  527. {1791, kcNoteFade, _T("Note Fade")},
  528. {1792 | KeyCommand::Hidden, kcNoteFadeOld, _T("Note Fade")}, // Legacy
  529. {1793, kcEditPasteFlood, _T("Paste Flood")},
  530. {1794, kcOrderlistNavigateLeft, _T("Previous Order")},
  531. {1795, kcOrderlistNavigateRight, _T("Next Order")},
  532. {1796, kcOrderlistNavigateFirst, _T("First Order")},
  533. {1797, kcOrderlistNavigateLast, _T("Last Order")},
  534. {KeyCommand::Hidden, kcOrderlistNavigateLeftSelect, _T("kcOrderlistNavigateLeftSelect")},
  535. {KeyCommand::Hidden, kcOrderlistNavigateRightSelect, _T("kcOrderlistNavigateRightSelect")},
  536. {KeyCommand::Hidden, kcOrderlistNavigateFirstSelect, _T("kcOrderlistNavigateFirstSelect")},
  537. {KeyCommand::Hidden, kcOrderlistNavigateLastSelect, _T("kcOrderlistNavigateLastSelect")},
  538. {1802, kcOrderlistEditDelete, _T("Delete Order")},
  539. {1803, kcOrderlistEditInsert, _T("Insert Order")},
  540. {1804, kcOrderlistEditPattern, _T("Edit Pattern")},
  541. {1805, kcOrderlistSwitchToPatternView, _T("Switch to pattern editor")},
  542. {1806, kcDuplicatePattern, _T("Duplicate Pattern")},
  543. {1807, kcOrderlistPat0, _T("Pattern index digit 0")},
  544. {1808, kcOrderlistPat1, _T("Pattern index digit 1")},
  545. {1809, kcOrderlistPat2, _T("Pattern index digit 2")},
  546. {1810, kcOrderlistPat3, _T("Pattern index digit 3")},
  547. {1811, kcOrderlistPat4, _T("Pattern index digit 4")},
  548. {1812, kcOrderlistPat5, _T("Pattern index digit 5")},
  549. {1813, kcOrderlistPat6, _T("Pattern index digit 6")},
  550. {1814, kcOrderlistPat7, _T("Pattern index digit 7")},
  551. {1815, kcOrderlistPat8, _T("Pattern index digit 8")},
  552. {1816, kcOrderlistPat9, _T("Pattern index digit 9")},
  553. {1817, kcOrderlistPatPlus, _T("Increase pattern index ")},
  554. {1818, kcOrderlistPatMinus, _T("Decrease pattern index")},
  555. {1819, kcShowSplitKeyboardSettings, _T("Split Keyboard Settings dialog")},
  556. {1820, kcEditPushForwardPaste, _T("Push Forward Paste (Insert)")},
  557. {1821, kcInstrumentEnvelopePointMoveLeft, _T("Move envelope point left")},
  558. {1822, kcInstrumentEnvelopePointMoveRight, _T("Move envelope point right")},
  559. {1823, kcInstrumentEnvelopePointMoveUp, _T("Move envelope point up")},
  560. {1824, kcInstrumentEnvelopePointMoveDown, _T("Move envelope point down")},
  561. {1825, kcInstrumentEnvelopePointPrev, _T("Select previous envelope point")},
  562. {1826, kcInstrumentEnvelopePointNext, _T("Select next envelope point")},
  563. {1827, kcInstrumentEnvelopePointInsert, _T("Insert Envelope Point")},
  564. {1828, kcInstrumentEnvelopePointRemove, _T("Remove Envelope Point")},
  565. {1829, kcInstrumentEnvelopeSetLoopStart, _T("Set Loop Start")},
  566. {1830, kcInstrumentEnvelopeSetLoopEnd, _T("Set Loop End")},
  567. {1831, kcInstrumentEnvelopeSetSustainLoopStart, _T("Set sustain loop start")},
  568. {1832, kcInstrumentEnvelopeSetSustainLoopEnd, _T("Set sustain loop end")},
  569. {1833, kcInstrumentEnvelopeToggleReleaseNode, _T("Toggle release node")},
  570. {1834, kcInstrumentEnvelopePointMoveUp8, _T("Move envelope point up (Coarse)")},
  571. {1835, kcInstrumentEnvelopePointMoveDown8, _T("Move envelope point down (Coarse)")},
  572. {1836, kcPatternEditPCNotePlugin, _T("Toggle PC Event/instrument plugin editor")},
  573. {1837, kcInstrumentEnvelopeZoomIn, _T("Zoom In")},
  574. {1838, kcInstrumentEnvelopeZoomOut, _T("Zoom Out")},
  575. {1839, kcVSTGUIToggleRecordParams, _T("Toggle Parameter Recording")},
  576. {1840, kcVSTGUIToggleSendKeysToPlug, _T("Pass Key Presses to Plugin")},
  577. {1841, kcVSTGUIBypassPlug, _T("Bypass Plugin")},
  578. {1842, kcInsNoteMapTransposeDown, _T("Transpose -1 (Note Map)")},
  579. {1843, kcInsNoteMapTransposeUp, _T("Transpose +1 (Note Map)")},
  580. {1844, kcInsNoteMapTransposeOctDown, _T("Transpose -1 Octave (Note Map)")},
  581. {1845, kcInsNoteMapTransposeOctUp, _T("Transpose +1 Octave (Note Map)")},
  582. {1846, kcInsNoteMapCopyCurrentNote, _T("Map all notes to selected note")},
  583. {1847, kcInsNoteMapCopyCurrentSample, _T("Map all notes to selected sample")},
  584. {1848, kcInsNoteMapReset, _T("Reset Note Mapping")},
  585. {1849, kcInsNoteMapEditSample, _T("Edit Current Sample")},
  586. {1850, kcInsNoteMapEditSampleMap, _T("Edit Sample Map")},
  587. {1851, kcInstrumentCtrlDuplicate, _T("Duplicate Instrument")},
  588. {1852, kcPanic, _T("Panic")},
  589. {1853, kcOrderlistPatIgnore, _T("Separator (+++) Index")},
  590. {1854, kcOrderlistPatInvalid, _T("Stop (---) Index")},
  591. {1855, kcViewEditHistory, _T("View Edit History")},
  592. {1856, kcSampleQuickFade, _T("Quick Fade")},
  593. {1857, kcSampleXFade, _T("Crossfade Sample Loop")},
  594. {1858, kcSelectBeat, _T("Select Beat")},
  595. {1859, kcSelectMeasure, _T("Select Measure")},
  596. {1860, kcFileSaveTemplate, _T("File/Save As Template")},
  597. {1861, kcIncreaseSpacing, _T("Increase Edit Step")},
  598. {1862, kcDecreaseSpacing, _T("Decrease Edit Step")},
  599. {1863, kcSampleAutotune, _T("Tune Sample to given Note")},
  600. {1864, kcFileCloseAll, _T("File/Close All")},
  601. {KeyCommand::Hidden, kcSetOctaveStop0, _T("")},
  602. {KeyCommand::Hidden, kcSetOctaveStop1, _T("")},
  603. {KeyCommand::Hidden, kcSetOctaveStop2, _T("")},
  604. {KeyCommand::Hidden, kcSetOctaveStop3, _T("")},
  605. {KeyCommand::Hidden, kcSetOctaveStop4, _T("")},
  606. {KeyCommand::Hidden, kcSetOctaveStop5, _T("")},
  607. {KeyCommand::Hidden, kcSetOctaveStop6, _T("")},
  608. {KeyCommand::Hidden, kcSetOctaveStop7, _T("")},
  609. {KeyCommand::Hidden, kcSetOctaveStop8, _T("")},
  610. {KeyCommand::Hidden, kcSetOctaveStop9, _T("")},
  611. {1875, kcOrderlistLockPlayback, _T("Lock Playback to Selection")},
  612. {1876, kcOrderlistUnlockPlayback, _T("Unlock Playback")},
  613. {1877, kcChannelSettings, _T("Quick Channel Settings")},
  614. {1878, kcChnSettingsPrev, _T("Previous Channel")},
  615. {1879, kcChnSettingsNext, _T("Next Channel")},
  616. {1880, kcChnSettingsClose, _T("Switch to Pattern Editor")},
  617. {1881, kcTransposeCustom, _T("Transpose Custom")},
  618. {1882, kcSampleZoomSelection, _T("Zoom into Selection")},
  619. {1883, kcChannelRecordSelect, _T("Channel Record Select")},
  620. {1884, kcChannelSplitRecordSelect, _T("Channel Split Record Select")},
  621. {1885, kcDataEntryUp, _T("Data Entry +1")},
  622. {1886, kcDataEntryDown, _T("Data Entry -1")},
  623. {1887, kcSample8Bit, _T("Convert to 8-bit / 16-bit")},
  624. {1888, kcSampleMonoMix, _T("Convert to Mono (Mix)")},
  625. {1889, kcSampleMonoLeft, _T("Convert to Mono (Left Channel)")},
  626. {1890, kcSampleMonoRight, _T("Convert to Mono (Right Channel)")},
  627. {1891, kcSampleMonoSplit, _T("Convert to Mono (Split Sample)")},
  628. {1892, kcQuantizeSettings, _T("Quantize Settings")},
  629. {1893, kcDataEntryUpCoarse, _T("Data Entry Up (Coarse)")},
  630. {1894, kcDataEntryDownCoarse, _T("Data Entry Down (Coarse)")},
  631. {1895, kcToggleNoteOffRecordPC, _T("Toggle Note Off record (PC keyboard)")},
  632. {1896, kcToggleNoteOffRecordMIDI, _T("Toggle Note Off record (MIDI)")},
  633. {1897, kcFindInstrument, _T("Pick up nearest instrument number")},
  634. {1898, kcPlaySongFromPattern, _T("Play Song from Pattern Start")},
  635. {1899, kcVSTGUIToggleRecordMIDIOut, _T("Record MIDI Out to Pattern Editor")},
  636. {1900, kcToggleClipboardManager, _T("Toggle Clipboard Manager")},
  637. {1901, kcClipboardPrev, _T("Cycle to Previous Clipboard")},
  638. {1902, kcClipboardNext, _T("Cycle to Next Clipboard")},
  639. {1903, kcSelectRow, _T("Select Row")},
  640. {1904, kcSelectEvent, _T("Select Event")},
  641. {1905, kcEditRedo, _T("Redo")},
  642. {1906, kcFileAppend, _T("File/Append Module")},
  643. {1907, kcSampleTransposeUp, _T("Transpose +1")},
  644. {1908, kcSampleTransposeDown, _T("Transpose -1")},
  645. {1909, kcSampleTransposeOctUp, _T("Transpose +1 Octave")},
  646. {1910, kcSampleTransposeOctDown, _T("Transpose -1 Octave")},
  647. {1911, kcPatternInterpolateInstr, _T("Interpolate Instrument")},
  648. {1912, kcDummyShortcut, _T("Dummy Shortcut")},
  649. {1913, kcSampleUpsample, _T("Upsample")},
  650. {1914, kcSampleDownsample, _T("Downsample")},
  651. {1915, kcSampleResample, _T("Resample")},
  652. {1916, kcSampleCenterLoopStart, _T("Center loop start in view")},
  653. {1917, kcSampleCenterLoopEnd, _T("Center loop end in view")},
  654. {1918, kcSampleCenterSustainStart, _T("Center sustain loop start in view")},
  655. {1919, kcSampleCenterSustainEnd, _T("Center sustain loop end in view")},
  656. {1920, kcInstrumentEnvelopeLoad, _T("Load Envelope")},
  657. {1921, kcInstrumentEnvelopeSave, _T("Save Envelope")},
  658. {1922, kcChannelTranspose, _T("Transpose Channel")},
  659. {1923, kcChannelDuplicate, _T("Duplicate Channel")},
  660. // Reserved range 1924...1949 for kcStartSampleCues...kcEndSampleCues (generated below)
  661. {1950, kcOrderlistEditCopyOrders, _T("Copy Orders")},
  662. {KeyCommand::Hidden, kcTreeViewStopPreview, _T("Stop sample preview")},
  663. {1952, kcSampleDuplicate, _T("Duplicate Sample")},
  664. {1953, kcSampleSlice, _T("Slice at cue points")},
  665. {1954, kcInstrumentEnvelopeScale, _T("Scale Envelope Points")},
  666. {1955, kcInsNoteMapRemove, _T("Remove All Samples")},
  667. {1956, kcInstrumentEnvelopeSelectLoopStart, _T("Select Envelope Loop Start")},
  668. {1957, kcInstrumentEnvelopeSelectLoopEnd, _T("Select Envelope Loop End")},
  669. {1958, kcInstrumentEnvelopeSelectSustainStart, _T("Select Envelope Sustain Start")},
  670. {1959, kcInstrumentEnvelopeSelectSustainEnd, _T("Select Envelope Sustain End")},
  671. {1960, kcInstrumentEnvelopePointMoveLeftCoarse, _T("Move envelope point left (Coarse)")},
  672. {1961, kcInstrumentEnvelopePointMoveRightCoarse, _T("Move envelope point right (Coarse)")},
  673. {1962, kcSampleCenterSampleStart, _T("Zoom into sample start")},
  674. {1963, kcSampleCenterSampleEnd, _T("Zoom into sample end")},
  675. {1964, kcSampleTrimToLoopEnd, _T("Trim to loop end")},
  676. {1965, kcLockPlaybackToRows, _T("Lock Playback to Rows")},
  677. {1966, kcSwitchToInstrLibrary, _T("Switch To Instrument Library")},
  678. {1967, kcPatternSetInstrumentNotEmpty, _T("Apply current instrument to existing only")},
  679. {1968, kcSelectColumn, _T("Select Column")},
  680. {1969, kcSampleStereoSep, _T("Change Stereo Separation")},
  681. {1970, kcTransposeCustomQuick, _T("Transpose Custom (Quick)")},
  682. {1971, kcPrevEntryInColumn, _T("Jump to previous entry in column")},
  683. {1972, kcNextEntryInColumn, _T("Jump to next entry in column")},
  684. {1973, kcViewTempoSwing, _T("View Global Tempo Swing Settings")},
  685. {1974, kcChordEditor, _T("Show Chord Editor")},
  686. {1975, kcToggleLoopSong, _T("Toggle Loop Song")},
  687. {1976, kcInstrumentEnvelopeSwitchToVolume, _T("Switch to Volume Envelope")},
  688. {1977, kcInstrumentEnvelopeSwitchToPanning, _T("Switch to Panning Envelope")},
  689. {1978, kcInstrumentEnvelopeSwitchToPitch, _T("Switch to Pitch / Filter Envelope")},
  690. {1979, kcInstrumentEnvelopeToggleVolume, _T("Toggle Volume Envelope")},
  691. {1980, kcInstrumentEnvelopeTogglePanning, _T("Toggle Panning Envelope")},
  692. {1981, kcInstrumentEnvelopeTogglePitch, _T("Toggle Pitch Envelope")},
  693. {1982, kcInstrumentEnvelopeToggleFilter, _T("Toggle Filter Envelope")},
  694. {1983, kcInstrumentEnvelopeToggleLoop, _T("Toggle Envelope Loop")},
  695. {1984, kcInstrumentEnvelopeToggleSustain, _T("Toggle Envelope Sustain Loop")},
  696. {1985, kcInstrumentEnvelopeToggleCarry, _T("Toggle Envelope Carry")},
  697. {1986, kcSampleInitializeOPL, _T("Initialize OPL Instrument")},
  698. {1987, kcFileSaveCopy, _T("File/Save Copy")},
  699. {1988, kcMergePatterns, _T("Merge Patterns")},
  700. {1989, kcSplitPattern, _T("Split Pattern")},
  701. {1990, kcSampleToggleDrawing, _T("Toggle Sample Drawing")},
  702. {1991, kcSampleResize, _T("Add Silence / Create Sample")},
  703. {1992, kcSampleGrid, _T("Configure Sample Grid")},
  704. {1993, kcLoseSelection, _T("Lose Selection")},
  705. {1994, kcCutPatternChannel, _T("Cut to Pattern Channel Clipboard")},
  706. {1995, kcCutPattern, _T("Cut to Pattern Clipboard")},
  707. {1996, kcCopyPatternChannel, _T("Copy to Pattern Channel Clipboard")},
  708. {1997, kcCopyPattern, _T("Copy to Pattern Clipboard")},
  709. {1998, kcPastePatternChannel, _T("Paste from Pattern Channel Clipboard")},
  710. {1999, kcPastePattern, _T("Paste from Pattern Clipboard")},
  711. {2000, kcToggleSmpInsList, _T("Toggle between lists")},
  712. {2001, kcExecuteSmpInsListItem, _T("Open item in editor")},
  713. {2002, kcDeleteRowGlobal, _T("Delete Row(s) (Global)")},
  714. {2003, kcDeleteWholeRowGlobal, _T("Delete Row(s) (All Channels, Global)")},
  715. {2004, kcInsertRowGlobal, _T("Insert Row(s) (Global)")},
  716. {2005, kcInsertWholeRowGlobal, _T("Insert Row(s) (All Channels, Global)")},
  717. {2006, kcPrevSequence, _T("Previous Sequence")},
  718. {2007, kcNextSequence, _T("Next Sequence")},
  719. {2008, kcChnColorFromPrev , _T("Pick Color from Previous Channel")},
  720. {2009, kcChnColorFromNext , _T("Pick Color from Next Channel") },
  721. {2010, kcChannelMoveLeft, _T("Move Channels to Left")},
  722. {2011, kcChannelMoveRight, _T("Move Channels to Right")},
  723. {2012, kcSampleConvertPingPongLoop, _T("Convert Ping-Pong Loop to Unidirectional") },
  724. {2013, kcSampleConvertPingPongSustain, _T("Convert Ping-Pong Sustain Loop to Unidirectional") },
  725. {2014, kcChannelAddBefore, _T("Add Channel Before Current")},
  726. {2015, kcChannelAddAfter, _T("Add Channel After Current") },
  727. {2016, kcChannelRemove, _T("Remove Channel") },
  728. {2017, kcSetFXFinetune, _T("Finetune") },
  729. {2018, kcSetFXFinetuneSmooth, _T("Finetune (Smooth)")},
  730. {2019, kcOrderlistEditInsertSeparator, _T("Insert Separator") },
  731. {2020, kcTempoIncrease, _T("Increase Tempo")},
  732. {2021, kcTempoDecrease, _T("Decrease Tempo")},
  733. {2022, kcTempoIncreaseFine, _T("Increase Tempo (Fine)")},
  734. {2023, kcTempoDecreaseFine, _T("Decrease Tempo (Fine)")},
  735. {2024, kcSpeedIncrease, _T("Increase Ticks per Row")},
  736. {2025, kcSpeedDecrease, _T("Decrease Ticks per Row")},
  737. {2026, kcRenameSmpInsListItem, _T("Rename Item")},
  738. {2027, kcShowChannelCtxMenu, _T("Show Channel Context (Right-Click) Menu")},
  739. {2028, kcShowChannelPluginCtxMenu, _T("Show Channel Plugin Context (Right-Click) Menu")},
  740. {2029, kcViewToggle, _T("Toggle Between Upper / Lower View") },
  741. {2030, kcFileSaveOPL, _T("File/Export OPL Register Dump") },
  742. {2031, kcSampleLoadRaw, _T("Load Raw Sample")},
  743. {2032, kcTogglePatternPlayRow, _T("Toggle row playback when navigating")},
  744. {2033, kcInsNoteMapTransposeSamples, _T("Transpose Samples / Reset Map") },
  745. {KeyCommand::Hidden, kcPrevEntryInColumnSelect, _T("kcPrevEntryInColumnSelect")},
  746. {KeyCommand::Hidden, kcNextEntryInColumnSelect, _T("kcNextEntryInColumnSelect")},
  747. };
  748. // Get command descriptions etc.. loaded up.
  749. void CCommandSet::SetupCommands()
  750. {
  751. for(const auto &def : CommandDefinitions)
  752. {
  753. m_commands[def.cmd] = {def.uid, def.description};
  754. }
  755. for(int j = kcStartSampleCues; j <= kcEndSampleCues; j++)
  756. {
  757. CString s = MPT_CFORMAT("Preview Sample Cue {}")(j - kcStartSampleCues + 1);
  758. m_commands[j] = {static_cast<uint32>(1924 + j - kcStartSampleCues), s};
  759. }
  760. static_assert(1924 + kcEndSampleCues - kcStartSampleCues < 1950);
  761. // Automatically generated note entry keys in non-pattern contexts
  762. for(const auto ctx : NoteContexts)
  763. {
  764. const auto contextStartNotes = std::get<1>(ctx);
  765. const auto contextStopNotes = std::get<2>(ctx);
  766. if(contextStartNotes == kcVPStartNotes)
  767. continue;
  768. for(int i = kcVPStartNotes; i <= kcVPEndNotes; i++)
  769. {
  770. m_commands[i - kcVPStartNotes + contextStartNotes] = {KeyCommand::Hidden, m_commands[i].Message};
  771. }
  772. for(int i = kcVPStartNoteStops; i <= kcVPEndNoteStops; i++)
  773. {
  774. m_commands[i - kcVPStartNoteStops + contextStopNotes] = {KeyCommand::Hidden, m_commands[i].Message};
  775. }
  776. }
  777. #ifdef MPT_BUILD_DEBUG
  778. // Ensure that every visible command has a unique ID
  779. for(size_t i = 0; i < kcNumCommands; i++)
  780. {
  781. if(m_commands[i].ID() != 0 || !m_commands[i].IsHidden())
  782. {
  783. for(size_t j = i + 1; j < kcNumCommands; j++)
  784. {
  785. if(m_commands[i].ID() == m_commands[j].ID())
  786. {
  787. LOG_COMMANDSET(MPT_UFORMAT("Duplicate or unset command UID: {}\n")(m_commands[i].ID()));
  788. MPT_ASSERT_NOTREACHED();
  789. }
  790. }
  791. }
  792. }
  793. #endif // MPT_BUILD_DEBUG
  794. }
  795. // Command Manipulation
  796. CString CCommandSet::Add(KeyCombination kc, CommandID cmd, bool overwrite, int pos, bool checkEventConflict)
  797. {
  798. auto &kcList = m_commands[cmd].kcList;
  799. // Avoid duplicate
  800. if(mpt::contains(kcList, kc))
  801. {
  802. return CString();
  803. }
  804. // Check that this keycombination isn't already assigned (in this context), except for dummy keys
  805. CString report;
  806. if(auto conflictCmd = IsConflicting(kc, cmd, checkEventConflict); conflictCmd.first != kcNull)
  807. {
  808. if (!overwrite)
  809. {
  810. return CString();
  811. } else
  812. {
  813. if (IsCrossContextConflict(kc, conflictCmd.second))
  814. {
  815. report += _T("The following commands may conflict:\r\n >") + GetCommandText(conflictCmd.first) + _T(" in ") + conflictCmd.second.GetContextText() + _T("\r\n >") + GetCommandText(cmd) + _T(" in ") + kc.GetContextText() + _T("\r\n\r\n");
  816. LOG_COMMANDSET(mpt::ToUnicode(report));
  817. } else
  818. {
  819. //if(!TrackerSettings::Instance().MiscAllowMultipleCommandsPerKey)
  820. // Remove(conflictCmd.second, conflictCmd.first);
  821. report += _T("The following commands in same context share the same key combination:\r\n >") + GetCommandText(conflictCmd.first) + _T(" in ") + conflictCmd.second.GetContextText() + _T("\r\n\r\n");
  822. LOG_COMMANDSET(mpt::ToUnicode(report));
  823. }
  824. }
  825. }
  826. kcList.insert((pos < 0) ? kcList.end() : (kcList.begin() + pos), kc);
  827. //enfore rules on CommandSet
  828. report += EnforceAll(kc, cmd, true);
  829. return report;
  830. }
  831. std::pair<CommandID, KeyCombination> CCommandSet::IsConflicting(KeyCombination kc, CommandID cmd, bool checkEventConflict) const
  832. {
  833. if(m_commands[cmd].IsDummy()) // no need to search if we are adding a dummy key
  834. return {kcNull, KeyCombination()};
  835. for(int pass = 0; pass < 2; pass++)
  836. {
  837. // In the first pass, only look for conflicts in the same context, since
  838. // such conflicts are errors. Cross-context conflicts only emit warnings.
  839. for(int curCmd = 0; curCmd < kcNumCommands; curCmd++)
  840. {
  841. if(m_commands[curCmd].IsDummy())
  842. continue;
  843. for(auto &curKc : m_commands[curCmd].kcList)
  844. {
  845. if(pass == 0 && curKc.Context() != kc.Context())
  846. continue;
  847. if(KeyCombinationConflict(curKc, kc, checkEventConflict))
  848. {
  849. return {(CommandID)curCmd, curKc};
  850. }
  851. }
  852. }
  853. }
  854. return std::make_pair(kcNull, KeyCombination());
  855. }
  856. CString CCommandSet::Remove(int pos, CommandID cmd)
  857. {
  858. if (pos>=0 && (size_t)pos<m_commands[cmd].kcList.size())
  859. {
  860. return Remove(m_commands[cmd].kcList[pos], cmd);
  861. }
  862. LOG_COMMANDSET(U_("Failed to remove a key: keychoice out of range."));
  863. return _T("");
  864. }
  865. CString CCommandSet::Remove(KeyCombination kc, CommandID cmd)
  866. {
  867. auto &kcList = m_commands[cmd].kcList;
  868. auto index = std::find(kcList.begin(), kcList.end(), kc);
  869. if (index != kcList.end())
  870. {
  871. kcList.erase(index);
  872. LOG_COMMANDSET(U_("Removed a key"));
  873. return EnforceAll(kc, cmd, false);
  874. } else
  875. {
  876. LOG_COMMANDSET(U_("Failed to remove a key as it was not found"));
  877. return CString();
  878. }
  879. }
  880. CString CCommandSet::EnforceAll(KeyCombination inKc, CommandID inCmd, bool adding)
  881. {
  882. //World's biggest, most confusing method. :)
  883. //Needs refactoring. Maybe make lots of Rule subclasses, each with their own Enforce() method?
  884. KeyCombination curKc; // for looping through key combinations
  885. KeyCombination newKc; // for adding new key combinations
  886. CString report;
  887. if(m_enforceRule[krAllowNavigationWithSelection])
  888. {
  889. // When we get a new navigation command key, we need to
  890. // make sure this navigation will work when any selection key is pressed
  891. if(inCmd >= kcStartPatNavigation && inCmd <= kcEndPatNavigation)
  892. {//Check that it is a nav cmd
  893. CommandID cmdNavSelection = (CommandID)(kcStartPatNavigationSelect + (inCmd-kcStartPatNavigation));
  894. for(auto &kc :m_commands[kcSelect].kcList)
  895. {//for all selection modifiers
  896. newKc = inKc;
  897. newKc.Modifier(kc); //Add selection modifier's modifiers to this command
  898. if(adding)
  899. {
  900. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - adding key with modifier:{} to command: {}")(newKc.Modifier().GetRaw(), cmdNavSelection));
  901. Add(newKc, cmdNavSelection, false);
  902. } else
  903. {
  904. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - removing key with modifier:{} to command: {}")(newKc.Modifier().GetRaw(), cmdNavSelection));
  905. Remove(newKc, cmdNavSelection);
  906. }
  907. }
  908. }
  909. // Same applies for orderlist navigation
  910. else if(inCmd >= kcStartOrderlistNavigation && inCmd <= kcEndOrderlistNavigation)
  911. {//Check that it is a nav cmd
  912. CommandID cmdNavSelection = (CommandID)(kcStartOrderlistNavigationSelect+ (inCmd-kcStartOrderlistNavigation));
  913. for(auto &kc : m_commands[kcSelect].kcList)
  914. {//for all selection modifiers
  915. newKc = inKc;
  916. newKc.AddModifier(kc); //Add selection modifier's modifiers to this command
  917. if(adding)
  918. {
  919. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - adding key with modifier:{} to command: {}")(newKc.Modifier().GetRaw(), cmdNavSelection));
  920. Add(newKc, cmdNavSelection, false);
  921. } else
  922. {
  923. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - removing key with modifier:{} to command: {}")(newKc.Modifier().GetRaw(), cmdNavSelection));
  924. Remove(newKc, cmdNavSelection);
  925. }
  926. }
  927. }
  928. // When we get a new selection key, we need to make sure that
  929. // all navigation commands will work with this selection key pressed
  930. else if(inCmd == kcSelect)
  931. {
  932. // check that is is a selection
  933. for(int curCmd=kcStartPatNavigation; curCmd<=kcEndPatNavigation; curCmd++)
  934. {
  935. // for all nav commands
  936. for(auto &kc : m_commands[curCmd].kcList)
  937. {
  938. // for all keys for this command
  939. CommandID cmdNavSelection = (CommandID)(kcStartPatNavigationSelect + (curCmd-kcStartPatNavigation));
  940. newKc = kc; // get all properties from the current nav cmd key
  941. newKc.AddModifier(inKc); // and the new selection modifier
  942. if(adding)
  943. {
  944. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - adding key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), cmdNavSelection));
  945. Add(newKc, cmdNavSelection, false);
  946. } else
  947. {
  948. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - removing key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), cmdNavSelection));
  949. Remove(newKc, cmdNavSelection);
  950. }
  951. }
  952. } // end all nav commands
  953. for(int curCmd = kcStartOrderlistNavigation; curCmd <= kcEndOrderlistNavigation; curCmd++)
  954. {// for all nav commands
  955. for(auto &kc : m_commands[curCmd].kcList)
  956. {// for all keys for this command
  957. CommandID cmdNavSelection = (CommandID)(kcStartOrderlistNavigationSelect+ (curCmd-kcStartOrderlistNavigation));
  958. newKc = kc; // get all properties from the current nav cmd key
  959. newKc.AddModifier(inKc); // and the new selection modifier
  960. if(adding)
  961. {
  962. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - adding key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), cmdNavSelection));
  963. Add(newKc, cmdNavSelection, false);
  964. } else
  965. {
  966. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowNavigationWithSelection - removing key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), cmdNavSelection));
  967. Remove(newKc, cmdNavSelection);
  968. }
  969. }
  970. } // end all nav commands
  971. }
  972. } // end krAllowNavigationWithSelection
  973. if(m_enforceRule[krAllowSelectionWithNavigation])
  974. {
  975. KeyCombination newKcSel;
  976. // When we get a new navigation command key, we need to ensure
  977. // all selection keys will work even when this new selection key is pressed
  978. if(inCmd >= kcStartPatNavigation && inCmd <= kcEndPatNavigation)
  979. {//if this is a navigation command
  980. for(auto &kc : m_commands[kcSelect].kcList)
  981. {//for all deselection modifiers
  982. newKcSel = kc; // get all properties from the selection key
  983. newKcSel.AddModifier(inKc); // add modifiers from the new nav command
  984. if(adding)
  985. {
  986. LOG_COMMANDSET(U_("Enforcing rule krAllowSelectionWithNavigation: adding removing kcSelectWithNav and kcSelectOffWithNav"));
  987. Add(newKcSel, kcSelectWithNav, false);
  988. } else
  989. {
  990. LOG_COMMANDSET(U_("Enforcing rule krAllowSelectionWithNavigation: removing kcSelectWithNav and kcSelectOffWithNav"));
  991. Remove(newKcSel, kcSelectWithNav);
  992. }
  993. }
  994. }
  995. // Same for orderlist navigation
  996. if(inCmd >= kcStartOrderlistNavigation && inCmd <= kcEndOrderlistNavigation)
  997. {//if this is a navigation command
  998. for(auto &kc : m_commands[kcSelect].kcList)
  999. {//for all deselection modifiers
  1000. newKcSel = kc; // get all properties from the selection key
  1001. newKcSel.AddModifier(inKc); // add modifiers from the new nav command
  1002. if(adding)
  1003. {
  1004. LOG_COMMANDSET(U_("Enforcing rule krAllowSelectionWithNavigation: adding removing kcSelectWithNav and kcSelectOffWithNav"));
  1005. Add(newKcSel, kcSelectWithNav, false);
  1006. } else
  1007. {
  1008. LOG_COMMANDSET(U_("Enforcing rule krAllowSelectionWithNavigation: removing kcSelectWithNav and kcSelectOffWithNav"));
  1009. Remove(newKcSel, kcSelectWithNav);
  1010. }
  1011. }
  1012. }
  1013. // When we get a new selection key, we need to ensure it will work even when
  1014. // any navigation key is pressed
  1015. else if(inCmd == kcSelect)
  1016. {
  1017. for(int curCmd = kcStartPatNavigation; curCmd <= kcEndPatNavigation; curCmd++)
  1018. {//for all nav commands
  1019. for(auto &kc : m_commands[curCmd].kcList)
  1020. {// for all keys for this command
  1021. newKcSel = inKc; // get all properties from the selection key
  1022. newKcSel.AddModifier(kc); //add the nav keys' modifiers
  1023. if(adding)
  1024. {
  1025. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowSelectionWithNavigation - adding key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), kcSelectWithNav));
  1026. Add(newKcSel, kcSelectWithNav, false);
  1027. } else
  1028. {
  1029. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowSelectionWithNavigation - removing key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), kcSelectWithNav));
  1030. Remove(newKcSel, kcSelectWithNav);
  1031. }
  1032. }
  1033. } // end all nav commands
  1034. for(int curCmd = kcStartOrderlistNavigation; curCmd <= kcEndOrderlistNavigation; curCmd++)
  1035. {//for all nav commands
  1036. for(auto &kc : m_commands[curCmd].kcList)
  1037. {// for all keys for this command
  1038. newKcSel=inKc; // get all properties from the selection key
  1039. newKcSel.AddModifier(kc); //add the nav keys' modifiers
  1040. if(adding)
  1041. {
  1042. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowSelectionWithNavigation - adding key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), kcSelectWithNav));
  1043. Add(newKcSel, kcSelectWithNav, false);
  1044. } else
  1045. {
  1046. LOG_COMMANDSET(MPT_UFORMAT("Enforcing rule krAllowSelectionWithNavigation - removing key:{} with modifier:{} to command: {}")(curCmd, inKc.Modifier().GetRaw(), kcSelectWithNav));
  1047. Remove(newKcSel, kcSelectWithNav);
  1048. }
  1049. }
  1050. } // end all nav commands
  1051. }
  1052. }
  1053. // if we add a selector or a copy selector, we need it to switch off when we release the key.
  1054. if (m_enforceRule[krAutoSelectOff])
  1055. {
  1056. KeyCombination newKcDeSel;
  1057. CommandID cmdOff = kcNull;
  1058. switch (inCmd)
  1059. {
  1060. case kcSelect: cmdOff = kcSelectOff; break;
  1061. case kcSelectWithNav: cmdOff = kcSelectOffWithNav; break;
  1062. case kcCopySelect: cmdOff = kcCopySelectOff; break;
  1063. case kcCopySelectWithNav: cmdOff = kcCopySelectOffWithNav; break;
  1064. case kcSelectWithCopySelect: cmdOff = kcSelectOffWithCopySelect; break;
  1065. case kcCopySelectWithSelect: cmdOff = kcCopySelectOffWithSelect; break;
  1066. }
  1067. if(cmdOff != kcNull)
  1068. {
  1069. newKcDeSel = inKc;
  1070. newKcDeSel.EventType(kKeyEventUp);
  1071. // Register key-up when releasing any of the modifiers.
  1072. // Otherwise, select key combos might get stuck. Example:
  1073. // [Ctrl Down] [Alt Down] [Ctrl Up] [Alt Up] After this action, copy select (Ctrl+Drag) would still be activated without this code.
  1074. const UINT maxMod = TrackerSettings::Instance().MiscDistinguishModifiers ? MaxMod : (MaxMod & ~(HOTKEYF_RSHIFT | HOTKEYF_RCONTROL | HOTKEYF_RALT));
  1075. for(UINT i = 0; i <= maxMod; i++)
  1076. {
  1077. // Avoid Windows key, so that it won't detected as being actively used
  1078. if(i & HOTKEYF_EXT)
  1079. continue;
  1080. newKcDeSel.Modifier(static_cast<Modifiers>(i));
  1081. //newKcDeSel.mod&=~CodeToModifier(inKc.code); //<-- Need to get rid of right modifier!!
  1082. if (adding)
  1083. Add(newKcDeSel, cmdOff, false);
  1084. else
  1085. Remove(newKcDeSel, cmdOff);
  1086. }
  1087. }
  1088. }
  1089. // Allow combinations of copyselect and select
  1090. if(m_enforceRule[krAllowSelectCopySelectCombos])
  1091. {
  1092. KeyCombination newKcSel, newKcCopySel;
  1093. if(inCmd==kcSelect)
  1094. {
  1095. // On getting a new selection key, make this selection key work with all copy selects' modifiers
  1096. // On getting a new selection key, make all copyselects work with this key's modifiers
  1097. for(auto &kc : m_commands[kcCopySelect].kcList)
  1098. {
  1099. newKcSel=inKc;
  1100. newKcSel.AddModifier(kc);
  1101. newKcCopySel = kc;
  1102. newKcCopySel.AddModifier(inKc);
  1103. LOG_COMMANDSET(U_("Enforcing rule krAllowSelectCopySelectCombos"));
  1104. if(adding)
  1105. {
  1106. Add(newKcSel, kcSelectWithCopySelect, false);
  1107. Add(newKcCopySel, kcCopySelectWithSelect, false);
  1108. } else
  1109. {
  1110. Remove(newKcSel, kcSelectWithCopySelect);
  1111. Remove(newKcCopySel, kcCopySelectWithSelect);
  1112. }
  1113. }
  1114. }
  1115. if(inCmd == kcCopySelect)
  1116. {
  1117. // On getting a new copyselection key, make this copyselection key work with all selects' modifiers
  1118. // On getting a new copyselection key, make all selects work with this key's modifiers
  1119. for(auto &kc : m_commands[kcSelect].kcList)
  1120. {
  1121. newKcSel = kc;
  1122. newKcSel.AddModifier(inKc);
  1123. newKcCopySel = inKc;
  1124. newKcCopySel.AddModifier(kc);
  1125. LOG_COMMANDSET(U_("Enforcing rule krAllowSelectCopySelectCombos"));
  1126. if(adding)
  1127. {
  1128. Add(newKcSel, kcSelectWithCopySelect, false);
  1129. Add(newKcCopySel, kcCopySelectWithSelect, false);
  1130. } else
  1131. {
  1132. Remove(newKcSel, kcSelectWithCopySelect);
  1133. Remove(newKcCopySel, kcCopySelectWithSelect);
  1134. }
  1135. }
  1136. }
  1137. }
  1138. // Lock Notes to Chords
  1139. if (m_enforceRule[krLockNotesToChords])
  1140. {
  1141. if (inCmd>=kcVPStartNotes && inCmd<=kcVPEndNotes)
  1142. {
  1143. int noteOffset = inCmd - kcVPStartNotes;
  1144. for(auto &kc : m_commands[kcChordModifier].kcList)
  1145. {//for all chord modifier keys
  1146. newKc = inKc;
  1147. newKc.AddModifier(kc);
  1148. if (adding)
  1149. {
  1150. LOG_COMMANDSET(U_("Enforcing rule krLockNotesToChords: auto adding in a chord command"));
  1151. Add(newKc, (CommandID)(kcVPStartChords+noteOffset), false);
  1152. }
  1153. else
  1154. {
  1155. LOG_COMMANDSET(U_("Enforcing rule krLockNotesToChords: auto removing a chord command"));
  1156. Remove(newKc, (CommandID)(kcVPStartChords+noteOffset));
  1157. }
  1158. }
  1159. }
  1160. if (inCmd==kcChordModifier)
  1161. {
  1162. int noteOffset;
  1163. for (int curCmd=kcVPStartNotes; curCmd<=kcVPEndNotes; curCmd++)
  1164. {//for all notes
  1165. for(auto kc : m_commands[curCmd].kcList)
  1166. {//for all keys for this note
  1167. noteOffset = curCmd - kcVPStartNotes;
  1168. kc.AddModifier(inKc);
  1169. if (adding)
  1170. {
  1171. LOG_COMMANDSET(U_("Enforcing rule krLockNotesToChords: auto adding in a chord command"));
  1172. Add(kc, (CommandID)(kcVPStartChords+noteOffset), false);
  1173. }
  1174. else
  1175. {
  1176. LOG_COMMANDSET(U_("Enforcing rule krLockNotesToChords: auto removing a chord command"));
  1177. Remove(kc, (CommandID)(kcVPStartChords+noteOffset));
  1178. }
  1179. }
  1180. }
  1181. }
  1182. }
  1183. // Auto set note off on release
  1184. if (m_enforceRule[krNoteOffOnKeyRelease])
  1185. {
  1186. if (inCmd>=kcVPStartNotes && inCmd<=kcVPEndNotes)
  1187. {
  1188. int noteOffset = inCmd - kcVPStartNotes;
  1189. newKc=inKc;
  1190. newKc.EventType(kKeyEventUp);
  1191. if (adding)
  1192. {
  1193. LOG_COMMANDSET(U_("Enforcing rule krNoteOffOnKeyRelease: adding note off command"));
  1194. Add(newKc, (CommandID)(kcVPStartNoteStops+noteOffset), false);
  1195. }
  1196. else
  1197. {
  1198. LOG_COMMANDSET(U_("Enforcing rule krNoteOffOnKeyRelease: removing note off command"));
  1199. Remove(newKc, (CommandID)(kcVPStartNoteStops+noteOffset));
  1200. }
  1201. }
  1202. if (inCmd>=kcVPStartChords && inCmd<=kcVPEndChords)
  1203. {
  1204. int noteOffset = inCmd - kcVPStartChords;
  1205. newKc=inKc;
  1206. newKc.EventType(kKeyEventUp);
  1207. if (adding)
  1208. {
  1209. LOG_COMMANDSET(U_("Enforcing rule krNoteOffOnKeyRelease: adding Chord off command"));
  1210. Add(newKc, (CommandID)(kcVPStartChordStops+noteOffset), false);
  1211. }
  1212. else
  1213. {
  1214. LOG_COMMANDSET(U_("Enforcing rule krNoteOffOnKeyRelease: removing Chord off command"));
  1215. Remove(newKc, (CommandID)(kcVPStartChordStops+noteOffset));
  1216. }
  1217. }
  1218. if(inCmd >= kcSetOctave0 && inCmd <= kcSetOctave9)
  1219. {
  1220. int noteOffset = inCmd - kcSetOctave0;
  1221. newKc=inKc;
  1222. newKc.EventType(kKeyEventUp);
  1223. if (adding)
  1224. {
  1225. LOG_COMMANDSET(U_("Enforcing rule krNoteOffOnKeyRelease: adding Chord off command"));
  1226. Add(newKc, (CommandID)(kcSetOctaveStop0+noteOffset), false);
  1227. }
  1228. else
  1229. {
  1230. LOG_COMMANDSET(U_("Enforcing rule krNoteOffOnKeyRelease: removing Chord off command"));
  1231. Remove(newKc, (CommandID)(kcSetOctaveStop0+noteOffset));
  1232. }
  1233. }
  1234. }
  1235. // Reassign freed number keys to octaves
  1236. if (m_enforceRule[krReassignDigitsToOctaves] && !adding)
  1237. {
  1238. if ( (inKc.Modifier() == ModNone) && //no modifier
  1239. ( (inKc.Context() == kCtxViewPatternsNote) || (inKc.Context() == kCtxViewPatterns) ) && //note scope or pattern scope
  1240. ( ('0'<=inKc.KeyCode() && inKc.KeyCode()<='9') || (VK_NUMPAD0<=inKc.KeyCode() && inKc.KeyCode()<=VK_NUMPAD9) ) ) //is number key
  1241. {
  1242. newKc = KeyCombination(kCtxViewPatternsNote, ModNone, inKc.KeyCode(), kKeyEventDown);
  1243. int offset = ('0'<=inKc.KeyCode() && inKc.KeyCode()<='9') ? newKc.KeyCode()-'0' : newKc.KeyCode()-VK_NUMPAD0;
  1244. Add(newKc, (CommandID)(kcSetOctave0 + (newKc.KeyCode()-offset)), false);
  1245. }
  1246. }
  1247. // Add spacing
  1248. if (m_enforceRule[krAutoSpacing])
  1249. {
  1250. if (inCmd == kcSetSpacing && adding)
  1251. {
  1252. newKc = KeyCombination(kCtxViewPatterns, inKc.Modifier(), 0, kKeyEventDown);
  1253. for (char i = 0; i <= 9; i++)
  1254. {
  1255. newKc.KeyCode('0' + i);
  1256. Add(newKc, (CommandID)(kcSetSpacing0 + i), false);
  1257. newKc.KeyCode(VK_NUMPAD0 + i);
  1258. Add(newKc, (CommandID)(kcSetSpacing0 + i), false);
  1259. }
  1260. }
  1261. else if (!adding && (inCmd < kcSetSpacing || inCmd > kcSetSpacing9))
  1262. {
  1263. // Re-add combinations that might have been overwritten by another command
  1264. if(('0' <= inKc.KeyCode() && inKc.KeyCode() <= '9') || (VK_NUMPAD0 <= inKc.KeyCode() && inKc.KeyCode() <= VK_NUMPAD9))
  1265. {
  1266. for(const auto &spacing : m_commands[kcSetSpacing].kcList)
  1267. {
  1268. newKc = KeyCombination(kCtxViewPatterns, spacing.Modifier(), inKc.KeyCode(), spacing.EventType());
  1269. if('0' <= inKc.KeyCode() && inKc.KeyCode() <= '9')
  1270. Add(newKc, (CommandID)(kcSetSpacing0 + inKc.KeyCode() - '0'), false);
  1271. else if(VK_NUMPAD0 <= inKc.KeyCode() && inKc.KeyCode() <= VK_NUMPAD9)
  1272. Add(newKc, (CommandID)(kcSetSpacing0 + inKc.KeyCode() - VK_NUMPAD0), false);
  1273. }
  1274. }
  1275. }
  1276. }
  1277. if (m_enforceRule[krPropagateNotes])
  1278. {
  1279. if((inCmd >= kcVPStartNotes && inCmd <= kcVPEndNotes) || (inCmd >= kcVPStartNoteStops && inCmd <= kcVPEndNoteStops))
  1280. {
  1281. const bool areNoteStarts = (inCmd >= kcVPStartNotes && inCmd <= kcVPEndNotes);
  1282. const auto startNote = areNoteStarts ? kcVPStartNotes : kcVPStartNoteStops;
  1283. const auto noteOffset = inCmd - startNote;
  1284. for(const auto ctx : NoteContexts)
  1285. {
  1286. const auto context = std::get<0>(ctx);
  1287. const auto contextStartNote = areNoteStarts ? std::get<1>(ctx) : std::get<2>(ctx);
  1288. if(contextStartNote == startNote)
  1289. continue;
  1290. newKc = inKc;
  1291. newKc.Context(context);
  1292. if(adding)
  1293. {
  1294. LOG_COMMANDSET(U_("Enforcing rule krPropagateNotes: adding Note on/off"));
  1295. Add(newKc, static_cast<CommandID>(contextStartNote + noteOffset), false);
  1296. } else
  1297. {
  1298. LOG_COMMANDSET(U_("Enforcing rule krPropagateNotes: removing Note on/off"));
  1299. Remove(newKc, static_cast<CommandID>(contextStartNote + noteOffset));
  1300. }
  1301. }
  1302. } else if(inCmd == kcNoteCut || inCmd == kcNoteOff || inCmd == kcNoteFade)
  1303. {
  1304. // Stop preview in instrument browser
  1305. KeyCombination newKcTree = inKc;
  1306. newKcTree.Context(kCtxViewTree);
  1307. if(adding)
  1308. {
  1309. Add(newKcTree, kcTreeViewStopPreview, false);
  1310. } else
  1311. {
  1312. Remove(newKcTree, kcTreeViewStopPreview);
  1313. }
  1314. }
  1315. }
  1316. if (m_enforceRule[krCheckModifiers])
  1317. {
  1318. // for all commands that must be modifiers
  1319. for (auto curCmd : { kcSelect, kcCopySelect, kcChordModifier, kcSetSpacing })
  1320. {
  1321. //for all of this command's key combinations
  1322. for (auto &kc : m_commands[curCmd].kcList)
  1323. {
  1324. if ((!kc.Modifier()) || (kc.KeyCode()!=VK_SHIFT && kc.KeyCode()!=VK_CONTROL && kc.KeyCode()!=VK_MENU && kc.KeyCode()!=0 &&
  1325. kc.KeyCode()!=VK_LWIN && kc.KeyCode()!=VK_RWIN )) // Feature: use Windows keys as modifier keys
  1326. {
  1327. report += _T("Error! ") + GetCommandText((CommandID)curCmd) + _T(" must be a modifier (shift/ctrl/alt), but is currently ") + inKc.GetKeyText() + _T("\r\n");
  1328. //replace with dummy
  1329. kc.Modifier(ModShift);
  1330. kc.KeyCode(0);
  1331. kc.EventType(kKeyEventNone);
  1332. }
  1333. }
  1334. }
  1335. }
  1336. if (m_enforceRule[krPropagateSampleManipulation])
  1337. {
  1338. static constexpr CommandID propagateCmds[] = {kcSampleLoad, kcSampleSave, kcSampleNew};
  1339. static constexpr CommandID translatedCmds[] = {kcInstrumentLoad, kcInstrumentSave, kcInstrumentNew};
  1340. if(const auto propCmd = std::find(std::begin(propagateCmds), std::end(propagateCmds), inCmd); propCmd != std::end(propagateCmds))
  1341. {
  1342. //propagate to InstrumentView
  1343. const auto newCmd = translatedCmds[std::distance(std::begin(propagateCmds), propCmd)];
  1344. m_commands[newCmd].kcList.reserve(m_commands[inCmd].kcList.size());
  1345. for(auto kc : m_commands[inCmd].kcList)
  1346. {
  1347. kc.Context(kCtxViewInstruments);
  1348. m_commands[newCmd].kcList.push_back(kc);
  1349. }
  1350. }
  1351. }
  1352. /* if (enforceRule[krFoldEffectColumnAnd])
  1353. {
  1354. if (inKc.ctx == kCtxViewPatternsFX) {
  1355. KeyCombination newKc = inKc;
  1356. newKc.ctx = kCtxViewPatternsFXparam;
  1357. if (adding) {
  1358. Add(newKc, inCmd, false);
  1359. } else {
  1360. Remove(newKc, inCmd);
  1361. }
  1362. }
  1363. if (inKc.ctx == kCtxViewPatternsFXparam) {
  1364. KeyCombination newKc = inKc;
  1365. newKc.ctx = kCtxViewPatternsFX;
  1366. if (adding) {
  1367. Add(newKc, inCmd, false);
  1368. } else {
  1369. Remove(newKc, inCmd);
  1370. }
  1371. }
  1372. }
  1373. */
  1374. return report;
  1375. }
  1376. //Generate a keymap from a command set
  1377. void CCommandSet::GenKeyMap(KeyMap &km)
  1378. {
  1379. std::vector<KeyEventType> eventTypes;
  1380. std::vector<InputTargetContext> contexts;
  1381. km.clear();
  1382. const bool allowDupes = TrackerSettings::Instance().MiscAllowMultipleCommandsPerKey;
  1383. // Copy commandlist content into map:
  1384. for(UINT cmd = 0; cmd < kcNumCommands; cmd++)
  1385. {
  1386. if(m_commands[cmd].IsDummy())
  1387. continue;
  1388. for(auto curKc : m_commands[cmd].kcList)
  1389. {
  1390. eventTypes.clear();
  1391. contexts.clear();
  1392. // Handle keyEventType mask.
  1393. if(curKc.EventType() & kKeyEventDown)
  1394. eventTypes.push_back(kKeyEventDown);
  1395. if(curKc.EventType() & kKeyEventUp)
  1396. eventTypes.push_back(kKeyEventUp);
  1397. if(curKc.EventType() & kKeyEventRepeat)
  1398. eventTypes.push_back(kKeyEventRepeat);
  1399. //ASSERT(eventTypes.GetSize()>0);
  1400. // Handle super-contexts (contexts that represent a set of sub contexts)
  1401. if(curKc.Context() == kCtxViewPatterns)
  1402. contexts.insert(contexts.end(), {kCtxViewPatternsNote, kCtxViewPatternsIns, kCtxViewPatternsVol, kCtxViewPatternsFX, kCtxViewPatternsFXparam});
  1403. else if(curKc.Context() == kCtxCtrlPatterns)
  1404. contexts.push_back(kCtxCtrlOrderlist);
  1405. else
  1406. contexts.push_back(curKc.Context());
  1407. for(auto ctx : contexts)
  1408. {
  1409. for(auto event : eventTypes)
  1410. {
  1411. KeyCombination kc(ctx, curKc.Modifier(), curKc.KeyCode(), event);
  1412. if(!allowDupes)
  1413. {
  1414. KeyMapRange dupes = km.equal_range(kc);
  1415. km.erase(dupes.first, dupes.second);
  1416. }
  1417. km.insert(std::make_pair(kc, static_cast<CommandID>(cmd)));
  1418. }
  1419. }
  1420. }
  1421. }
  1422. }
  1423. void CCommandSet::Copy(const CCommandSet *source)
  1424. {
  1425. m_oldSpecs = nullptr;
  1426. std::copy(std::begin(source->m_commands), std::end(source->m_commands), std::begin(m_commands));
  1427. }
  1428. // Export
  1429. bool CCommandSet::SaveFile(const mpt::PathString &filename)
  1430. {
  1431. /* Layout:
  1432. //----( Context1 Text (id) )----
  1433. ctx:UID:Description:Modifier:Key:EventMask
  1434. ctx:UID:Description:Modifier:Key:EventMask
  1435. ...
  1436. //----( Context2 Text (id) )----
  1437. ...
  1438. */
  1439. mpt::SafeOutputFile sf(filename, std::ios::out, mpt::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave));
  1440. mpt::ofstream& f = sf;
  1441. if(!f)
  1442. {
  1443. ErrorBox(IDS_CANT_OPEN_FILE_FOR_WRITING);
  1444. return false;
  1445. }
  1446. f << "//----------------- OpenMPT key binding definition file ---------------\n"
  1447. "//- Format is: -\n"
  1448. "//- Context:Command ID:Modifiers:Key:KeypressEventType //Comments -\n"
  1449. "//----------------------------------------------------------------------\n"
  1450. "version:" << KEYMAP_VERSION << "\n";
  1451. std::vector<HKL> layouts(GetKeyboardLayoutList(0, nullptr));
  1452. GetKeyboardLayoutList(static_cast<int>(layouts.size()), layouts.data());
  1453. for(int ctx = 0; ctx < kCtxMaxInputContexts; ctx++)
  1454. {
  1455. f << "\n//----( " << mpt::ToCharset(mpt::Charset::UTF8, KeyCombination::GetContextText((InputTargetContext)ctx)) << " )------------\n";
  1456. for(int cmd = kcFirst; cmd < kcNumCommands; cmd++)
  1457. {
  1458. if(m_commands[cmd].IsHidden())
  1459. continue;
  1460. for(const auto kc : m_commands[cmd].kcList)
  1461. {
  1462. if(kc.Context() != ctx)
  1463. continue; // Sort by context
  1464. f << ctx << ":"
  1465. << m_commands[cmd].ID() << ":"
  1466. << static_cast<int>(kc.Modifier().GetRaw()) << ":"
  1467. << kc.KeyCode();
  1468. if(cmd >= kcVPStartNotes && cmd <= kcVPEndNotes)
  1469. {
  1470. UINT sc = 0, vk = kc.KeyCode();
  1471. for(auto i = layouts.begin(); i != layouts.end() && sc == 0; i++)
  1472. {
  1473. sc = MapVirtualKeyEx(vk, MAPVK_VK_TO_VSC, *i);
  1474. }
  1475. f << "/" << sc;
  1476. }
  1477. f << ":"
  1478. << static_cast<int>(kc.EventType().GetRaw()) << "\t\t//"
  1479. << mpt::ToCharset(mpt::Charset::UTF8, GetCommandText((CommandID)cmd)) << ": "
  1480. << mpt::ToCharset(mpt::Charset::UTF8, kc.GetKeyText()) << " ("
  1481. << mpt::ToCharset(mpt::Charset::UTF8, kc.GetKeyEventText()) << ")\n";
  1482. }
  1483. }
  1484. }
  1485. return true;
  1486. }
  1487. static std::string GetDefaultKeymap()
  1488. {
  1489. return mpt::make_basic_string(mpt::byte_cast<mpt::span<const char>>(GetResource(MAKEINTRESOURCE(IDR_DEFAULT_KEYBINDINGS), TEXT("KEYBINDINGS"))));
  1490. }
  1491. bool CCommandSet::LoadFile(std::istream &iStrm, const mpt::ustring &filenameDescription, const bool fillExistingSet)
  1492. {
  1493. KeyCombination kc;
  1494. char s[1024];
  1495. std::string curLine;
  1496. std::vector<std::string> tokens;
  1497. int l = 0;
  1498. m_oldSpecs = nullptr; // After clearing the key set, need to fix effect letters
  1499. if(!fillExistingSet)
  1500. {
  1501. for(auto &cmd : m_commands)
  1502. cmd.kcList.clear();
  1503. }
  1504. CString errText;
  1505. int errorCount = 0;
  1506. std::vector<HKL> layouts(GetKeyboardLayoutList(0, nullptr));
  1507. GetKeyboardLayoutList(static_cast<int>(layouts.size()), layouts.data());
  1508. const std::string whitespace(" \n\r\t");
  1509. while(iStrm.getline(s, std::size(s)))
  1510. {
  1511. curLine = s;
  1512. l++;
  1513. // Cut everything after a //, trim whitespace
  1514. auto pos = curLine.find("//");
  1515. if(pos != std::string::npos)
  1516. curLine.resize(pos);
  1517. pos = curLine.find_first_not_of(whitespace);
  1518. if(pos == std::string::npos)
  1519. continue;
  1520. curLine.erase(0, pos);
  1521. pos = curLine.find_last_not_of(whitespace);
  1522. if(pos != std::string::npos)
  1523. curLine.resize(pos + 1);
  1524. if (curLine.empty())
  1525. continue;
  1526. tokens = mpt::String::Split<std::string>(curLine, ":");
  1527. if(tokens.size() == 2 && !mpt::CompareNoCaseAscii(tokens[0], "version"))
  1528. {
  1529. // This line indicates the version of this keymap file (e.g. "version:1")
  1530. int fileVersion = ConvertStrTo<int>(tokens[1]);
  1531. if(fileVersion > KEYMAP_VERSION)
  1532. {
  1533. errText.AppendFormat(_T("File version is %d, but your version of OpenMPT only supports loading files up to version %d.\n"), fileVersion, KEYMAP_VERSION);
  1534. }
  1535. continue;
  1536. }
  1537. // Format: ctx:UID:Description:Modifier:Key:EventMask
  1538. CommandID cmd = kcNumCommands;
  1539. if(tokens.size() >= 5)
  1540. {
  1541. kc.Context(static_cast<InputTargetContext>(ConvertStrTo<int>(tokens[0])));
  1542. cmd = FindCmd(ConvertStrTo<uint32>(tokens[1]));
  1543. // Modifier
  1544. kc.Modifier(static_cast<Modifiers>(ConvertStrTo<int>(tokens[2])));
  1545. // Virtual Key code / Scan code
  1546. UINT vk = 0;
  1547. auto scPos = tokens[3].find('/');
  1548. if(scPos != std::string::npos)
  1549. {
  1550. // Scan code present
  1551. UINT sc = ConvertStrTo<UINT>(tokens[3].substr(scPos + 1));
  1552. for(auto i = layouts.begin(); i != layouts.end() && vk == 0; i++)
  1553. {
  1554. vk = MapVirtualKeyEx(sc, MAPVK_VSC_TO_VK, *i);
  1555. }
  1556. }
  1557. if(vk == 0)
  1558. {
  1559. vk = ConvertStrTo<UINT>(tokens[3]);
  1560. }
  1561. kc.KeyCode(vk);
  1562. // Event
  1563. kc.EventType(static_cast<KeyEventType>(ConvertStrTo<int>(tokens[4])));
  1564. if(fillExistingSet && cmd != kcNull && GetKeyListSize(cmd) != 0)
  1565. {
  1566. // Do not map shortcuts that already have custom keys assigned.
  1567. // In particular with default note keys, this can create awkward keymaps when loading
  1568. // e.g. an IT-style keymap and it contains two keys mapped to the same notes.
  1569. continue;
  1570. }
  1571. }
  1572. // Error checking
  1573. if(cmd < 0 || cmd >= kcNumCommands || kc.Context() >= kCtxMaxInputContexts || tokens.size() < 4)
  1574. {
  1575. errorCount++;
  1576. if (errorCount < 10)
  1577. {
  1578. if(tokens.size() < 4)
  1579. errText.AppendFormat(_T("Line %d was not understood.\n"), l);
  1580. else
  1581. errText.AppendFormat(_T("Line %d contained an unknown command.\n"), l);
  1582. } else if (errorCount == 10)
  1583. {
  1584. errText += _T("Too many errors detected, not reporting any more.\n");
  1585. }
  1586. } else
  1587. {
  1588. Add(kc, cmd, !fillExistingSet, -1, !fillExistingSet);
  1589. }
  1590. }
  1591. if(!fillExistingSet)
  1592. {
  1593. // Add the default command set to our freshly loaded command set.
  1594. std::istringstream ss{ GetDefaultKeymap() };
  1595. LoadFile(ss, mpt::ustring(), true);
  1596. } else
  1597. {
  1598. // We were just adding stuff to an existing command set - don't delete it!
  1599. return true;
  1600. }
  1601. // Fix up old keymaps containing legacy commands that have been merged into other commands
  1602. static constexpr std::pair<CommandID, CommandID> MergeCommands[] =
  1603. {
  1604. {kcFileSaveAsMP3, kcFileSaveAsWave},
  1605. {kcNoteCutOld, kcNoteCut},
  1606. {kcNoteOffOld, kcNoteOff},
  1607. {kcNoteFadeOld, kcNoteFade},
  1608. };
  1609. for(const auto [from, to] : MergeCommands)
  1610. {
  1611. m_commands[to].kcList.insert(m_commands[to].kcList.end(), m_commands[from].kcList.begin(), m_commands[from].kcList.end());
  1612. m_commands[from].kcList.clear();
  1613. }
  1614. if(!errText.IsEmpty())
  1615. {
  1616. Reporting::Warning(MPT_CFORMAT("The following problems have been encountered while trying to load the key binding file {}:\n{}")
  1617. (mpt::ToCString(filenameDescription), errText));
  1618. }
  1619. m_oldSpecs = nullptr;
  1620. return true;
  1621. }
  1622. bool CCommandSet::LoadFile(const mpt::PathString &filename)
  1623. {
  1624. mpt::ifstream fin(filename);
  1625. if(fin.fail())
  1626. {
  1627. Reporting::Warning(MPT_TFORMAT("Can't open key bindings file {} for reading. Default key bindings will be used.")(filename));
  1628. return false;
  1629. } else
  1630. {
  1631. return LoadFile(fin, filename.ToUnicode());
  1632. }
  1633. }
  1634. bool CCommandSet::LoadDefaultKeymap()
  1635. {
  1636. std::istringstream ss{ GetDefaultKeymap() };
  1637. return LoadFile(ss, U_("\"executable resource\""));
  1638. }
  1639. CommandID CCommandSet::FindCmd(uint32 uid) const
  1640. {
  1641. for(int i = 0; i < kcNumCommands; i++)
  1642. {
  1643. if(m_commands[i].ID() == uid)
  1644. return static_cast<CommandID>(i);
  1645. }
  1646. return kcNull;
  1647. }
  1648. CString KeyCombination::GetContextText(InputTargetContext ctx)
  1649. {
  1650. switch(ctx)
  1651. {
  1652. case kCtxAllContexts: return _T("Global Context");
  1653. case kCtxViewGeneral: return _T("General Context [bottom]");
  1654. case kCtxViewPatterns: return _T("Pattern Context [bottom]");
  1655. case kCtxViewPatternsNote: return _T("Pattern Context [bottom] - Note Col");
  1656. case kCtxViewPatternsIns: return _T("Pattern Context [bottom] - Ins Col");
  1657. case kCtxViewPatternsVol: return _T("Pattern Context [bottom] - Vol Col");
  1658. case kCtxViewPatternsFX: return _T("Pattern Context [bottom] - FX Col");
  1659. case kCtxViewPatternsFXparam: return _T("Pattern Context [bottom] - Param Col");
  1660. case kCtxViewSamples: return _T("Sample Context [bottom]");
  1661. case kCtxViewInstruments: return _T("Instrument Context [bottom]");
  1662. case kCtxViewComments: return _T("Comments Context [bottom]");
  1663. case kCtxCtrlGeneral: return _T("General Context [top]");
  1664. case kCtxCtrlPatterns: return _T("Pattern Context [top]");
  1665. case kCtxCtrlSamples: return _T("Sample Context [top]");
  1666. case kCtxCtrlInstruments: return _T("Instrument Context [top]");
  1667. case kCtxCtrlComments: return _T("Comments Context [top]");
  1668. case kCtxCtrlOrderlist: return _T("Orderlist");
  1669. case kCtxVSTGUI: return _T("Plugin GUI Context");
  1670. case kCtxChannelSettings: return _T("Quick Channel Settings Context");
  1671. case kCtxUnknownContext:
  1672. default: return _T("Unknown Context");
  1673. }
  1674. }
  1675. CString KeyCombination::GetKeyEventText(FlagSet<KeyEventType> event)
  1676. {
  1677. CString text;
  1678. bool first = true;
  1679. if (event & kKeyEventDown)
  1680. {
  1681. first=false;
  1682. text.Append(_T("KeyDown"));
  1683. }
  1684. if (event & kKeyEventRepeat)
  1685. {
  1686. if (!first) text.Append(_T("|"));
  1687. text.Append(_T("KeyHold"));
  1688. first=false;
  1689. }
  1690. if (event & kKeyEventUp)
  1691. {
  1692. if (!first) text.Append(_T("|"));
  1693. text.Append(_T("KeyUp"));
  1694. }
  1695. return text;
  1696. }
  1697. CString KeyCombination::GetModifierText(FlagSet<Modifiers> mod)
  1698. {
  1699. CString text;
  1700. if (mod[ModShift]) text.Append(_T("Shift+"));
  1701. if (mod[ModCtrl]) text.Append(_T("Ctrl+"));
  1702. if (mod[ModAlt]) text.Append(_T("Alt+"));
  1703. if (mod[ModRShift]) text.Append(_T("RShift+"));
  1704. if (mod[ModRCtrl]) text.Append(_T("RCtrl+"));
  1705. if (mod[ModRAlt]) text.Append(_T("RAlt+"));
  1706. if (mod[ModWin]) text.Append(_T("Win+")); // Feature: use Windows keys as modifier keys
  1707. if (mod[ModMidi]) text.Append(_T("MIDI"));
  1708. return text;
  1709. }
  1710. CString KeyCombination::GetKeyText(FlagSet<Modifiers> mod, UINT code)
  1711. {
  1712. CString keyText = GetModifierText(mod);
  1713. if(mod[ModMidi])
  1714. {
  1715. if(code < 0x80)
  1716. keyText.AppendFormat(_T(" CC %u"), code);
  1717. else
  1718. keyText += MPT_CFORMAT(" {}{}")(mpt::ustring(NoteNamesSharp[(code & 0x7F) % 12]), (code & 0x7F) / 12);
  1719. } else
  1720. {
  1721. keyText.Append(CHotKeyCtrl::GetKeyName(code, IsExtended(code)));
  1722. }
  1723. //HACK:
  1724. if (keyText == _T("Ctrl+CTRL")) keyText = _T("Ctrl");
  1725. else if (keyText == _T("Alt+ALT")) keyText = _T("Alt");
  1726. else if (keyText == _T("Shift+SHIFT")) keyText = _T("Shift");
  1727. else if (keyText == _T("RCtrl+CTRL")) keyText = _T("RCtrl");
  1728. else if (keyText == _T("RAlt+ALT")) keyText = _T("RAlt");
  1729. else if (keyText == _T("RShift+SHIFT")) keyText = _T("RShift");
  1730. return keyText;
  1731. }
  1732. CString CCommandSet::GetKeyTextFromCommand(CommandID c, UINT key) const
  1733. {
  1734. if (key < m_commands[c].kcList.size())
  1735. return m_commands[c].kcList[0].GetKeyText();
  1736. else
  1737. return CString();
  1738. }
  1739. // Quick Changes - modify many commands with one call.
  1740. bool CCommandSet::QuickChange_NotesRepeat(bool repeat)
  1741. {
  1742. for (CommandID cmd = kcVPStartNotes; cmd <= kcVPEndNotes; cmd=(CommandID)(cmd + 1)) //for all notes
  1743. {
  1744. for(auto &kc : m_commands[cmd].kcList)
  1745. {
  1746. if(repeat)
  1747. kc.EventType(kc.EventType() | kKeyEventRepeat);
  1748. else
  1749. kc.EventType(kc.EventType() & ~kKeyEventRepeat);
  1750. }
  1751. }
  1752. return true;
  1753. }
  1754. bool CCommandSet::QuickChange_SetEffects(const CModSpecifications &modSpecs)
  1755. {
  1756. // Is this already the active key configuration?
  1757. if(&modSpecs == m_oldSpecs)
  1758. {
  1759. return false;
  1760. }
  1761. m_oldSpecs = &modSpecs;
  1762. int choices = 0;
  1763. KeyCombination kc(kCtxViewPatternsFX, ModNone, 0, kKeyEventDown | kKeyEventRepeat);
  1764. for(CommandID cmd = kcFixedFXStart; cmd <= kcFixedFXend; cmd = static_cast<CommandID>(cmd + 1))
  1765. {
  1766. // Remove all old choices
  1767. choices = GetKeyListSize(cmd);
  1768. for(int p = choices; p >= 0; --p)
  1769. {
  1770. Remove(p, cmd);
  1771. }
  1772. char effect = modSpecs.GetEffectLetter(static_cast<ModCommand::COMMAND>(cmd - kcSetFXStart + 1));
  1773. if(effect >= 'A' && effect <= 'Z')
  1774. {
  1775. // VkKeyScanEx needs lowercase letters
  1776. effect = effect - 'A' + 'a';
  1777. } else if(effect < '0' || effect > '9')
  1778. {
  1779. // Don't map effects that use "weird" effect letters (such as # or \)
  1780. effect = '?';
  1781. }
  1782. if(effect != '?')
  1783. {
  1784. // Hack for situations where a non-latin keyboard layout without A...Z key code mapping may the current layout (e.g. Russian),
  1785. // but a latin layout (e.g. EN-US) is installed as well.
  1786. std::vector<HKL> layouts(GetKeyboardLayoutList(0, nullptr));
  1787. GetKeyboardLayoutList(static_cast<int>(layouts.size()), layouts.data());
  1788. SHORT codeNmod = -1;
  1789. for(auto i = layouts.begin(); i != layouts.end() && codeNmod == -1; i++)
  1790. {
  1791. codeNmod = VkKeyScanEx(effect, *i);
  1792. }
  1793. if(codeNmod != -1)
  1794. {
  1795. kc.KeyCode(LOBYTE(codeNmod));
  1796. // Don't add modifier keys, since on French keyboards, numbers are input using Shift.
  1797. // We don't really want that behaviour here, and I'm sure we don't want that in other cases on other layouts as well.
  1798. kc.Modifier(ModNone);
  1799. Add(kc, cmd, true);
  1800. }
  1801. if (effect >= '0' && effect <= '9') // For numbers, ensure numpad works too
  1802. {
  1803. kc.KeyCode(VK_NUMPAD0 + (effect - '0'));
  1804. Add(kc, cmd, true);
  1805. }
  1806. }
  1807. }
  1808. return true;
  1809. }
  1810. // Stupid MFC crap: for some reason VK code isn't enough to get correct string with GetKeyName.
  1811. // We also need to figure out the correct "extended" bit.
  1812. bool KeyCombination::IsExtended(UINT code)
  1813. {
  1814. if (code==VK_SNAPSHOT) //print screen
  1815. return true;
  1816. if (code>=VK_PRIOR && code<=VK_DOWN) //pgup, pg down, home, end, cursor keys,
  1817. return true;
  1818. if (code>=VK_INSERT && code<=VK_DELETE) // ins, del
  1819. return true;
  1820. if (code>=VK_LWIN && code<=VK_APPS) //winkeys & application key
  1821. return true;
  1822. if (code==VK_DIVIDE) //Numpad '/'
  1823. return true;
  1824. if (code==VK_NUMLOCK) //print screen
  1825. return true;
  1826. if (code>=0xA0 && code<=0xA5) //attempt for RL mods
  1827. return true;
  1828. return false;
  1829. }
  1830. void CCommandSet::SetupContextHierarchy()
  1831. {
  1832. // For now much be fully expanded (i.e. don't rely on grandparent relationships).
  1833. m_isParentContext[kCtxAllContexts].set(kCtxViewGeneral);
  1834. m_isParentContext[kCtxAllContexts].set(kCtxViewPatterns);
  1835. m_isParentContext[kCtxAllContexts].set(kCtxViewPatternsNote);
  1836. m_isParentContext[kCtxAllContexts].set(kCtxViewPatternsIns);
  1837. m_isParentContext[kCtxAllContexts].set(kCtxViewPatternsVol);
  1838. m_isParentContext[kCtxAllContexts].set(kCtxViewPatternsFX);
  1839. m_isParentContext[kCtxAllContexts].set(kCtxViewPatternsFXparam);
  1840. m_isParentContext[kCtxAllContexts].set(kCtxViewSamples);
  1841. m_isParentContext[kCtxAllContexts].set(kCtxViewInstruments);
  1842. m_isParentContext[kCtxAllContexts].set(kCtxViewComments);
  1843. m_isParentContext[kCtxAllContexts].set(kCtxViewTree);
  1844. m_isParentContext[kCtxAllContexts].set(kCtxInsNoteMap);
  1845. m_isParentContext[kCtxAllContexts].set(kCtxVSTGUI);
  1846. m_isParentContext[kCtxAllContexts].set(kCtxCtrlGeneral);
  1847. m_isParentContext[kCtxAllContexts].set(kCtxCtrlPatterns);
  1848. m_isParentContext[kCtxAllContexts].set(kCtxCtrlSamples);
  1849. m_isParentContext[kCtxAllContexts].set(kCtxCtrlInstruments);
  1850. m_isParentContext[kCtxAllContexts].set(kCtxCtrlComments);
  1851. m_isParentContext[kCtxAllContexts].set(kCtxCtrlSamples);
  1852. m_isParentContext[kCtxAllContexts].set(kCtxCtrlOrderlist);
  1853. m_isParentContext[kCtxAllContexts].set(kCtxChannelSettings);
  1854. m_isParentContext[kCtxViewPatterns].set(kCtxViewPatternsNote);
  1855. m_isParentContext[kCtxViewPatterns].set(kCtxViewPatternsIns);
  1856. m_isParentContext[kCtxViewPatterns].set(kCtxViewPatternsVol);
  1857. m_isParentContext[kCtxViewPatterns].set(kCtxViewPatternsFX);
  1858. m_isParentContext[kCtxViewPatterns].set(kCtxViewPatternsFXparam);
  1859. m_isParentContext[kCtxCtrlPatterns].set(kCtxCtrlOrderlist);
  1860. }
  1861. bool CCommandSet::KeyCombinationConflict(KeyCombination kc1, KeyCombination kc2, bool checkEventConflict) const
  1862. {
  1863. bool modConflict = (kc1.Modifier()==kc2.Modifier());
  1864. bool codeConflict = (kc1.KeyCode()==kc2.KeyCode());
  1865. bool eventConflict = ((kc1.EventType()&kc2.EventType()));
  1866. bool ctxConflict = (kc1.Context() == kc2.Context());
  1867. bool crossCxtConflict = IsCrossContextConflict(kc1, kc2);
  1868. bool conflict = modConflict && codeConflict && (eventConflict || !checkEventConflict) &&
  1869. (ctxConflict || crossCxtConflict);
  1870. return conflict;
  1871. }
  1872. bool CCommandSet::IsCrossContextConflict(KeyCombination kc1, KeyCombination kc2) const
  1873. {
  1874. return m_isParentContext[kc1.Context()][kc2.Context()] || m_isParentContext[kc2.Context()][kc1.Context()];
  1875. }
  1876. OPENMPT_NAMESPACE_END