हैंडलिंग कीबोर्ड और माउस इनपुट (जीत एपीआई)


11

विंडोज के तहत माउस या कीबोर्ड को पकड़ने के कई तरीके हैं। इसलिए मैंने उनमें से कुछ की कोशिश की, लेकिन उनमें से प्रत्येक के कुछ फायदे और कमियां हैं। मैं आपसे पूछना चाहता हूं: किस विधि का उपयोग करें?

मैंने इन्हें आज़माया है:

  1. WM_KEYDOWN / WM_KEYUP - मुख्य नुकसान यह है कि, मैं बाएँ और दाएँ हाथ की कुंजियों जैसे कि ALT, CONTROL या SHIFT के बीच अंतर नहीं कर सकता।

  2. GetKeyboardState - यह पहली विधि की समस्या को हल करता है, लेकिन एक नया है। जब मुझे लगता है कि राइट-एएलटी कुंजी दबाया जाता है, तो मुझे यह भी पता चलता है कि लेफ्ट-कंट्रोल कुंजी नीचे है। यह व्यवहार स्थानीयकृत कीबोर्ड लेआउट (चेक - सीएस) का उपयोग करते समय ही होता है।

  3. WM_INPUT (रॉ इनपुट) - यह विधि बाएं और दाएं हाथ की चाबियाँ (यदि मैं याद रख सकता हूं) को अलग नहीं करता है और माउस आंदोलन के लिए कभी-कभी माउस स्थिति के शून्य डेल्टा मानों के साथ संदेश उत्पन्न करता है।

जवाबों:


10

इसका सबसे अच्छा और सरल तरीका यह है कि आप अपने पहले विचार का उपयोग करें और WM_KEYUP / WM_KEYDOWN संदेशों के साथ-साथ WM_SYSKEYUP / WM_SYSKEYDOWN संदेशों को भी हैंडल करें। ये लेफ्ट और राइट शिफ्ट / कंट्रोल / अल्ट कीज के बीच अंतर का पता लगाने में मदद कर सकते हैं, आपको बस उपयुक्त की जरूरत है वर्चुअल की कोड की जरूरत है । वे VK_LSHIFT / VK_RSHIFT, VK_LCONTROL / VK_RCONTROL, और VK_LMENU / VK_RMENU (ALT कुंजी के लिए) हैं।

मैंने एक पोस्ट लिखा कि मैंने यह कैसे किया, और मैं एक ही हैंडलर में WM_KEYUP / WM_KEYDOWN और WM_SYSKEYUP / WM_SYSKEYDOWN दोनों को संभाल रहा था। (दुर्भाग्य से, ब्लॉग अब उपलब्ध नहीं है।)

एकमात्र जटिलता जो मैं देख सकता हूं, क्योंकि आप एक गैर-यूएस कीबोर्ड का उपयोग कर रहे हैं, जिसे आपको MSDN पर WM_SYSKEYUP लेख में वर्णित अनुक्रम को संभालने के लिए कुछ अतिरिक्त तर्क में जोड़ने की आवश्यकता होगी । हालाँकि मैं शायद मास्टेरियोडा की तुलना में कुछ सरल बनाने की कोशिश करूंगा।


WM_ संदेश निश्चित रूप से सबसे सरल हैं, लेकिन "सर्वश्रेष्ठ" केवल तभी यदि आप मिस्ड इवेंट्स की परवाह नहीं करते हैं। एक बार मुझे पता चला कि यह एक अचूक समस्या थी, मैंने उस समाधान को छोड़ दिया; यदि आपका एप्लिकेशन किसी कुंजी के डाउन होने पर फोकस खो देता है, तो यह कुंजी "अटक" जाएगी जब तक कि आप इसे फिर से फोकस में नहीं दबाते।
डैश-टॉम-बैंग

1
वास्तव में लापता इनपुट एक समस्या है, लेकिन सबसे आसान समाधान उचित रूप से फोकस / सक्रियण संदेशों को संभालना और इसके चारों ओर काम करना होगा। व्यावहारिक रूप से आप जो करना चाहते हैं, वह गेम को रोकना है जब आप फोकस खो देते हैं, क्योंकि उपयोगकर्ता को किसी अन्य तत्काल आवेदन पर टी स्विच करने की आवश्यकता हो सकती है, या वे गलती से विंडोज़ कुंजी मारते हैं।
डेमिन

