为什么我的DirectX程序没有识别出我已经发布了转义键? (C ++)

时间:2009-10-19 20:43:42

标签: c++ keyboard directx directinput

编辑:经过更多代码修改后,错误仍然存​​在,修改后的代码如下所示:

KeyDown()

const int input_bit_num = 0x8000;
char keys[256];
bool KeyDown(int key)
{
    return (keys[key] & input_bit_num) != 0;
}

PollKeyboard()

LPDIRECTINPUTDEVICE8 di_keyboard;
void PollKeyboard()
{
    long result = di_keyboard->GetDeviceState(sizeof(keys), (LPVOID)&keys);
    char para[16];
    itoa(result, para, 17);
        if(result != DI_OK) MessageBox(NULL, para, "ERROR", MB_OK);

}

当我尝试将MessageBox放在KeyDown() if语句中时(如下面的游戏循环中所示),即使我停止按下键,MessageBox也会显示出来,即:我按下“将你想退出吗?“消息框出现,我说不,它消失然后立即重新出现,好像我还在拿着钥匙。

这是我的循环:

void GameRun(HWND hWnd) //called once every frame
{
    PollKeyboard();
    if(GetTickCount - start >= 30)
    {
        if(KeyDown(DIK_LEFT))
            MoveLeft();
        if(KeyDown(DIK_RIGHT))
            MoveRight();
    }

    if(d3ddev->BeginScene())
    {
        //rendering
    }

    if(KeyDown(DIK_ESCAPE))
    {
        //any MessageBox()
        int result = MessageBox(hWnd, "I'm causing so much trouble!", "IMMORTAL", MB_YESNOCANCEL);
        if(result == IDYES)
            //end
    }
}

编辑:PollKeyboard()中的捕获显示序列53gd6bcc,但我无法找到它对应的错误代码。

编辑:经过另一次测试后,我看到即使MessageBox不在KeyDown()if语句中,仍然会出现毛刺。

编辑:经过一些测试后,看来MessageBox本身正在引起故障。

2 个答案:

答案 0 :(得分:2)

因为示例代码有效,程序中的其他内容会导致错误。尝试将下面的代码移动到您自己的代码中,直到它工作,然后您将知道代码的哪一部分是罪魁祸首。

示例代码

好吧,巨大的代码块出现了。此代码适用于我。 (Escape,以及所有其他键成功激活和停用)。它很大,评论和解释相当好。试试这个,如果它有效,我们将检查你的程序的其他部分,如果没有,我只能给你带来“祝你好运”,并采取你想要的:

// DirectInput
#define DIRECTINPUT_VERSION 0x0800
#include<dinput.h>

// Standard stuff
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>

// Link from code, MSVC specific, could be done in project settings
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")

// Utility lexical_cast, use Boost if possible.
// Simple replacement, converts a stream-able `T`
// to a string
template <typename T>
const std::string lexical_cast(const T& pValue)
{
    std::stringstream ss;
    ss << pValue;

    return ss.str();
}

// Utility function + macro to execute DirectX code with exceptions.
// Kinda ugly, but helpful for us.
void check_error(HRESULT pResult, const std::string& pFuncName)
{
    // DI_OK == S_OK, but S_OK is more general, so we'll use that
    if (pResult != S_OK)
    {
        throw std::runtime_error("Error executing: " + pFuncName +
                                "! Returned: " + lexical_cast(pResult));
    }
}

// Macro, makes calling the function easier. It is wrapped in
// an `if` statement for reasons outlined in:
// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.5
#define CHECK_ERROR(x) if (true) { check_error(x, #x); } else (void)0

// The above gives the warning:
// "warning C4127: conditional expression is constant", disable below:
#pragma warning(disable: 4127)

// Manages input
class input_manager
{
public:
    // Constants
    static const int NumberKeys = 256;

    // Creation
    input_manager(void)
    {
        // Create input and keyboard (like I said, ugly macro, but helpful :] )
        CHECK_ERROR(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
            IID_IDirectInput8, reinterpret_cast<void**>(&_input), 0));


        CHECK_ERROR(_input->CreateDevice(GUID_SysKeyboard, &_keyboard, 0));
        CHECK_ERROR(_keyboard->SetDataFormat(&c_dfDIKeyboard));
        CHECK_ERROR(_keyboard->Acquire());
    }

    ~input_manager(void)
    {
        // Free resources. Note: Many programmers
        // unnecessarily wrap this stuff in
        // `if (_keyboard !=0)`, and then
        // `_keyboard = 0`. This is completely unnecessary,
        // because destructors are only run one time.

        // Also, I can assume they are valid, because if they
        // weren't, we wouldn't be here (an exception would have
        // been thrown)

        _keyboard->Unacquire();
        _keyboard->Release();
        _input->Release();

        // Also, if we wrapped this into a nice RAII class, we wouldn't
        // be forced to write a destructor, but this is outside the scope.
        // Feel free to ask how; additionally, since we're on the topic, if you'd
        // like more tips handling input (I've written PLENTY of input managers)
        // I'm free for asking about things like testing for triggers rather than pressed
        // ("was it pressed, regardless if it's being held now" versus
        // "is it being pressed"), etc.
    }

    // Operations
    void update(void)
    {
        CHECK_ERROR(_keyboard->GetDeviceState(NumberKeys, reinterpret_cast<void*>(&_keys)));
    }

    // Query
    bool key_pressed(int pKey) const
    {
        return test_key(pKey);
    }

    // Might wrap into an operator[] for convenience.

