OpenClonk
C4PlayerControlAssignment Class Reference

#include <C4PlayerControl.h>

Public Types

enum  TriggerModes {
  CTM_Default = 0 , CTM_Hold = 1 << 0 , CTM_Release = 1 << 1 , CTM_AlwaysUnhandled = 1 << 2 ,
  CTM_HandleDownStatesOnly = 1 << 3 , CTM_ClearRecentKeys = 1 << 4
}
 

Public Member Functions

 C4PlayerControlAssignment ()
 
 ~C4PlayerControlAssignment ()=default
 
void CompileFunc (StdCompiler *pComp)
 
void CopyKeyFrom (const C4PlayerControlAssignment &src_assignment)
 
bool ResolveRefs (class C4PlayerControlAssignmentSet *pParentSet, C4PlayerControlDefs *pControlDefs)
 
bool IsComboMatched (const C4PlayerControlRecentKeyList &DownKeys, const C4PlayerControlRecentKeyList &RecentKeys) const
 
void SetInherited (bool to_val)
 
void SetInheritedAssignment (const C4PlayerControlAssignment *to_val)
 
void ResetKeyToInherited ()
 
bool IsKeyChanged () const
 
void SetControlName (const char *control_name)
 
void SetKey (const C4KeyCodeEx &key)
 
bool operator== (const C4PlayerControlAssignment &cmp) const
 
bool operator< (const C4PlayerControlAssignment &cmp) const
 
const char * GetControlName () const
 
int32_t GetControl () const
 
const char * GetGUIName (const C4PlayerControlDefs &defs) const
 
const char * GetGUIDesc (const C4PlayerControlDefs &defs) const
 
bool IsGUIDisabled () const
 
int32_t GetGUIGroup () const
 
bool IsRefsResolved () const
 
void ResetRefsResolved ()
 
bool IsAlwaysUnhandled () const
 
int32_t GetTriggerMode () const
 
const C4KeyCodeExGetTriggerKey () const
 
bool HasCombo () const
 
bool IsOverrideAssignments () const
 
bool IsInherited () const
 
const C4PlayerControlAssignmentGetInheritedAssignment () const
 
StdStrBuf GetKeysAsString (bool human_readable, bool short_name) const
 

Detailed Description

Definition at line 142 of file C4PlayerControl.h.

Member Enumeration Documentation

◆ TriggerModes

Enumerator
CTM_Default 
CTM_Hold 
CTM_Release 
CTM_AlwaysUnhandled 
CTM_HandleDownStatesOnly 
CTM_ClearRecentKeys 

Definition at line 146 of file C4PlayerControl.h.

147  {
148  CTM_Default = 0, // standard behaviour: The control will be triggered
149  CTM_Hold = 1 << 0, // the control will be put into "down"-mode
150  CTM_Release = 1 << 1, // the hold mode of the control will be released
151  CTM_AlwaysUnhandled = 1 << 2, // the key will not block handling of other keys even if it got handled
152  CTM_HandleDownStatesOnly = 1 << 3, // used when an already handled release key is processed to reset down states of overridden keys only
153  CTM_ClearRecentKeys = 1 << 4 // if this assignment is triggered, RecentKeys are reset so no more combos can be generated
154  };

Constructor & Destructor Documentation

◆ C4PlayerControlAssignment()

C4PlayerControlAssignment::C4PlayerControlAssignment ( )
inline

Definition at line 190 of file C4PlayerControl.h.

190  :
191  TriggerKey()
192  {}

◆ ~C4PlayerControlAssignment()

C4PlayerControlAssignment::~C4PlayerControlAssignment ( )
default

Member Function Documentation

◆ CompileFunc()

void C4PlayerControlAssignment::CompileFunc ( StdCompiler pComp)

Definition at line 206 of file C4PlayerControl.cpp.

207 {
208  if (!pComp->Name("Assignment")) { pComp->NameEnd(); pComp->excNotFound("Assignment"); }
209  pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(KeyCombo), "Key", KeyComboVec()));
210  pComp->Value(mkNamingAdapt(fComboIsSequence, "ComboIsSequence", false));
211  pComp->Value(mkNamingAdapt(mkParAdapt(sControlName, StdCompiler::RCT_Idtf), "Control", "None"));
212  pComp->Value(mkNamingAdapt(mkParAdapt(sGUIName, StdCompiler::RCT_All), "GUIName", ""));
213  pComp->Value(mkNamingAdapt(mkParAdapt(sGUIDesc, StdCompiler::RCT_All), "GUIDesc", ""));
214  pComp->Value(mkNamingAdapt(iGUIGroup,"GUIGroup",0));
215  pComp->Value(mkNamingAdapt(fGUIDisabled, "GUIDisabled", false));
216  pComp->Value(mkNamingAdapt(iPriority, "Priority", 0));
217  const StdBitfieldEntry<int32_t> TriggerModeNames[] =
218  {
219  { "Default", CTM_Default },
220  { "Hold", CTM_Hold },
221  { "Release", CTM_Release },
222  { "AlwaysUnhandled", CTM_AlwaysUnhandled },
223  { "ClearRecentKeys", CTM_ClearRecentKeys },
224  { nullptr, 0 }
225  };
226  pComp->Value(mkNamingAdapt(mkBitfieldAdapt< int32_t>(iTriggerMode, TriggerModeNames), "TriggerMode", CTM_Default));
227  pComp->Value(mkNamingAdapt(fOverrideAssignments, "OverrideAssignments", false));
228  pComp->NameEnd();
229  // newly loaded structures are not resolved
230  if (pComp->isDeserializer()) fRefsResolved = false;
231 }
StdSTLContainerAdapt< C > mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep=StdCompiler::SEP_SEP)
Definition: StdAdaptors.h:713
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:490
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
Definition: StdAdaptors.h:883
void Value(const T &rStruct)
Definition: StdCompiler.h:161
virtual void NameEnd(bool fBreak=false)
Definition: StdCompiler.h:78
void excNotFound(const char *szMessage,...)
Definition: StdCompiler.h:233
virtual bool isDeserializer()
Definition: StdCompiler.h:53
virtual bool Name(const char *szName)
Definition: StdCompiler.h:77

References CTM_AlwaysUnhandled, CTM_ClearRecentKeys, CTM_Default, CTM_Hold, CTM_Release, StdCompiler::excNotFound(), StdCompiler::isDeserializer(), mkNamingAdapt(), mkParAdapt(), mkSTLContainerAdapt(), StdCompiler::Name(), StdCompiler::NameEnd(), StdCompiler::RCT_All, StdCompiler::RCT_Idtf, and StdCompiler::Value().

Here is the call graph for this function:

◆ CopyKeyFrom()

void C4PlayerControlAssignment::CopyKeyFrom ( const C4PlayerControlAssignment src_assignment)

Definition at line 257 of file C4PlayerControl.cpp.

258 {
259  // just copy key settings; keep control and priorities
260  KeyCombo = src_assignment.KeyCombo;
261  TriggerKey = src_assignment.TriggerKey;
262  fComboIsSequence = src_assignment.fComboIsSequence;
263  if (!src_assignment.fRefsResolved) fRefsResolved = false;
264 }

Referenced by ResetKeyToInherited().

Here is the caller graph for this function:

◆ GetControl()

int32_t C4PlayerControlAssignment::GetControl ( ) const
inline

Definition at line 209 of file C4PlayerControl.h.

209 { return iControl; }

Referenced by GetGUIDesc(), and GetGUIName().

Here is the caller graph for this function:

◆ GetControlName()

const char* C4PlayerControlAssignment::GetControlName ( ) const
inline

Definition at line 208 of file C4PlayerControl.h.

208 { return sControlName.getData(); }
const char * getData() const
Definition: StdBuf.h:442

References StdStrBuf::getData().

Referenced by ResolveRefs().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetGUIDesc()

const char * C4PlayerControlAssignment::GetGUIDesc ( const C4PlayerControlDefs defs) const

Definition at line 456 of file C4PlayerControl.cpp.