3

क्या कोई कारण है कि आप उन्हें जोड़ नहीं सकते? उदाहरण के लिए, Ctrl / Alt / Shift कुंजी के प्रेस का पता लगाने के लिए WM_KEYDOWN का उपयोग करें, फिर उस कॉल के भीतर GetKeyboardState () को दाईं ओर से अलग करने के लिए उपयोग करें?


हाँ मैं कर सकता हूँ। मैं शायद इस समाधान के साथ समाप्त हो जाएगा (शायद GetAsyncKeyState का उपयोग करना बेहतर होगा)। लेकिन मैं किसी भी बेहतर समाधान की तलाश कर रहा हूं यदि कोई मौजूद है। और राइट-एटीएल कुंजी दो WM_KEYDOWN संदेश भी भेजती है (कीबोर्ड लेआउट के कारण)। तो केवल WM_INPUT या DirectInput ही रहता है।
डीलक्स

3

WM_INPUT अच्छा है। मुझे लगता है कि आप RAWKEYBOARD संरचना का उपयोग करके बाएँ / दाएँ कुंजियों को भेद सकते हैं । कठिन हिस्सा यह पता लगा सकता है कि प्रमुख पहचानकर्ताओं (यानी स्कैन्कोड्स) से कैसे निपटना है, लेकिन मैं यह नहीं कह सकता कि मैंने कीबोर्ड इनपुट के लिए इसका उपयोग करने की कभी कोशिश नहीं की है। WM_KEYDOWN इतना आसान है :)

मैंने माउस इनपुट के लिए WM_INPUT का उपयोग किया है, हालाँकि। यह बहुत निम्न स्तर का है। इसमें कोई त्वरण लागू नहीं है, जो बहुत अच्छा है (IMO)। WM_INPUT हाई-डीपीआई मूवमेंट का लाभ उठाने का एकमात्र तरीका हुआ करता था, लेकिन मुझे यकीन नहीं है कि यह अभी भी है। इस MSDN लेख को 2006 से देखें ।

प्रत्यक्ष रूप से माउस / कीबोर्ड के लिए Microsoft द्वारा स्पष्ट रूप से हतोत्साहित किया जाता है। पहले से लिंक किए गए MSDN लेख देखें। यदि आपको जॉयस्टिक की आवश्यकता है, तो XInput शायद जाने का रास्ता है।

संपादित करें: इस पर मेरी जानकारी बहुत दिनांकित हो सकती है।


3

असल में, WM_KEYDOWN / WM_KEYUP को पकड़ने पर आप L / R Ctrl / Alt के अलावा बता सकते हैं। आसान है, यह नहीं है, लेकिन जो कोड मैं उपयोग करता हूं, यहां आपके पास, हम्म हम्म हो सकता है।

आशा है कि यह अभी भी काम करता है, मैं करता हूँ।

// Receives a WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN or WM_SYSKEYUP message and 
// returns a virtual key of the key that triggered the message.
// 
// If the key has a common virtual key code, that code is returned. 
// For Alt's and Ctrl's, the values from the KeyCodes enumeration are used.
int translateKeyMessage (MSG& Msg);

// Virtual key codes for keys that aren't defined in the windows headers.
enum KeyCodes
{
    VK_LEFTCTRL = 162,
    VK_RIGHTCTRL = 163,
    VK_LEFTALT = 164,
    VK_RIGHTALT = 165
};

// ======================================================================================

