Pointer To A Pointer Problem

Posted By: 3Dski

Pointer To A Pointer Problem - 10/23/07 17:49

I want to write my own key mapping maintenance routines. The goal I wanted to achieve is, store the location of "on_cul", and others into array locations. I would have another array that stores the current event function that "on_cul", and others, were pointing. Then, when I want to restore "on_cul", I would be able to loop through the array to reset what "on_cul", and others, are pointing at, as opposed to writing item-by-item lines of code. I'm thinking that the storage for "on_cul", for example, would need to be a pointer to a pointer, void**.

I've tried a good number of syntax variations to try to do this without any success. Is what I'm describing even possible in Lite-C? Any help would be greatly appreciated!
Posted By: Uhrwerk

Re: Pointer To A Pointer Problem - 10/23/07 19:02

on_cul is not ideal to achieve what you're trying to do. Better store the function pointers in an array or any other data structures and catch the on_key event. The scancode of the key pressed is passed as a parameter to that function.

The right syntax for a pointer to a function pointer is void** as you already found out.
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/23/07 19:40

What I hear you saying is, an alternative would be ot drop the use of the existing on_* handlers and create my own... because, you cannot save on_* in an array element in such a way as to allow changing what it is pointed an array element? The is a hack example of what I was intending to do:

function myfunction();

handler_store[1] = &on_a; // save location of on_a(?)
...
**handler_store[1] = myfunction; // indirectly change what on_a points to (?)

ALTERNATIVELY...

function key_event_one();
function key_event_two();
function handle_key(var scancode);
...
void* events[...];
...
// Initialize event handler array; index associated with scan code...
event[1] = key_event_one;
event[2] = key_event_two;

// Set on_anykey to generic handler function...
on_anykey = handle_key;

function handle_key(var scancode)
{
// Get handler from array of handlers and execute....
void* handler = event[scancode];
handler();
}
Posted By: i_program_games

Re: Pointer To A Pointer Problem - 10/23/07 20:11

This may be accomplished by wrapper functions as per my example below.

#define ON_A 0
#define ON_B 1

function* pFunctions[2]; //pointer to an array of size 2
function pFunction(function*); //a function pointer to a function accepting a function pointer

function SetOnA(function* pFunction)
{
on_a = pFunction; //indirectly set on_a
}

function SetOnB(function* pFunction)
{
on_b = pFunction; //indirectly set on_b
}

function BeepOnce()
{
beep();
}

function BeepTwice()
{
beep();
beep();
}

function main()
{
//Assign functions to the array.
pFunctions[ON_A]=SetOnA;
pFunctions[ON_B]=SetOnB;

pFunction = pFunctions[ON_A];
pFunction(BeepOnce);//set pointer to our OnSetA wrapper function;

//Uncomment to see that this works too.
//pFunction = pFunctions[ON_B];
//pFunction(BeepOnce);//set pointer to our OnSetB wrapper function;

}
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/23/07 21:12

I understand and this is certainly an good alternative. The only think I don't like is overhead of creating all the wrapper methods each of the on_*, then setting each into the array. I'm certainly going to keep your suggestion in mind, in the event that I run across a problem doing it the other way:


#define KB_ESC 1 // esc;
#define KB_1 2 // 1;
#define KB_2 3 // 2;
...
function init_key_map()
function save_key_map()
function restore_key_map()
function map_key(int scode, function* func)
function handle_keys(int scode);

function* key_map[88]; // main map
function* key_map_cache[88]; // temp store to restore main map
...
function init_key_map()
{
int i;
for( i = 0;i < 89; i++)
{
current_key_mapping = NULL; // NULL;
}
}

function save_key_map()
{

int i;
for( i = 0; i < 89;i++)
{
key_map_cache = key_map;
}
}

function restore_key_map()
{
int i;
for( i = 0; i < 89; i++)
{
key_map = key_map_cache;
}
}

function map_key(int scode, function* func)
{
if (scode > 0 && scode < 89)
{
key_map[scode] = func;
}
}

function handle_keys(int scancode)
{
function* handler = key_map[scancode];
if ( handler != null ) handler();
}

on_anykey = handle_keys;