457 {
458  // local desc?
459  if (sGUIDesc.getLength()) return sGUIDesc.getData();
460  // otherwise, fall back to def
461  const C4PlayerControlDef *def = defs.GetControlByIndex(GetControl());
462  if (def) return def->GetGUIDesc();
463  // no def and no desc...
464  return nullptr;
465 }
const char * GetGUIDesc() const
const C4PlayerControlDef * GetControlByIndex(int32_t idx) const
size_t getLength() const
Definition: StdBuf.h:445

References GetControl(), C4PlayerControlDefs::GetControlByIndex(), StdStrBuf::getData(), C4PlayerControlDef::GetGUIDesc(), and StdStrBuf::getLength().

Here is the call graph for this function:

◆ GetGUIGroup()

int32_t C4PlayerControlAssignment::GetGUIGroup ( ) const

Definition at line 472 of file C4PlayerControl.cpp.

473 {
474  return iGUIGroup;
475 }

◆ GetGUIName()

const char * C4PlayerControlAssignment::GetGUIName ( const C4PlayerControlDefs defs) const

Definition at line 440 of file C4PlayerControl.cpp.

441 {
442  // local name?
443  if (sGUIName.getLength())
444  {
445  // special: None defaults to empty name
446  if (sGUIName == "None") return "";
447  return sGUIName.getData();
448  }
449  // otherwise, fall back to def
450  const C4PlayerControlDef *def = defs.GetControlByIndex(GetControl());
451  if (def) return def->GetGUIName();
452  // no def and no name...
453  return nullptr;
454 }
const char * GetGUIName() const

References GetControl(), C4PlayerControlDefs::GetControlByIndex(), StdStrBuf::getData(), C4PlayerControlDef::GetGUIName(), and StdStrBuf::getLength().

Here is the call graph for this function:

◆ GetInheritedAssignment()

const C4PlayerControlAssignment* C4PlayerControlAssignment::GetInheritedAssignment ( ) const
inline

Definition at line 222 of file C4PlayerControl.h.

222 { return inherited_assignment; }

◆ GetKeysAsString()

StdStrBuf C4PlayerControlAssignment::GetKeysAsString ( bool  human_readable,
bool  short_name 
) const

Definition at line 422 of file C4PlayerControl.cpp.

423 {
424  // create a short, human-readable string of the assigned key
425  // to be displayed e.g. in tutorial messages explaining controls
426  StdStrBuf result;
427  if (!KeyCombo.size()) return result;
428  // trigger key
429  KeyComboVec::const_iterator i=KeyCombo.begin();
430  result.Take(i->Key.ToString(human_readable, short_name));
431  // extra keys of combo
432  while (++i != KeyCombo.end())
433  {
434  result.AppendChar(fComboIsSequence ? ',' : '+');
435  result.Append(i->Key.ToString(human_readable, short_name));
436  }
437  return result;
438 }
void AppendChar(char cChar)
Definition: StdBuf.h:588
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
void Take(char *pnData)
Definition: StdBuf.h:457

References StdStrBuf::Append(), StdStrBuf::AppendChar(), and StdStrBuf::Take().

Here is the call graph for this function:

◆ GetTriggerKey()

const C4KeyCodeEx& C4PlayerControlAssignment::GetTriggerKey ( ) const
inline

Definition at line 218 of file C4PlayerControl.h.

218 { return TriggerKey; }

◆ GetTriggerMode()

int32_t C4PlayerControlAssignment::GetTriggerMode ( ) const
inline

Definition at line 217 of file C4PlayerControl.h.

217 { return iTriggerMode; }

◆ HasCombo()

bool C4PlayerControlAssignment::HasCombo ( ) const
inline

Definition at line 219 of file C4PlayerControl.h.

219 { return KeyCombo.size()>1; }

Referenced by IsComboMatched().

Here is the caller graph for this function:

◆ IsAlwaysUnhandled()

bool C4PlayerControlAssignment::IsAlwaysUnhandled ( ) const
inline

Definition at line 216 of file C4PlayerControl.h.

216 { return !!(iTriggerMode & CTM_AlwaysUnhandled); }

References CTM_AlwaysUnhandled.

◆ IsComboMatched()