int translateKeyMessage (MSG& Msg)
{
    // Determine the virtual key code.
    int VirtualKeyCode = Msg.wParam;

    // Determine whether the key is an extended key, e.g. a right 
    // hand Alt or Ctrl.
    bool Extended = (Msg.lParam & (1 << 24)) != 0;

    // If this is a system message, is the Alt bit of the message on?
    bool AltBit = false;    
    if (Msg.message == WM_SYSKEYDOWN || Msg.message == WM_SYSKEYUP)
        AltBit = (Msg.lParam & (1 << 29)) != 0;

    if ((Msg.message == WM_SYSKEYUP || Msg.message == WM_KEYUP) && !Extended && !AltBit && VirtualKeyCode == 18)
    {
        // Left Alt
        return KeyCodes::VK_LEFTALT;
    }

    // Left Ctrl
    if (!Extended && !AltBit && VirtualKeyCode == 17)
    {
        // Peek for the next message.
        MSG nextMsg;
        BOOL nextMessageFound = PeekMessage(&nextMsg, NULL, 0, 0, PM_NOREMOVE);

        // If the next message is for the right Alt:
        if (nextMessageFound && nextMsg.message == Msg.message && nextMsg.wParam == 18)
        {
            //
            bool nextExtended = (nextMsg.lParam & (1 << 24)) != 0;

            //
            bool nextAltBit = false;    
            if (nextMsg.message == WM_SYSKEYDOWN || nextMsg.message == WM_SYSKEYUP)
                nextAltBit = (nextMsg.lParam & (1 << 29)) != 0;

            // If it is really for the right Alt
            if (nextExtended && !nextAltBit)
            {
                // Remove the next message
                PeekMessage(&nextMsg, NULL, 0, 0, PM_REMOVE);

                // Right Alt
                return KeyCodes::VK_RIGHTALT;
            }
        }

        // Left Ctrl
        return KeyCodes::VK_LEFTCTRL;
    }

    if (Msg.message == WM_SYSKEYUP && !Extended && AltBit && VirtualKeyCode == 17)
    {
        // Peek for the next message.
        MSG nextMsg;
        BOOL nextMessageFound = PeekMessage(&nextMsg, NULL, 0, 0, PM_NOREMOVE);

        // If the next message is for the right Alt:
        if (nextMessageFound && nextMsg.message == WM_KEYUP && nextMsg.wParam == 18)
        {
            //
            bool nextExtended = (nextMsg.lParam & (1 << 24)) != 0;

            //
            bool nextAltBit = false;    
            if (nextMsg.message == WM_SYSKEYDOWN || nextMsg.message == WM_SYSKEYUP)
                nextAltBit = (nextMsg.lParam & (1 << 29)) != 0;

            // If it is really for the right Alt
            if (nextExtended && !nextAltBit)
            {
                // Remove the next message
                PeekMessage(&nextMsg, NULL, 0, 0, PM_REMOVE);

                // Right Alt
                return KeyCodes::VK_RIGHTALT;
            }
        }
    }

    // Right Ctrl
    if (Extended && !AltBit && VirtualKeyCode == 17)
        return KeyCodes::VK_RIGHTCTRL;

    // Left Alt
    if (!Extended && AltBit && VirtualKeyCode == 18)
        return KeyCodes::VK_LEFTALT;

    // Default
    return VirtualKeyCode;
}

1
कोड के लिए +1, लेकिन योदा की तरह बोलने के लिए -1। यह कष्टप्रद है और आपके उत्तरों को पढ़ना कठिन बनाता है।
एंथनी

वास्तव में, यह मजाक खातों के लिए जगह नहीं है।
कोडरंग जूल

2

आप DirectInput API या हाल ही में, XInput API आज़मा सकते हैं


1
क्या XImput केवल XBox 360 नियंत्रक के लिए पीसी से जुड़ा नहीं है? मैंने पढ़ा है DirectInput थोड़ा अप्रचलित है, इसलिए मैंने इसका उपयोग करने से बचने की कोशिश की है। लेकिन मैंने DirectInput को भी आज़माया है और अच्छी तरह से जीता है।
डीलक्स

XInput केवल गेमपैड के लिए ही है। विंडोज 10 के रूप में, XInput को 'IGamepad' इंटरफेस के पक्ष में चित्रित किया गया है। उसके ऊपर आपको अन्य तंत्रों पर RAW_INPUT का उपयोग करना चाहिए, क्योंकि उन पर सीमाएँ हैं।
लावोलपे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.