OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
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

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 ( )
inline

Definition at line 190 of file C4PlayerControl.h.

190  :
191  TriggerKey()
192  {}
C4PlayerControlAssignment::~C4PlayerControlAssignment ( )
default

Member Function Documentation

void C4PlayerControlAssignment::CompileFunc ( StdCompiler pComp)

Definition at line 208 of file C4PlayerControl.cpp.

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().

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

Here is the call graph for this function:

void C4PlayerControlAssignment::CopyKeyFrom ( const C4PlayerControlAssignment src_assignment)

Definition at line 259 of file C4PlayerControl.cpp.

Referenced by ResetKeyToInherited().

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

Here is the caller graph for this function:

int32_t C4PlayerControlAssignment::GetControl ( ) const
inline

Definition at line 209 of file C4PlayerControl.h.

Referenced by GetGUIDesc(), and GetGUIName().

209 { return iControl; }

Here is the caller graph for this function:

const char* C4PlayerControlAssignment::GetControlName ( ) const
inline

Definition at line 208 of file C4PlayerControl.h.

References StdStrBuf::getData().

Referenced by ResolveRefs().

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

Definition at line 458 of file C4PlayerControl.cpp.

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

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

Here is the call graph for this function:

int32_t C4PlayerControlAssignment::GetGUIGroup ( ) const

Definition at line 474 of file C4PlayerControl.cpp.

475 {
476  return iGUIGroup;
477 }
const char * C4PlayerControlAssignment::GetGUIName ( const C4PlayerControlDefs defs) const

Definition at line 442 of file C4PlayerControl.cpp.

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

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

Here is the call graph for this function:

const C4PlayerControlAssignment* C4PlayerControlAssignment::GetInheritedAssignment ( ) const
inline

Definition at line 222 of file C4PlayerControl.h.

222 { return inherited_assignment; }
StdStrBuf C4PlayerControlAssignment::GetKeysAsString ( bool  human_readable,
bool  short_name 
) const

Definition at line 424 of file C4PlayerControl.cpp.

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

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

Here is the call graph for this function:

const C4KeyCodeEx& C4PlayerControlAssignment::GetTriggerKey ( ) const
inline

Definition at line 218 of file C4PlayerControl.h.

218 { return TriggerKey; }
int32_t C4PlayerControlAssignment::GetTriggerMode ( ) const
inline

Definition at line 217 of file C4PlayerControl.h.

217 { return iTriggerMode; }
bool C4PlayerControlAssignment::HasCombo ( ) const
inline

Definition at line 219 of file C4PlayerControl.h.

Referenced by IsComboMatched().

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

Here is the caller graph for this function:

bool C4PlayerControlAssignment::IsAlwaysUnhandled ( ) const
inline

Definition at line 216 of file C4PlayerControl.h.

References CTM_AlwaysUnhandled.

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

Definition at line 365 of file C4PlayerControl.cpp.

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

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

Here is the call graph for this function:

bool C4PlayerControlAssignment::IsGUIDisabled ( ) const

Definition at line 469 of file C4PlayerControl.cpp.

470 {
471  return fGUIDisabled;
472 }
bool C4PlayerControlAssignment::IsInherited ( ) const
inline

Definition at line 221 of file C4PlayerControl.h.

221 { return is_inherited; }
bool C4PlayerControlAssignment::IsKeyChanged ( ) const

Definition at line 240 of file C4PlayerControl.cpp.

241 {
242  // no inherited assignment? Then the key is always custom
243  if (!inherited_assignment) return true;
244  // otherwise, compare
245  return KeyCombo != inherited_assignment->KeyCombo || fComboIsSequence != inherited_assignment->fComboIsSequence;
246 }
bool C4PlayerControlAssignment::IsOverrideAssignments ( ) const
inline

Definition at line 220 of file C4PlayerControl.h.

220 { return fOverrideAssignments; }
bool C4PlayerControlAssignment::IsRefsResolved ( ) const
inline

Definition at line 214 of file C4PlayerControl.h.

Referenced by ResolveRefs().

214 { return fRefsResolved; }

Here is the caller graph for this function:

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!
bool C4PlayerControlAssignment::operator== ( const C4PlayerControlAssignment cmp) const

Definition at line 412 of file C4PlayerControl.cpp.

413 {
414  // doesn't compare resolved TriggerKey/iControl
415  return KeyCombo == cmp.KeyCombo
416  && sControlName == cmp.sControlName
417  && sGUIName == cmp.sGUIName
418  && sGUIDesc == cmp.sGUIDesc
419  && fGUIDisabled == cmp.fGUIDisabled
420  && iTriggerMode == cmp.iTriggerMode
421  && iPriority == cmp.iPriority;
422 }
void C4PlayerControlAssignment::ResetKeyToInherited ( )

Definition at line 235 of file C4PlayerControl.cpp.

References CopyKeyFrom().

236 {
237  if (inherited_assignment) CopyKeyFrom(*inherited_assignment);
238 }
void CopyKeyFrom(const C4PlayerControlAssignment &src_assignment)

Here is the call graph for this function:

void C4PlayerControlAssignment::ResetRefsResolved ( )
inline

Definition at line 215 of file C4PlayerControl.h.

215 { fRefsResolved = false; } // Mark references to other assignments as not resolved
bool C4PlayerControlAssignment::ResolveRefs ( class C4PlayerControlAssignmentSet pParentSet,
C4PlayerControlDefs pControlDefs 
)

Definition at line 268 of file C4PlayerControl.cpp.

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().

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

Definition at line 203 of file C4PlayerControl.h.

References StdStrBuf::Copy().

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

Here is the call graph for this function:

void C4PlayerControlAssignment::SetInherited ( bool  to_val)
inline

Definition at line 199 of file C4PlayerControl.h.

199 { is_inherited = to_val; }
void C4PlayerControlAssignment::SetInheritedAssignment ( const C4PlayerControlAssignment to_val)
inline

Definition at line 200 of file C4PlayerControl.h.

200 { inherited_assignment = to_val; }
void C4PlayerControlAssignment::SetKey ( const C4KeyCodeEx key)

Definition at line 248 of file C4PlayerControl.cpp.

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

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