bool C4PlayerControlAssignment::IsComboMatched ( const C4PlayerControlRecentKeyList DownKeys,
const C4PlayerControlRecentKeyList RecentKeys 
) const

Definition at line 363 of file C4PlayerControl.cpp.

364 {
365  assert(HasCombo());
366  // check if combo is currently fulfilled (assuming TriggerKey is already matched)
367  if (fComboIsSequence)
368  {
370  // combo is a sequence: The last keys of RecentKeys must match the sequence
371  // the last ComboKey is the TriggerKey, which is omitted because it has already been matched and is not to be found in RecentKeys yet
372  auto i = KeyCombo.rbegin()+1;
373  for (auto ri = RecentKeys.rbegin(); i!=KeyCombo.rend(); ++ri)
374  {
375  // no more keys pressed but combo didn't end? -> no combo match
376  if (ri == RecentKeys.rend()) return false;
377  const C4PlayerControlRecentKey &rk = *ri;
378  // user waited for too long?
379  C4TimeMilliseconds tKeyRecent = rk.tTime;
380  if (tKeyLast - tKeyRecent > C4PlayerControl::MaxSequenceKeyDelay) return false;
381  // key doesn't match?
382  const KeyComboItem &k = *i;
383  if (!(rk.matched_key == k.Key))
384  {
385  // mouse movement commands do not break sequences
387  return false;
388  }
389  // key OK
390  ++i;
391  }
392  }
393  else
394  {
395  // combo requires keys to be down simultanuously: check that all keys of the combo are in the down-list
396  for (const auto & k : KeyCombo)
397  {
398  bool fFound = false;
399  for (const auto & dk : DownKeys)
400  {
401  if (dk.matched_key == k.Key) { fFound = true; break; }
402  }
403  if (!fFound) return false;
404  }
405  }
406  // combo OK!
407  return true;
408 }
const C4KeyCode KEY_MOUSE_Move
bool Key_IsMouse(C4KeyCode key)
uint8_t Key_GetMouseEvent(C4KeyCode key)
static C4TimeMilliseconds Now()
C4KeyCode Key
C4TimeMilliseconds tTime

References HasCombo(), C4KeyCodeEx::Key, Key_GetMouseEvent(), Key_IsMouse(), KEY_MOUSE_Move, C4PlayerControlRecentKey::matched_key, C4PlayerControl::MaxSequenceKeyDelay, C4TimeMilliseconds::Now(), and C4PlayerControlRecentKey::tTime.

Here is the call graph for this function:

◆ IsGUIDisabled()

bool C4PlayerControlAssignment::IsGUIDisabled ( ) const

Definition at line 467 of file C4PlayerControl.cpp.

468 {
469  return fGUIDisabled;
470 }

◆ IsInherited()

bool C4PlayerControlAssignment::IsInherited ( ) const
inline

Definition at line 221 of file C4PlayerControl.h.

221 { return is_inherited; }

◆ IsKeyChanged()

bool C4PlayerControlAssignment::IsKeyChanged ( ) const

Definition at line 238 of file C4PlayerControl.cpp.

239 {
240  // no inherited assignment? Then the key is always custom
241  if (!inherited_assignment) return true;
242  // otherwise, compare
243  return KeyCombo != inherited_assignment->KeyCombo || fComboIsSequence != inherited_assignment->fComboIsSequence;
244 }

◆ IsOverrideAssignments()

bool C4PlayerControlAssignment::IsOverrideAssignments ( ) const
inline

Definition at line 220 of file C4PlayerControl.h.

220 { return fOverrideAssignments; }

◆ IsRefsResolved()

bool C4PlayerControlAssignment::IsRefsResolved ( ) const
inline

Definition at line 214 of file C4PlayerControl.h.

214 { return fRefsResolved; }

Referenced by ResolveRefs().

Here is the caller graph for this function:

◆ operator<()

bool C4PlayerControlAssignment::operator< ( const C4PlayerControlAssignment cmp) const
inline

Definition at line 207 of file C4PlayerControl.h.

207 { return iPriority > cmp.iPriority; } // assignments are processed in DESCENDING priority!

◆ operator==()