private:
    // Constants
    static const int PressMask = 0x80;

    // Sorry for the confusion, but indeed, with
    // `char`s the mask is simply 0x80.

    // Utility
    bool test_key(int pKey) const
    {
        return (_keys[pKey] & PressMask) != 0;
    }

    // Members
    LPDIRECTINPUT8 _input;
    LPDIRECTINPUTDEVICE8 _keyboard;

    char _keys[NumberKeys];
};

void test_keys(const input_manager& input)
{
    bool anyPressed = false;

    for (unsigned i = 0; i < input_manager::NumberKeys; ++i)
    {
        if (input.key_pressed(i))
        {
            std::cout << "Pressing: " << i << std::endl;

            anyPressed = true;
        }
    }

    if (!anyPressed)
    {
        std::cout << "No keys pressed." << std::endl;
    }
}

void execute(void)
{
    input_manager input;

    std::cout << "Press Q to quit." << std::endl;

    bool running = true;
    while (running)
    {
        input.update();

        if (input.key_pressed(DIK_Q))
        {
            running = false;
        }

        test_keys(input);

        Sleep(0); // give some processor time
    }
}

int main(void)
{
    // Place real code in an execute function, so main
    // is clean and ready to catch exceptions:
    try
    {
        execute();
    }
    catch (const std::exception& e)
    {
        // Error!
        std::cerr << "Unhandled exception:" << e.what() << std::endl;
    }
}

旧建议:

尝试从GetDeviceState中捕获返回值:

HRESULT result =                              // v Prefer C++-style casts
    di_keyboard->GetDeviceState(sizeof(keys), reinterpret_cast<void*>(&keys);

if (result != DI_OK)
{
    // uh-oh
    std::cout << result << std::endl;
}

将其与table here进行比较。

旧半答案:

在Extra Stuff部分的代码中编辑后不久,我意识到错误,抱歉我没有及早发现它。你正在测试错误的位:)

观察:

//                                     v HERE! Should be 0x8000, not 0x80.
return (GetAsyncKeyState(pKeyCode) & 0x8000) != 0;

试试:

int KeyDown(int key)
{
    return (keys[key] & 0x8000);
}

此外,这应该移动到常量以避免幻数:

// somewhere, probably in the private section of the class or in a detail namespace:
static const int PushedMask = 0x8000;

// code reads better:
int KeyDown(int key)
{
    return (keys[key] & PushedMask);
}

最后,在C ++中你有一个bool类型,所以要利用它!

// v here
bool KeyDown(int key)
{
    return (keys[key] & PushedMask);
}

我知道Visual Studio会警告这个从intbool的转换,所以你可以摆脱它,同时让你的意图更清晰:

bool KeyDown(int key)
{
    return (keys[key] & PushedMask) != 0; // or == 1, your choice
}

额外的东西:

请尝试以下代码:

#include <iostream>
#include <windows.h>

bool key_pressed(int pKeyCode)
{
    return (GetAsyncKeyState(pKeyCode) & 0x8000) != 0;
}

void test_keys(void)
{
    for (unsigned i = 0; i < 255; ++i)
    {
        if (key_pressed(i))
        {
            std::cout << "Pressing: " << i << std::endl;
        }
    }
}

int main(void)
{
    bool running = true;
    while (running)
    {
        if (key_pressed(VK_ESCAPE))
        {
            running = false;
        }

        test_keys();

        Sleep(0);
    }
}

这适用于我(响应所有键,退出时退出)。 GetAsyncKeyState的最小测试用例。如果这有效,请在评论中添加操作系统,键盘等。

答案 1 :(得分:1)

如果您创建MessageBox(Null,...),则在创建窗口后您将无法控制窗口。 IE,按下键时窗口不会消失。

至于为什么它一直出现,似乎与此有关:

const int input_bit_num = 0x8000;
char keys[256];
bool KeyDown(int key)
{
    return (keys[key] & input_bit_num) != 0;
}

键由1个字节长的字符组成,而input_bit_num是2个字节的值。虽然我老实说不知道你正在寻找哪一位(0xff - 0x00是1字节的域)。

老实说,我对你的代码运行感到惊讶,除非&amp;操作正在转入键[key-1],在这种情况下,任何KeyDown都是未定义的,当key为0时,KeyDown(...)特别危险。