Archived

This topic is now archived and is closed to further replies.

Keyboard remapping?

This topic is 5576 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Okay, I can do a simple switch statement to check for the keysym(I''m using SDL, btw), and execute a member function. Now, what if I want to give the user the ability some time to alter the keys he uses? Switch statements only work on constants. My first thought was simply to have the switch statement execute the function on the other side of a function pointer. However, I don''t want to have bad programming practice by making a bunch of global functions(I''m trying to use an object-oriented approach). The solution, of course, is to make them point to a member function. However, a function pointer works only for a given signature, which includes the class of which it is a member. I either couldn''t figure out the syntax to do so, or it is impossible to cast a generic void(*)() to a class-specific void(myclass::*)(). So, I tried to think of a generic architecture that would allow me to remap keys that would be possible to connect to each of the various classes that control the program at different times. I want each class that controls execution to hold the functions that execute while under its control. I''m stumped.

Share this post


Link to post
Share on other sites
quote:
Original post by Flarelocke
However, a function pointer works only for a given signature, which includes the class of which it is a member. I either couldn''t figure out the syntax to do so, or it is impossible to cast a generic void(*)() to a class-specific void(myclass::*)().

Well, I can''t tell you the syntax either, but it is possible to use a member function pointer like that, so scour your docs

quote:
So, I tried to think of a generic architecture that would allow me to remap keys that would be possible to connect to each of the various classes that control the program at different times.

I try not to make things too generic, as you end up writing a library rather than a game. A simple approach is to have a KeyBinder class that stores mappings of keypresses to actions. Actions are your in-game concepts like turn left, fire, select item, whatever. So you just get the keypress, send it to the KeyBinder class to be translated, and then switch on the return value.

If you need different key assignments for different parts of the program, consider deriving KeyBinder child classes that each have different lists of actions... one for menus, one for in the game, and so on.

The KeyBinder class can also be responsible for reading and writing itself to disk so that the bindings can be persistent.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files | My stuff ]

Share this post


Link to post
Share on other sites
I''m in college right now, and I left all my programming books at home. The most informative(and it''s quite informative) page I could find is:
http://www.newty.de/CCPP/FPT/em_fpt.html

I don''t really have a problem with writing code that''s generic enough to be used in a library because this game is more a learning experience than a marketable game(it''s just a clone of a little-known but very addictive DOS game. Which had some really annoying default keys that could not be changed, hence my question), and writing generic code is, I suppose, more difficult than writing just a game.

I''ve tried:
    alternate = reinterpret_cast(tester1.myfunc);

    alternate = reinterpret_cast(tester1.*myfunc);

    alternate = reinterpret_cast(tester1::myfunc);

    alternate = reinterpret_cast(tester1.&myfunc);


        alternate = dynamic_cast(tester1.myfunc);

        alternate = dynamic_cast(tester1.*myfunc);

        alternate = dynamic_cast(tester1.&myfunc);

        alternate = dynamic_cast(tester1::myfunc);


And the same with static cast, but I never really expected that to work. No luck. And this is the easier version with casting a base class function pointer to a derived class function pointer.

I keep getting two errors, the first of which is always different but the second of which is always the same:
"pointer to member function called, but not in class scope"

How, may I ask, do you know it''s possible? It''s quite possible that such functionality works as per standard in GCC(I think I have 2.95, or whatever version it is everyone uses). It''s also possible that a compiler isn''t supposed to be able to do this.

See what this site has to say:
quote:
C++ has a lot of things going on under the hood such as hidden arguments to methods. Pointers to members allow you to safely declare a pointer to a class method and call methods through that pointer.


Anyway,
quote:
A simple approach is to have a KeyBinder class that stores mappings of keypresses to actions. Actions are your in-game concepts like turn left, fire, select item, whatever. So you just get the keypress, send it to the KeyBinder class to be translated, and then switch on the return value.
Okay, I think I get it.

Why would subclassing be necessary? I can envision a template(different enums would be used as the template parameter) or different instances(the numbers casted to different enums from the integer internal, or simply reinterpretted based on a different set of integer/action definitions). Hmm. Now that I think about it, the action-finder function could be overrided to cast to a different enum.