bool C4PlayerControlAssignment::operator== ( const C4PlayerControlAssignment cmp) const

Definition at line 410 of file C4PlayerControl.cpp.

411 {
412  // doesn't compare resolved TriggerKey/iControl
413  return KeyCombo == cmp.KeyCombo
414  && sControlName == cmp.sControlName
415  && sGUIName == cmp.sGUIName
416  && sGUIDesc == cmp.sGUIDesc
417  && fGUIDisabled == cmp.fGUIDisabled
418  && iTriggerMode == cmp.iTriggerMode
419  && iPriority == cmp.iPriority;
420 }

◆ ResetKeyToInherited()

void C4PlayerControlAssignment::ResetKeyToInherited ( )

Definition at line 233 of file C4PlayerControl.cpp.

234 {
235  if (inherited_assignment) CopyKeyFrom(*inherited_assignment);
236 }
void CopyKeyFrom(const C4PlayerControlAssignment &src_assignment)

References CopyKeyFrom().

Here is the call graph for this function:

◆ ResetRefsResolved()

void C4PlayerControlAssignment::ResetRefsResolved ( )
inline

Definition at line 215 of file C4PlayerControl.h.

215 { fRefsResolved = false; } // Mark references to other assignments as not resolved

◆ ResolveRefs()

bool C4PlayerControlAssignment::ResolveRefs ( class C4PlayerControlAssignmentSet pParentSet,
C4PlayerControlDefs pControlDefs 
)

Definition at line 266 of file C4PlayerControl.cpp.

267 {
268  // avoid circular chains
269  static int32_t recursion_check = 0;
270  if (recursion_check > 10)
271  {
272  LogFatal(FormatString("Maximum recursion limit reached while resolving player control assignments of set %s in assignment for key %s. This is probably due to a circular control chain.", pParentSet->GetName(), GetControlName()).getData());
273  return false;
274  }
275  ++recursion_check;
276  // resolve control name
277  iControl = pControlDefs->GetControlIndexByIdentifier(sControlName.getData());
278  // resolve keys
279  KeyComboVec NewCombo;
280  for (auto & rKeyComboItem : KeyCombo)
281  {
282  const char *szKeyName = rKeyComboItem.sKeyName.getData();
283  // check if this is a key reference. A key reference must be preceded by CON_
284  // it may also be preceded by modifiers (Shift+), which are already set in rKeyComboItem.Key.dwShift
285  bool is_key_reference = false;
286  int last_shift_delim_pos;
287  if (szKeyName && *szKeyName)
288  {
289  if ((last_shift_delim_pos=SCharLastPos('+', szKeyName)) > -1) szKeyName += last_shift_delim_pos+1;
290  if (SEqual2(szKeyName, "CON_"))
291  {
292  is_key_reference = true;
293  szKeyName +=4;
294  }
295  }
296  if (is_key_reference)
297  {
298  // this is a key reference
299  // - find referenced target assignment
300  C4PlayerControlAssignment *pRefAssignment = pParentSet->GetAssignmentByControlName(szKeyName);
301  if (pRefAssignment)
302  {
303  // resolve itself if necessary
304  if (!pRefAssignment->IsRefsResolved()) if (!pRefAssignment->ResolveRefs(pParentSet, pControlDefs)) { --recursion_check; return false; }
305  // insert all keys of that combo into own combo
306  // add any extra shift states from reference
307  DWORD ref_shift = rKeyComboItem.Key.dwShift;
308  if (ref_shift)
309  {
310  for (auto assignment_combo_item : pRefAssignment->KeyCombo)
311  {
312  assignment_combo_item.Key.dwShift |= ref_shift;
313  NewCombo.push_back(assignment_combo_item);
314  }
315  }
316  else
317  {
318  NewCombo.insert(NewCombo.end(), pRefAssignment->KeyCombo.begin(), pRefAssignment->KeyCombo.end());
319  }
320  }
321  else
322  {
323  // undefined reference? Not fatal, but inform user
324  LogF("WARNING: Control %s of set %s contains reference to unassigned control %s.", GetControlName(), pParentSet->GetName(), rKeyComboItem.sKeyName.getData());
325  NewCombo.clear();
326  }
327  }
328  else
329  {
330  // non-reference: check if the assignment was valid
331 #ifndef USE_CONSOLE
332  if (rKeyComboItem.Key == KEY_Default)
333  LogF(R"(WARNING: Control %s of set %s contains undefined key "%s".)", GetControlName(), pParentSet->GetName(), szKeyName);
334 #endif
335  // ...and just keep this item.
336  NewCombo.push_back(rKeyComboItem);
337  }
338  }
339  KeyCombo = NewCombo;
340  // adjust Control and Shift into key states for non-sequence combo keys
341  // e.g. LeftControl,A should become LeftControl,Ctrl+A.
342  if (KeyCombo.size() > 1 && !fComboIsSequence)
343  {
344  int32_t shift = 0;
345  for (auto & i : KeyCombo)
346  {
347  if (i.Key.Key == K_CONTROL_L || i.Key.Key == K_CONTROL_R) shift |= KEYS_Control;
348  if (i.Key.Key == K_SHIFT_L || i.Key.Key == K_SHIFT_R) shift |= KEYS_Shift;
349  shift |= i.Key.dwShift;
350  }
351  for (auto & i : KeyCombo) i.Key.dwShift |= shift;
352  }
353  // remove control/shift duplications
354  for (auto & i : KeyCombo) i.Key.FixShiftKeys();
355  // the trigger key is always last of the chain
356  if (KeyCombo.size()) TriggerKey = KeyCombo.back().Key; else TriggerKey = C4KeyCodeEx();
357  // done
358  fRefsResolved = true;
359  --recursion_check;
360  return true;
361 }
const C4KeyCode KEY_Default
@ KEYS_Shift
@ KEYS_Control
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:262
bool LogFatal(const char *szMessage)
Definition: C4Log.cpp:239
uint32_t DWORD
bool SEqual2(const char *szStr1, const char *szStr2)
Definition: Standard.cpp:204
int SCharLastPos(char cTarget, const char *szInStr)
Definition: Standard.cpp:253
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
const char * GetControlName() const
bool ResolveRefs(class C4PlayerControlAssignmentSet *pParentSet, C4PlayerControlDefs *pControlDefs)
int32_t GetControlIndexByIdentifier(const char *szIdentifier) const