save_key_map() allows you to backup gaming key mapping in the event that you want to change the mapping while in a menu. When leaving the menu, restore_key_map() could be called to reset gaming keys. Setting a key event would be done with a call like, map_key(KB_1, myFunct).
Posted By: i_program_games

Re: Pointer To A Pointer Problem - 10/23/07 21:26

If you get it to work directly the way you imply please post the solution here as it would be more flexible.
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/23/07 22:52

I've got it to work in preliminary work, but with some minor changes to the above. One major problem I'm having right now is I didn't include for mappings into mouse and joy stick which made my program blow up when I'd click the mouse. I need to work out some logic to include the mouse and joystick scan codes into my array mapping.

Also, if you include default.c, it includes defs for key events, as well as debug. This means if you want to use default.c for debugging, then you'ld have to reset the events to the keys there to a nothing() function in your own code.

I'll post the code after I get a more complete solution... but, it's good to know that it can work with little difficulty... so far : )
Posted By: i_program_games

Re: Pointer To A Pointer Problem - 10/24/07 00:06

What about shoving some functionality into a struct. I'll work on this with you as I'll be needing this functionality soon.
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/24/07 04:31

Actually, I did start out think of putting key into into a array of structs, but decided against it. But, maybe you have a different slannt on it where it might become more worthwhile. I was going to place the code over in contributions, but if we're polishing, then it's probably best to be here. Here's my first hack that seems to be working pretty good. I'm having problems with the default handlers in might code, which might just be an interaction between my general environment and default handler code itself... not the new key-handler mapping scheme...

Code:

// SCAN CODE HANDLER DEFINES
#define KB_ESC 1 // on_esc;
#define KB_1 2 // on_1;
#define KB_2 3 // on_2;
#define KB_3 4 // on_3;
#define KB_4 5 // on_4;
#define KB_5 6 // on_5;
#define KB_6 7 // on_6;
#define KB_7 8 // on_7;
#define KB_8 9 // on_8;
#define KB_9 10 // on_9;
#define KB_0 12 // on_0;
#define KB_MINUS 13 // on_minusc;
#define KB_EQUALS 14 // on_equals;
#define KB_BKSP 14 // on_bksp;
#define KB_TAB 15 // on_tab;
#define KB_Q 16 // on_q;
#define KB_W 17 // on_w;
#define KB_E 18 // on_e;
#define KB_R 19 // on_r;
#define KB_T 20 // on_t;
#define KB_Z 21 // on_z;
#define KB_U 22 // on_u;
#define KB_I 23 // on_i;
#define KB_O 24 // on_o;
#define KB_P 25 // on_p;
#define KB_BRACKL 26 // on_brackl;
#define KB_BRACKR 27 // on_brackr;
#define KB_ENTER 28 // on_enter;
#define KB_CTRL 29 // on_ctrl;
#define KB_A 30 // on_a;
#define KB_S 31 // on_s;
#define KB_D 32 // on_d;
#define KB_F 33 // on_f;
#define KB_G 34 // on_g;
#define KB_H 35 // on_h;
#define KB_J 36 // on_j;
#define KB_K 37 // on_k;
#define KB_L 38 // on_l;
#define KB_SEMIC 39 // on_semic;
#define KB_APOS 40 // on_apos;
#define KB_GRAVE 41 // on_grave;
#define KB_SHIFTL 42 // on_shiftl;
#define KB_BKSL 43 // on_bksl;
#define KB_Y 44 // on_y;
#define KB_X 45 // on_x;
#define KB_C 46 // on_c;
#define KB_V 47 // on_v;
#define KB_B 48 // on_b;
#define KB_N 49 // on_n;
#define KB_M 50 // on_m;
#define KB_C 51 // on_comma;
#define KB_PERIOD 52 // on_period;
#define KB_SLASH 53 // on_slash;
#define KB_SHIFTR 54 // on_shiftr;
#define KB_ALT 56 // on_alt;
#define KB_SPACE 57 // on_space;
#define KB_CAPS 58 // on_caps;
#define KB_F1 59 // on_f1;
#define KB_F2 60 // on_f2;
#define KB_F3 61 // on_f3;
#define KB_F4 62 // on_f4;
#define KB_F5 63 // on_f5;
#define KB_F6 64 // on_f6;
#define KB_F7 65 // on_f7;
#define KB_F8 66 // on_f8;
#define KB_F9 67 // on_f9;
#define KB_F10 68 // on_f10;
#define KB_PAUSE 69 // on_pause;
#define KB_SCRLK 70 // on_scrlk;
#define KB_HOME 71 // on_home;
#define KB_UARROW 72 // on_cuu;
#define KB_PGUP 73 // on_pgup;
#define KB_LARROW 75 // on_cul;
#define KB_RARROW 77 // on_cur;
#define KB_END 79 // on_end;
#define KB_DRRROW 80 // on_cud;
#define KB_PGDN 81 // &on_pgdn;
#define KB_INS 82 // on_ins;
#define KB_DEL 83 // on_del;
#define KB_F11 87 // on_f11;
#define KB_F12 88 // on_f12;
// ... JOY STICK BUTTONS
#define JOY_1 89 // 256 on_joy1
#define JOY_2 90 // 257 on_joy2
#define JOY_3 91 // 258 on_joy3
#define JOY_4 92 // 259 on_joy4
#define JOY_5 93 // 260 on_joy5
#define JOY_6 94 // 261 on_joy6
#define JOY_7 95 // 262 on_joy7
#define JOY_8 96 // 263 on_joy8
#define JOY_9 97 // 264 on_joy9
#define JOY_10 98 // 265 on_joy10
#define JOY_11 99 // 266 on_joy11
#define JOY_12 100 // 267 on_joy12
#define JOY_2_1 101 //268 on_joy2_1
#define JOY_2_2 102 // 269 on_joy2_2
#define JOY_2_3 103 // 270 on_joy2_3
#define JOY_2_4 104 // 271 on_joy2_4
#define JOY_2_5 105 // 272 on_joy2_5
#define JOY_2_6 106 // 273 on_joy2_6
#define JOY_2_7 107 // 274 on_joy2_7
#define JOY_2_8 108 // 275 on_joy2_8
#define JOY_2_9 109 // 276 on_joy2_9
#define JOY_2_10 110 // 277 on_joy2_10
#define JOY_2_11 111 // 278 on_joy2_11
#define JOY_2_12 112 // 279 on_joy2_12
// ... MOUSE BUTTONS
#define MB_LEFT 113 // 280 on_mouse_left
#define MB_RIGHT 114 // 281 on_mouse_right
#define MB_MIDDLE 115 //282 on_mouse_middle
#define MAX_KEY_POS 115
#define LAST_KB_KEY 88
#define SCAN_CODE_MARGIN 166

// KEYBOARD MAPPING PROTOTYPES
void disable_onkey_defaults();
void init_key_map();
void map_default_keys();
void cache_key_map();
void restore_key_map();
void map_key(var scode, void* funct);
void handle_key(var scode);
void handler_function(); // ... pointer to retrieve handler from arraay
void nothing(); // ... do nothing handler to disable default on_*

void* key_map[88]; // ... main key-handler storage
void* key_map_cache[88]; // ... backup for key_map[]; forsave and restore

/////////////// FUNCTIONS /////////////////////////
// Sets key_map and key_map_cache
// elements to NULL.
void init_key_map()
{
int i;
for( i = 0;i <= MAX_KEY_POS; i++)
{
key_map[i] = NULL;
key_map_cache[i] = NULL;
}
}

// Copies key_map elements to key_map_cache
// for later restoration.
void cache_key_map()
{
int i;
for( i = 0; i <= MAX_KEY_POS;i++)
{
key_map_cache[i] = key_map[i];
}
}

// Restores key_map elements; copies key_map_cache
// elements back to key_map.
void restore_key_map()
{
int i;
for( i = 0; i <= MAX_KEY_POS; i++)
{
key_map[i] = key_map_cache[i];
}
}

// Creates a key-event mapping based on the given
// scan code (scode) and the handler (funct).
void map_key(var scode, void* funct)
{
if (scode > 0 && scode <= MAX_KEY_POS )
{
key_map[scode] = funct;
}
}

// Maps keys traditionally mapped in default.c using
// the mapping array system (key_map[]).
void map_default_keys()
{
// Only allow these logic if default.c has been include...
#ifdef default_c
disable_onkey_defaults();
// ...disable default.c on_* settings for keys

// Reset the defaults into custom mapping array...
map_key(KB_F2, def_save);
map_key(KB_F3, def_load);
// map_key(KB_F5, def_video); ... problem with this event with my current code
map_key(KB_F4, def_exit);
map_key(KB_F6, def_shot);
// map_key(KB_F11, def_debug); ... problem with this event with my current code
map_key(KB_F12, def_sound);
map_key(KB_0, def_moveset);
map_key(KB_ENTER, def_screen);
map_key(KB_TAB, def_console);
// I use this to toggle my menu panel on and off...
// map_key(KB_ESC, show_main_menu);
#endif
}

// Generic key event handler meant to be used with on_anykey.
void handle_key(var scode)
{
int converted = scode;
// Scancode is 255 to 282 for joystick and mouse,
// so adjust index down to available map position (89 through 115))
if ( scode > LAST_KB_KEY ) converted -= SCAN_CODE_MARGIN;
handler_function = key_map[converted];
if ( handler_function != NULL)
{
handler_function();
}
}

void nothing(){}

// Ensure that keys mapped via default.c are
// disabled in the on_* domain.
// NOTE: Because, on_* = NULL didn't seem
// to be effective from main().
void disable_onkey_defaults()
{
on_f2 = nothing;
on_f3 = nothing;
on_f5 = nothing;
on_f4 = nothing;
on_f6 = nothing;
on_f11 = nothing;
on_f12 = nothing;
on_0 = nothing;
on_enter = nothing;
on_tab = nothing;
on_esc = nothing;
}



I'm not fully understanding "freeze_mode" and I'm not sure whether it should be used during the operation of swapping key event handlers, so know I need to investigate this. I think the code is pretty straight forward. Let me know what you think.
Posted By: i_program_games

Re: Pointer To A Pointer Problem - 10/24/07 21:01

Looks straight forward as you say. However, why the pointer to void in map_key. I assume it works this way with all but def_video and def_debug. Also, I assume def_video and def_debug are in default.h? You'll have to play around with freeze_mode to really understand what it does as it's difficult to explain with words even though the documentation gives a description. I'll be looking into shoving this into a struct if it makes any sense. Keep up the good work
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/24/07 22:28

MISTAKE:

void* key_map[88
void* key_map_cache[88]

Should be...
void* key_map[MAX_KEY_POS];
void* key_map_cache[MAX_KEY_POS];

DON'T KNOW THAT GOT MESSED UP : (


The purpose of "void *" is the general specification for a function pointer, which the handlers are. All the def_* methods are default handlers defined in defaults.c, which is the reason for the "#ifdef default_c" (which gets defined if included). Haven't dug deep enough to know why def_video() and def_def_debug() crash when invoked in this code, as opposed to the setting them to their respective "nn_*" EVENT objects.

One odd thing is, Lite-C doesn't like locally defined function pointers, so you have to define one globally for use in functions... I hate this, but I guess this rule might relate of the "clean-up" methodology they built into the engine.

The use of a struct might be good to hold at least the key's literal name its corresponding handler's pointer. You wouldn't need to cache the key's name, so I would probably leave the caching array as is, but store the structs into the key_map[]. The key's name would only really be useful when providing an interface to see and change their key mapping, which is a good feature.

I'll keep playing and testing. I really need to learn how to effectly use debugging, which isn't as clean as I'm used to (Eclipse IDE, with JAVA).
Posted By: i_program_games

Re: Pointer To A Pointer Problem - 10/25/07 03:09

With debugging I create temporary global variable with debug in the name and set them to the value I want to see. For example debugStartPoint=startPoint; I haven't found a way for the debugger to allow local variables to be seen so this is my reason for it. I'm hacking the struct now and will post shortly.
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/25/07 03:37

Great! It's to bad that the debugging capabilities aren't a little more robust. By the way, that fix to the index in the declaration of the 2 arrays fixed the problem with those couple def_* functions... I'm surprised it even ran at all! I tried to run again when I was playing with my struct idea, had problems, so commented out to original code and crashed before things even really got running, which caused me to reexamine my shortcomings : )

For debugging... you just create a panel to display your debug* vars?
Posted By: i_program_games

Re: Pointer To A Pointer Problem - 10/25/07 04:02

Ok, I've hacked together a general on_anykey function which captures the scancode and resolves them via the key_mapping array. Anyway, here is what you were probably already thinking. As such I see no need for a struct at this time.

P.S. You have KB_C defined twice, once for the c key and once for the comma key. I changed it to KB_COMMA.


Implementation:

//Test Functions:
function BeepOnce()
{
beep();
}

function BeepTwice()
{
beep();
beep();
}
//End Test Functions

void gpFunction();//global function pointer

//function to handle input
function processInput(scancode)
{
gpFunction=key_map[scancode];
gpFunction();
}

function main()
{
map_key(KB_B, BeepOnce);
map_key(KB_C, BeepTwice);

on_anykey = processInput;
}
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/25/07 05:06

You got it right on the head! Now, I made one last change. I removed the call to disable_onkey_defaults() from the top of map_default_keys() and placed it at the top of init_key_map(). This makes more sense, since this is where we want to make sure the any on_* events are not set, while we are preping our own handling array. disable_onkey_defaults() is only called once, so it could really be removed, with its logic being moved to the top of init_key_map(). What do you think?

What got me going on this effort is, I was designing a intro splash screen, a main menu, with an options sub menu. I needed a way to turn off the keys during the splash screen display. I also want to add the ability to provide keyboard navigation of the menus when they're being displayed, but return back to the game mapping when they are closed.
Posted By: i_program_games

Re: Pointer To A Pointer Problem - 10/25/07 07:06

Yes, disable_onkey_defaults() should only be called once. I also believe I see the value of this architecture. I think that we need an array of arrays allowing for several different key mapping "sets". For example:

//Pseudocode

#define MAIN_MENU, 0
#define OPTIONS_MENU,1

//individual key sets
var arKeySetMainMenu[88];
var arKeySetOptionsMenu[88];

//all key sets
var arKeySets[2][88];

arKeySets[MAIN_MENU][KB_A]=arKeySetMainMenu[KB_A];
arKeySets[MAIN_MENU][KB_B]=arKeySetMainMenu[KB_B];

arKeySets[OPTIONS_MENU][KB_A]=arKeySetOptionsMenu[KB_A];
arKeySets[OPTIONS_MENU][KB_B]=arKeySetOptionsMenu[KB_B];

Of course we'd write a function to assign the arrays to this multidimensional array.
Or we could simply forgo extra arrays and shove stuff directly into the multidimensional array.
Posted By: 3Dski

Re: Pointer To A Pointer Problem - 10/28/07 20:06

I thought a bit about the possibility you speak of... multiple key mapping sets.

I had out-of-town guests and wasn't able to post another correction. I found another problem with the size specified for the arrays, which ripple down to the conditions tested. I noticed that your code is using the incorrect 88, which wouldn't include the mouse and joystick scancodes. The size of the arrays should be 116 as opposed to the earlier correction I made of 115. I noticed that your code is using the incorrect 88, which wouldn't include the mouse and joystick scancodes. If one did want to just include the keyboard, the 88 would have to be upped to 89 and the loop conditions would have to test for "< 89".

Here's the corrections I made to account for all scancodes:

EDITED: BETTER NAME FOR THE FOLLOWING WOULD BE KEY_MAP_SIZE...
#define MAX_KEY_POS 116

...

void init_key_map()
{
...
for( i = 0;i < MAX_KEY_POS; i++)
...
}


void cache_key_map()
{
...
for( i = 0; i < MAX_KEY_POS;i++)
...
}

void restore_key_map()
{
...
for( i = 0; i < MAX_KEY_POS; i++)
...
}

void map_key(var scode, void* funct)
{
if (scode > 0 && scode < MAX_KEY_POS )
...
}

I think this covers the array dimensioning problems. Recognized this problem when my code was crashing, in an attempt to work on navigation control. Saw the dimensioning problem and fixed it thinking it would correct my crash. Didn't correct the crash, but at least the subtle dimension problem is fix fixed.


Posted By: 3Dski

Re: Pointer To A Pointer Problem - 11/02/07 18:03

For anyone that has been visiting this thread, I've placed a corrected code listing in the form of an includeable Lite-C module over in "Lite-C Contribuitions", under the topic of "Key Mapping Management".
© 2024 lite-C Forums