From all the replies I got, can I surmise that not many people understand function pointers, let alone pointers-to-member-functions?

Share this post


Link to post
Share on other sites
Here''s something you might want to have a look at:


  

typedef void (*)( ) KeyboardEvent;

class CKeyboard
{

std::map<unsigned char, KeyboardEvent> vecKeyboardBuffer;

};


Now you can use vecKeyboardBuffer to map a key to a function.

Hope this helps!



-G|aD-

Share this post


Link to post
Share on other sites
But not a member function of an arbitrary class or arbitrary derived class from a specific base class, which was my original dilema. Try it if you don''t believe me.

The actions I need to take will require the input of much of the state of the game. This state is, as per standard OO practice, contained within a class.(several classes, one of which corresponds to a round of gameplay, one for the entity controlled by the player, and one for the entity spawned by firing a missile) I don''t want to make all these actions public; ideally they''d be contained within the class that contains the entity controlled by the player. I don''t want a bunch of global functions; the only one I have right now is main(), which is enough for me.(main()''s only about 4 lines long because it simply instantiates the class that does most of the work) OO design doesn''t work well with a bunch of global functions.

Share this post


Link to post
Share on other sites
Sure you can, here''s an example of using function pointers to member functions.


  

// printf...

#include <stdio.h>

// forward class declaration

class CMyClass;

// function pointer to a function from CMyClass

typedef void (CMyClass::*FuncEvent)(void);

// CMyClass definition

class CMyClass
{

public:

// func1

void func1(void)
{

printf("This is func1\n");

};

//func2

void func2(void)
{

printf("This is func2\n");

};

};

int main(int argc, char* argv[])
{

// we MUST create an instance of myClass object in order to get the addresses of the functions, otherwise those functions do not exists (a class is just that, an interface of how the object should look in memory once created)


CMyClass myClass;

// function pointer to a CMyClass member function

FuncEvent myEvent;

// assign the function pointer func1

myEvent = &CMyClass::func1;

// call the first functoin through function pointer

(myClass.*myEvent)();

// do the same for second function

myEvent = &CMyClass::func2;
(myClass.*myEvent)();

return 0;
}




Hope this helps!



-G|aD-

Share this post


Link to post
Share on other sites
Thanks!

For those of you who have been watching at home, the syntax I was looking for was:

alternate = reinterpret_cast(&test1::myfunc); 


I figured it required an instance instead of a class at which to point, but instead it requires a class, and an instance is used instead in the call to the pointer. Here''s how I called it:

(tester1.*alternate)(); 


btw, tester1 is an instance of test1, which is derived from an abstract base class called base.

Share this post


Link to post
Share on other sites
Because it doesn''t work without one

The pointer is to a member of the base class, not to the test class. I haven''t reduced it to the simplest possible case in which it would work yet.(It might allow from an arbitrary class to test1, it might allow a global function to test1::*, I''m not sure yet. I think I have enough information now.)

I suppose posting my full test code would be helpful as well:

  
#include <iostream>
#include <cstdlib>

class base{
public:
virtual void myfunc() = 0;
};

class test1 : public base{
public:
void myfunc();
};


class test2 : public base{
public:
void myfunc();
};


void (base::*alternate)(void);

int main(){
test1 tester1;
test2 tester2;

alternate = reinterpret_cast<void(base::*)()>(&test1::myfunc);
(tester1.*alternate)();
alternate = reinterpret_cast<void(base::*)()>(&test2::myfunc);
(tester2.*alternate)();

std::system("pause");
return 0;
}

void test1::myfunc(){
std::cout << "test1.myfunc()" << std::endl;
}

void test2::myfunc(){
std::cout << "test2.myfunc()" << std::endl;
}


I was pleased to find(accidentally) that the code doesn''t work if you change the inheritance from public to private.

I decided your method was best anyway. I would have to make my methods public, which is not as good an idea as simply using a keymap class to store and translate actions.

Share this post


Link to post
Share on other sites