References FormatString(), C4PlayerControlAssignmentSet::GetAssignmentByControlName(), C4PlayerControlDefs::GetControlIndexByIdentifier(), GetControlName(), StdStrBuf::getData(), C4PlayerControlAssignmentSet::GetName(), IsRefsResolved(), C4KeyCodeEx::Key, KEY_Default, KEYS_Control, KEYS_Shift, LogF(), LogFatal(), ResolveRefs(), SCharLastPos(), and SEqual2().

Referenced by ResolveRefs().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetControlName()

void C4PlayerControlAssignment::SetControlName ( const char *  control_name)
inline

Definition at line 203 of file C4PlayerControl.h.

203 { sControlName.Copy(control_name); }
void Copy()
Definition: StdBuf.h:467

References StdStrBuf::Copy().

Here is the call graph for this function:

◆ SetInherited()

void C4PlayerControlAssignment::SetInherited ( bool  to_val)
inline

Definition at line 199 of file C4PlayerControl.h.

199 { is_inherited = to_val; }

◆ SetInheritedAssignment()

void C4PlayerControlAssignment::SetInheritedAssignment ( const C4PlayerControlAssignment to_val)
inline

Definition at line 200 of file C4PlayerControl.h.

200 { inherited_assignment = to_val; }

◆ SetKey()

void C4PlayerControlAssignment::SetKey ( const C4KeyCodeEx key)

Definition at line 246 of file C4PlayerControl.cpp.

247 {
248  // set as one-key-combo
249  KeyCombo.resize(1);
250  KeyCombo[0].Key = key;
251  KeyCombo[0].Key.fRepeated = false;
252  KeyCombo[0].sKeyName.Clear();
253  fComboIsSequence = false;
254  TriggerKey = key;
255 }

The documentation for this class was generated from the following files: