📄 actionmap.cc
字号:
// if (action >= KEY_A && action <= KEY_Z) {
// buffer[0] = char(action - KEY_A + 'a');
// buffer[1] = '\0';
// return true;
// } else if (action >= KEY_0 && action <= KEY_9) {
// buffer[0] = char(action - KEY_0 + '0');
// buffer[1] = '\0';
if ( (asciiCode != 0) && dIsDecentChar((char)asciiCode))
{
for (U32 i = 0; gAsciiMap[i].asciiCode != 0xFFFF; i++) {
if (gAsciiMap[i].asciiCode == asciiCode)
{
dStrcpy(buffer, gAsciiMap[i].pDescription);
return true;
}
}
// Must not have found a string for that ascii code just record the char
buffer[0] = char(asciiCode);
buffer[1] = '\0';
return true;
}
else
{
if (action >= KEY_A && action <= KEY_Z)
{
buffer[0] = char(action - KEY_A + 'a');
buffer[1] = '\0';
return true;
}
else if (action >= KEY_0 && action <= KEY_9) {
buffer[0] = char(action - KEY_0 + '0');
buffer[1] = '\0';
return true;
}
for (U32 i = 0; gVirtualMap[i].code != 0xFFFFFFFF; i++) {
if (gVirtualMap[i].code == action) {
dStrcpy(buffer, gVirtualMap[i].pDescription);
return true;
}
}
}
Con::errorf( "ActionMap::getKeyString: no string for action %d", action );
return false;
}
//--------------------------------------------------------------------------
bool ActionMap::processBindCmd(const char *device, const char *action, const char *makeCmd, const char *breakCmd)
{
U32 deviceType;
U32 deviceInst;
if(!getDeviceTypeAndInstance(device, deviceType, deviceInst))
{
Con::printf("processBindCmd: unknown device: %s", device);
return false;
}
// Ok, we now have the deviceType and instance. Create an event descriptor
// for the bind...
//
EventDescriptor eventDescriptor;
if (createEventDescriptor(action, &eventDescriptor) == false) {
Con::printf("Could not create a description for binding: %s", action);
return false;
}
// Create the full bind entry, and place it in the map
//
// DMMTODO
Node* pBindNode = getNode(deviceType, deviceInst,
eventDescriptor.flags,
eventDescriptor.eventCode);
pBindNode->flags = Node::BindCmd;
pBindNode->deadZoneBegin = 0;
pBindNode->deadZoneEnd = 0;
pBindNode->scaleFactor = 1;
if(makeCmd[0])
pBindNode->makeConsoleCommand = dStrdup(makeCmd);
else
pBindNode->makeConsoleCommand = dStrdup("");
if(breakCmd[0])
pBindNode->breakConsoleCommand = dStrdup(breakCmd);
else
pBindNode->breakConsoleCommand = dStrdup("");
return true;
}
//------------------------------------------------------------------------------
bool ActionMap::processBind(const U32 argc, const char** argv)
{
// Ok, the bind will come in the following format:
// [device] [key or button] <[param spec] [param] ...> [fnName]
//
const char* pDeviceName = argv[0];
const char* pEvent = argv[1];
const char* pFnName = argv[argc - 1];
// Determine the device
U32 deviceType;
U32 deviceInst;
if(!getDeviceTypeAndInstance(argv[0], deviceType, deviceInst))
{
Con::printf("processBind: unknown device: %s", pDeviceName);
return false;
}
// Ok, we now have the deviceType and instance. Create an event descriptor
// for the bind...
//
EventDescriptor eventDescriptor;
if (createEventDescriptor(pEvent, &eventDescriptor) == false) {
Con::printf("Could not create a description for binding: %s", pEvent);
return false;
}
// Event has now been described, and device determined. we need now to extract
// any modifiers that the action map will apply to incoming events before
// calling the bound function...
//
// DMMTODO
U32 assignedFlags = 0;
F32 deadZoneBegin = 0.0f;
F32 deadZoneEnd = 0.0f;
F32 scaleFactor = 1.0f;
if (argc != 3) {
// We have the following: "[DSIR]" [deadZone] [scale]
//
const char* pSpec = argv[2];
for (U32 i = 0; pSpec[i] != '\0'; i++) {
switch (pSpec[i]) {
case 'r': case 'R':
assignedFlags |= Node::HasScale;
break;
case 's': case 'S':
assignedFlags |= Node::HasScale;
break;
case 'd': case 'D':
assignedFlags |= Node::HasDeadZone;
break;
case 'i': case 'I':
assignedFlags |= Node::Inverted;
break;
default:
AssertFatal(false, avar("Misunderstood specifier in bind (spec string: %s)",
pSpec));
}
}
// Ok, we have the flags. Scan the dead zone and scale, if any.
//
U32 curArg = 3;
if (assignedFlags & Node::HasDeadZone) {
dSscanf(argv[curArg], "%g %g", &deadZoneBegin, &deadZoneEnd);
curArg++;
}
if (assignedFlags & Node::HasScale) {
scaleFactor = dAtof(argv[curArg]);
curArg++;
}
if (curArg != (argc - 1)) {
AssertFatal(curArg == (argc - 1), "error in bind spec somewhere...");
Con::printf("Improperly specified bind for key: %s", argv[2]);
return false;
}
}
// We have decided to only allow one bind per console function, so
// remove any existing nodes that are bound to the given function:
if ( pFnName[0] )
{
U32 devMapIndex, nodeIndex;
while ( findBoundNode( pFnName, devMapIndex, nodeIndex ) )
{
dFree( mDeviceMaps[devMapIndex]->nodeMap[nodeIndex].makeConsoleCommand );
dFree( mDeviceMaps[devMapIndex]->nodeMap[nodeIndex].breakConsoleCommand );
mDeviceMaps[devMapIndex]->nodeMap.erase( nodeIndex );
}
}
// Ensure that the console function is properly specified?
//
// DMMTODO
// Create the full bind entry, and place it in the map
//
// DMMTODO
Node* pBindNode = getNode(deviceType, deviceInst,
eventDescriptor.flags,
eventDescriptor.eventCode);
pBindNode->flags = assignedFlags;
pBindNode->deadZoneBegin = deadZoneBegin;
pBindNode->deadZoneEnd = deadZoneEnd;
pBindNode->scaleFactor = scaleFactor;
pBindNode->consoleFunction = StringTable->insert(pFnName);
return true;
}
//------------------------------------------------------------------------------
bool ActionMap::processAction(const InputEvent* pEvent)
{
static const char *argv[2];
if (pEvent->action == SI_MAKE) {
const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
pEvent->modifier, pEvent->objInst);
if (pNode == NULL) {
// Check to see if we clear the modifiers, do we find an action?
if (pEvent->modifier != 0)
pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
0, pEvent->objInst);
if (pNode == NULL)
return false;
}
// Whadda ya know, we have this bound. Set up, and call the console
// function associated with it...
//
F32 value = pEvent->fValue;
if (pNode->flags & Node::Ranged) {
value = (value * 2.0f) - 1.0f;
if (pNode->flags & Node::Inverted)
value *= -1.0f;
} else {
if (pNode->flags & Node::Inverted)
value = 1.0f - value;
}
if (pNode->flags & Node::HasScale)
value *= pNode->scaleFactor;
if (pNode->flags & Node::HasDeadZone)
if (value >= pNode->deadZoneBegin &&
value <= pNode->deadZoneEnd)
value = 0.0f;
// Ok, we're all set up, call the function.
if(pNode->flags & Node::BindCmd)
{
// it's a bind command
if(pNode->makeConsoleCommand)
Con::evaluate(pNode->makeConsoleCommand);
}
else if ( pNode->consoleFunction[0] )
{
argv[0] = pNode->consoleFunction;
argv[1] = Con::getFloatArg(value);
Con::execute(2, argv);
}
//
// And enter the break into the table if this is a make event...
enterBreakEvent(pEvent, pNode);
return true;
} else if (pEvent->action == SI_MOVE) {
if (pEvent->deviceType == MouseDeviceType) {
const Node* pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
pEvent->modifier, pEvent->objType);
if (pNode == NULL) {
// Check to see if we clear the modifiers, do we find an action?
if (pEvent->modifier != 0)
pNode = findNode(pEvent->deviceType, pEvent->deviceInst,
0, pEvent->objType);
if (pNode == NULL)
return false;
}
// "Do nothing" bind:
if ( !pNode->consoleFunction[0] )
return( true );
// Whadda ya know, we have this bound. Set up, and call the console
// function associated with it. Mouse events ignore range and dead
// zone params.
//
F32 value = pEvent->fValue;
if (pNode->flags & Node::Inverted)
value *= -1.0f;
if (pNode->flags & Node::HasScale)
value *= pNode->scaleFactor;
// Ok, we're all set up, call the function.
argv[0] = pNode->consoleFunction;
argv[1] = Con::getFloatArg(value);
Con::execute(2, argv);
return true;
} else
{
// Joystick events...
const Node* pNode = findNode( pEvent->deviceType, pEvent->deviceInst,
pEvent->modifier, pEvent->objType );
if ( pNode == NULL )
{
// Check to see if we clear the modifiers, do we find an action?
if (pEvent->modifier != 0)
pNode = findNode( pEvent->deviceType, pEvent->deviceInst,
0, pEvent->objType );
if ( pNode == NULL )
return false;
}
// "Do nothing" bind:
if ( !pNode->consoleFunction[0] )
return( true );
// Whadda ya know, we have this bound. Set up, and call the console
// function associated with it. Joystick move events are the same as mouse
// move events except that they don't ignore dead zone.
//
F32 value = pEvent->fValue;
if ( pNode->flags & Node::Inverted )
value *= -1.0f;
if ( pNode->flags & Node::HasScale )
value *= pNode->scaleFactor;
if ( pNode->flags & Node::HasDeadZone )
if ( value >= pNode->deadZoneBegin &&
value <= pNode->deadZoneEnd )
value = 0.0f;
// Ok, we're all set up, call the function.
argv[0] = pNode->consoleFunction;
argv[1] = Con::getFloatArg( value );
Con::execute( 2, argv );
return true;
}
} else if (pEvent->action == SI_BREAK) {
return checkBreakTable(pEvent);
}
return false;
}
//------------------------------------------------------------------------------
void ActionMap::enterBreakEvent(const InputEvent* pEvent, const Node* pNode)
{
// There aren't likely to be many breaks outstanding at any one given time,
// so a simple linear search is probably sufficient. Note that the break table
// is static to the class, all breaks are directed to the action map that received
// the make.
//
S32 entry = -1;
for (U32 i = 0; i < smBreakTable.size(); i++) {
if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
smBreakTable[i].objInst == U32(pEvent->objInst)) {
// Match.
entry = i;
break;
}
}
if (entry == -1) {
smBreakTable.increment();
entry = smBreakTable.size() - 1;
smBreakTable[entry].deviceType = pEvent->deviceType;
smBreakTable[entry].deviceInst = pEvent->deviceInst;
smBreakTable[entry].objInst = pEvent->objInst;
}
// Ok, we now have the entry, and know that the device desc. and the objInst match.
// Copy out the node information...
//
smBreakTable[entry].consoleFunction = pNode->consoleFunction;
if(pNode->breakConsoleCommand)
smBreakTable[entry].breakConsoleCommand = dStrdup(pNode->breakConsoleCommand);
else
smBreakTable[entry].breakConsoleCommand = NULL;
smBreakTable[entry].flags = pNode->flags;
smBreakTable[entry].deadZoneBegin = pNode->deadZoneBegin;
smBreakTable[entry].deadZoneEnd = pNode->deadZoneEnd;
smBreakTable[entry].scaleFactor = pNode->scaleFactor;
}
//------------------------------------------------------------------------------
bool ActionMap::checkBreakTable(const InputEvent* pEvent)
{
for (U32 i = 0; i < smBreakTable.size(); i++) {
if (smBreakTable[i].deviceType == U32(pEvent->deviceType) &&
smBreakTable[i].deviceInst == U32(pEvent->deviceInst) &&
smBreakTable[i].objInst == U32(pEvent->objInst)) {
// Match. Issue the break event...
//
F32 value = pEvent->fValue;
if (smBreakTable[i].flags & Node::Ranged) {
value = (value * 2.0f) - 1.0f;
if (smBreakTable[i].flags & Node::Inverted)
value *= -1.0f;
} else {
if (smBreakTable[i].flags & Node::Inverted)
value = 1.0f - value;
}
if (smBreakTable[i].flags & Node::HasScale)
value *= smBreakTable[i].scaleFactor;
if (smBreakTable[i].flags & Node::HasDeadZone)
if (value >= smBreakTable[i].deadZoneBegin &&
value <= smBreakTable[i].deadZoneEnd)
value = 0.0f;
// Ok, we're all set up, call the function.
if(smBreakTable[i].consoleFunction)
{
if ( smBreakTable[i].consoleFunction[0] )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -