Keybord Bindings

Programmers discuss here anything related to FreeOrion programming. Primarily for the developers to discuss.

Moderator: Committer

Message
Author
User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Keybord Bindings

#16 Post by Geoff the Medio »

Deriving HotKeyManager from OptionsDB seems like a strange choice. I don't see any benefit to doing so, as you can store all the hotkey settings in the existing global OptionsDB which can be accessed by calling GetOptionsDB(). Deriving from OptionsDB brings in a lot of unnecessary functionality from OptionsDB that a hotkey manager doesn't need or have any sensible use for, and makes for a lot of confusing or oddly-named functions and structs in the HotKeyManager header.

I'm also very confused by

Code: Select all

typedef HotKeyManagerFn boost::function<void ()>;
What is that supposed to do? Whatever it is, it won't work as far as I know... Did you just swap the order in the typedef...?

Members of structs like Command are going to need better variable names than "value1" and "value2".

There are two ambiguously-named Get member functions in HotKeyManager that differ only by return type. These need proper descriptive and distinct names.

The Add function would be better with a decent unambiguous name. Is it supposed to be the undeclared AddCommand function that's used in MapWnd.cpp?

Same for Remove.

This probably won't work...

Code: Select all

const HotKey& value = 0
If you want to allow passing null, you need to pass in a pointer, not a reference.

Does class HotKey need an operator < any more?

HotKey::GetFlags would be better called GetModKeys

There is no need for char short_name or bool storable in struct Command. All commands should have their bound hotkey stored in the OptionsDB and on disk.

And again, you don't need to and shouldn't want to be storing pointers to CUIWnd or GG::Wnd objects within HotKeyManager. Doing this will require making sure those pointers always stay valid, and you can't be sure that various UI class objects won't be destructed and recreated at various times while the program is running... Particular cases where this might occur are between turns, or when resigning and loading or starting a new game. Much better would be to provide signals that can be connect to various functions from within UI classes, so that they can handle reconnecting in their own initialization code. Since you've aready suggested having windows register themselves with the hotkey manager when being constructed / initialized, why not just have those window connect hotkeymanager command signals to the code that executes those commands, and avoid the need to write your own register / deregister code? Exposing signals and using GG::Connect does this work for you.

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#17 Post by strooka »

ok, did some changes....

Code: Select all

// -*- C++ -*-
//by strooka
#ifndef _HotKeyManager_h_
#define _HotKeyManager_h_

#include <../GG/GG/Base.h>
#include <../GG/GG/GUI.h>
#include <../GG/GG/SignalsAndSlots.h>

#include "../util/OptionsDB.h"
#include "CUIControls.h"

#include <map>


class HotKeyManager;

/////////////////////////////////////////////
// Free Functions
/////////////////////////////////////////////
/** returns the single instance of the class */
HotKeyManager& GetHotKeyManager();

class HotKey 
{
public:
    HotKey( std::string str );
    HotKey( GG::Key key = GG::GGK_UNKNOWN, GG::Flags<GG::ModKey> mod_keys = GG::MOD_KEY_NONE );
    ~HotKey();

    void SetKey( std::pair< GG::Key, GG::Flags<GG::ModKey> >& Pair );

    bool operator < (const HotKey& b) const;

    static std::string& KeyString(GG::Key key = GG::GGK_UNKNOWN, GG::Flags<GG::ModKey> mod_keys = GG::MOD_KEY_NONE ); //!< computes Key input

    static GG::Key KeyFromString(std::string str); //!< computes string input for a Key

    static std::pair< GG::Key, GG::Flags<GG::ModKey> >& UserString(std::string str); //!< computes user input

    bool GetCtrl() {     return m_mod_keys & (GG::MOD_KEY_CTRL); }//!< Is CTRL key pressed to activate hotkey? 
    bool GetAlt() { return m_mod_keys & (GG::MOD_KEY_ALT); } //!< ALT key?
    bool GetShift() { return m_mod_keys & (GG::MOD_KEY_LSHIFT | GG::MOD_KEY_RSHIFT); } //!< SHIFT key?
    bool GetMeta() { return m_mod_keys & (GG::MOD_KEY_META); } //!< META key?

    GG::Key GetKey() { return m_key; }
    GG::Flags<GG::ModKey> GetModKeys() { return m_mod_keys; }

    static bool IsModKey(GG::Key key) {
        if( key == GG::GGK_RSHIFT || GG::GGK_LSHIFT || GG::GGK_RCTRL || GG::GGK_LCTRL || GG::GGK_LALT || GG::GGK_RALT || GG::GGK_LMETA || GG::GGK_RMETA )
            return true;
        else
            return false;
    }

    boost::signals::connection& GetConnection();

    template <class T> inline 
    void SetConnection(bool (T::*slot)(), const T* pWnd);
    void UpdateConnection();
    void RemoveConnection();
private:
    GG::Key m_key; //!< GG code for key that was pressed
    GG::Flags<GG::ModKey> m_mod_keys;
    boost::signals::connection m_connection;
};


class HotKeyManager
{
public:
     //!<because the template for std::string is already used in OptionsWnd we redefine it here
    struct SetOptionFunctor
    {
        SetOptionFunctor(const std::string& option_name, CUIEdit* edit) :
            m_option_name(option_name), m_edit(edit) {}

        void operator()(const std::string& str) 
        {
            HotKey hotkey = GetHotKeyManager().GetHotKey(m_option_name);
            std::pair < GG::Key, GG::Flags<GG::ModKey> > Pair(HotKey::UserString(str));
            hotkey.SetKey( Pair );
            GetHotKeyManager().RemoveHotKey(m_option_name);
            GetHotKeyManager().InsertHotKey(m_option_name, hotkey);
            m_edit->SetText(HotKey::KeyString(hotkey.GetKey(), hotkey.GetModKeys()));
        }

        const std::string m_option_name;
        CUIEdit* m_edit;
    };

    HotKey& GetHotKey(const std::string str) { return m_hotkeys_list[str]; }

    void InsertHotKey(const std::string option_name, const HotKey& hotkey) {
        m_hotkeys_list.insert( std::pair< const std::string, HotKey >(option_name, hotkey) );
    }
    void RemoveHotKey(const std::string option_name) {
        m_hotkeys_list.erase( option_name );
    }


private:
    std::map< const std::string, HotKey>           m_hotkeys_list;

    friend HotKeyManager& GetHotKeyManager();

    static HotKeyManager* s_HKManager;
};
//

#endif // _HotKeyManager_h_
in MapWnd, you do in the constructor :

Code: Select all

//by strooka
    GetHotKeyManager().InsertHotKey("UI.HotKey.MapWnd.command-a", HotKey(GG::GGK_a));
    GetHotKeyManager().InsertHotKey("UI.HotKey.MapWnd.command-b", HotKey(GG::GGK_b));
//
and somewhrer else maybe in the constructor too:

Code: Select all

void MapWnd::ConnectKeyboardAcceleratorSignals()
{

//by strooka
    HotKey hotkey = GetHotKeyManager().GetHotKey("UI.HotKey.MapWnd.command-a");
    hotkey.SetConnection<MapWnd>(&MapWnd::DoIt, this);

    hotkey = GetHotKeyManager().GetHotKey("UI.HotKey.MapWnd.command-b");
    hotkey.SetConnection<MapWnd>(&MapWnd::DoIt2, this);
//
thus connecting the signals and keep track of it.

i couldnt manage that with the options db, cause having problems with the >> operator.

i'll test it but it should work now after some more compiles.

Maybe i should save à String representation of the HotKeys in the options db.
I could create à wrapper func that gets them from the options db and initializes an element in the map m_hotkey_list. then it would Be saved to file.
Attachments
HotKeyManager.tgz
near to the end
(56.13 KiB) Downloaded 58 times

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Keybord Bindings

#18 Post by Geoff the Medio »

strooka wrote:i couldnt manage that with the options db, cause having problems with the >> operator.
[...]
Maybe i should save à String representation of the HotKeys in the options db.
I could create à wrapper func that gets them from the options db and initializes an element in the map m_hotkey_list. then it would Be saved to file.
Have a look at StreamableColor in ClientUI.h. OptionsDB already can store arbitrary structures if you define the appropriate operator >> and operator << to export as or be initialized from text. This should be doable for HotKey as well, for reasonabl definitions of HotKey. I'm also suspect it's what's causing your "problems with the >> operator", the meaning of which is unclear from the post.


Don't pass std::string by value when you could pass it by const reference. There are several cases where you've declared a function that takes an std::string by value.


You don't need to redefine SetOptionFunctor for strings as part of HotKeyManager. If hotkey options are to be stored as just strings then you could use the existing sting SetOptionFunctor. However this shouldn't matter, as there should be a separate UI wiget for binding hotkeys to commands that doesn't involve just a text edit box. This widget could include an edit box to display the results, but should be treated as a separate control with custom-designed interactivity for the setting of the hotkeys.


The HotKey and HotKeyManager classes need some reorganizing...


Currently you use HotKeyManager::InsertHotKey in the initialization of MapWnd. This won't work properly in general, because there could be more than one UI class instance created, and this would attempt to add "hotkeys" every time one is constructed, leading to duplication.

Instead, there should be a "AddCommand" function in the HotKeyManager. This would be used in a function in an anonymous namespace of various source files, like the OptionsDB option-adding code, except that all you'd do is call GetHotKeyManager().AddCommand(...) to add a new command, and it's not necessary to do the complicated store-and-process later business that's done for AddOptions and RegisterOptions.

The use of the AddCommand function would be to tell the HotKeyManager to add a "command". A command being in the HKM would mean that the HKM internally stores a boost::signal object that can be accessed by calling HotKeyManager::GetCommandSignal(const std::string& signal_name). This signal would emit whenever the appropriate keypress is detected, and various UI classes would use GG::Connect to connect the signal to a function to respond to it.

Adding a command to the KHM would also involve specifying:
* An internal name by which it is tracked. This would be like "UI.hotkey.map-zoom-in". The command would be looked up later by this name.
* A player-readable name stringtable entry. This would be like "HOTKEY_MAP_ZOOM_IN", which would be the name of a string in the stringtable that would be have associated translated text to describe the command to players, which might look like "Zoom in map".
* An (optional) default hotkey to bind to the command. This could be omitted to have no default hotkey bound to the command, or could be a HotKey object. This default would apply unless the player overrode the setting.

The signals would be stored within the HKM like so:

declare a few typedefs:

Code: Select all

typedef boost::signal<void()>                       SignalType;
typedef boost::shared_ptr<SignalType>               SignalPointerType;
typedef std::map<std::string, SignalPointerType>    SignalMapType;
and the HKM would have a map to store the signals:

Code: Select all

SignalMapType m_sig_map;    // command signals, indexed by code-name
In HotKeyManager::AddCommand, the signal would be created and stored in this map. It has to be stored as a shared_ptr since boost::signal is noncopyable.

Code: Select all

m_sig_map[command_name] = SignalPointerType(new SignalType()); // add a new signal to the map
Then in HotKeyManager::GetCommandSignal, you'd look up the signal in the map, and return it, or throw if no such signal existed.

Code: Select all

// get a signal by name, ensuring such a signal exists.
SignalMapType::const_iterator it = m_sig_map.find(command_name);
if (it == sig_map.end())
    throw std::runtime_error("attempted to get nonexistant signal");
SignalType& test_signal = *(it->second);
return test_signal;
An alternative to throwing would be to return a reference to a separate HotKeyManager class static signal that will never emit.

GetCommandSignal would be called in UI class initialization code, and would be used in a GG::Connect call, like any other signal.

For reference, this is very similar to how OptionsDB::OptionChangedSignal(const std::string& option_name) works, which returns a signal that is emitted whenever the indicated option is changed, or throws if not such option exists. A notable difference is that OptionsDB stores Options instead of shared_ptr<boost::signal<void()> >, which also gets around the issues of the boost::signal istelf being noncopyable.


HotKeyManager would also internally deal with all the issues of connecting keyboard accelerator signals to various command signals to which various hotkeys have been bound.

HotKey only needs to be something like:

Code: Select all

struct HotKey {
    HotKey(...);
    GG::Key                 key;
    GG::Flags<GG::ModKey>   mod_keys;
};
std::ostream& operator<<(std::ostream& os, const HotKey& hotkey);
std::istream& operator>>(std::istream& is, HotKey& hotkey);
since all the signals stuff will be handled within the HKM.

Also, when adding a command, the HKM should also register an option with the OptionsDB to store and retreive the HotKey to bind to the command. The default bound hotkey would come form the default keypress, if specified in AddCommand. In any case, the actual bound hotkey should be the one retreived from the OptionsDB. If this hasn't been changed by the user, it will be the default hotkey, but could also be something different.

Doing this this way avoid having to template over UI classes, and avoids issues of needing to track the lifetime of UI classes to be sure you're not dereferencing invalid pointers to objects that have been deleted, and avoids the need to manually track pointers to UI objects entirely, or the need for all hotkeyed commands to be defined through pointers to UI objects (which shouldn't necessarily be the case).

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#19 Post by strooka »

Ok although i have already à Solution to Store the String representation of à hotkey in options db i will overload the Operators.
I Need the opton functor since it Sets the New hotkey Value and reconeccts the Connection.
I have an update Ready and i will post it when it is runable.
I Need to store Not only the Signal i Store the whole Connection in hkm. Thus allowing to update the Connection when the hotkey is altered.
I'm on the Code updating the Connection and if you already know how to extract the sigs (the functions) connected from the Connection let me Know.
It should Be something like this:

Code: Select all

Vector<sig?> s = m_connection.get_connection().data->getsomevector()
for(int i =0...
m_connection.connect(...,s[i]
i'm Not shure weter i should create an extra window for Key creation, i would prefer recognizing the Key Input and Setting the String.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Keybord Bindings

#20 Post by Geoff the Medio »

strooka wrote:Ok although i have already à Solution to Store the String representation of à hotkey in options db i will overload the Operators.
If you want to store hotkeys by converting to string, storing them, and then retreiving a string and converting back to a hotkey each time it's needed, that's probably fine. However, it'd be cleaner and easier to use if you actually stored HotKey directly, by defining the operator << and >>, as then all the existing built in stuff for OptionsDB Get and Set will work natively with HotKey objects.
I Need the opton functor since it Sets the New hotkey Value and reconeccts the Connection.
I don't see what that's needed for... If you set up an edit box for the hotkey-string or make a custom-built hotkey UI widget (just a small widget, not a whole new window), then when the option value changes, the optionchangedsignal will be emitted, and you can connect that to a handler in the HKM. That would get the new string from the optionsDB, and wouldn't know anything about the UI widget that was used to set it.
I Need to store Not only the Signal i Store the whole Connection in hkm. Thus allowing to update the Connection when the hotkey is altered.
I didn't dicuss it in the design above, but yes, you'd need to actually connect the keyboard accelerator signal to something to make the hotkey do something. In the above discussion, it would involve connecting the accelerator signal to the command signal that would be publically exposed by calling GetCommandSignal.
I'm on the Code updating the Connection and if you already know how to extract the sigs (the functions) connected from the Connection let me Know.
As far as I can tell, there's no way to get the functions to which a signal is connected from the signal itself or from the connection object.

But you can store this information yourself... boost::signals::connection can be stored by value, so you can have an std::multimap<std::string, boost::signals::connection> or std::multimap<HotKey, boost::signals::connection> or somesuch. Whenever a connection is made using GG::Connect, a boost::signals::connection is returned, which you can insert into an std::multimap or std::map<std::string, std::set<boost::signals::connection> > or similar.

You could then look up the appropriate signals to disconnect when a hotkey binding is changed.
It should Be something like this:

Code: Select all

Vector<sig?> s = m_connection.get_connection().data->getsomevector()
for(int i =0...
m_connection.connect(...,s[i]
I don't think that's possible. I might be wrong, though... You can review the boost documentation about signals here.
i'm Not shure weter i should create an extra window for Key creation, i would prefer recognizing the Key Input and Setting the String.
There's no need for a separate window, but a UI widget dedicated to entering and displaying hotkey specifications would probably be useful. Putting UI functionality into internal bookkeeping of hotkey connections isn't a good idea, and just having a text or edit box might be limited. I don't know if there's any way to get a ctrl, alt, shift or meta key press or combinations of them from an edit box. Certainly if the user just types stuff into the edit box, it won't have a textual representation of the modkeys. Ideally the user should be able to initiate hotkey recording, optionally hold one or more modkeys, and then press a main key. When the main keypress is captured, the hotkey would be recorded, and the customized UI widget would display something appropriate.

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#21 Post by strooka »

Geoff the Medio wrote:
strooka wrote:Ok although i have already à Solution to Store the String representation of à hotkey in options db i will overload the Operators.
If you want to store hotkeys by converting to string, storing them, and then retreiving a string and converting back to a hotkey each time it's needed, that's probably fine. However, it'd be cleaner and easier to use if you actually stored HotKey directly, by defining the operator << and >>, as then all the existing built in stuff for OptionsDB Get and Set will work natively with HotKey objects.
[/quote]

yep Ur right

I don't see what that's needed for... If you set up an edit box for the hotkey-string or make a custom-built hotkey UI widget (just a small widget, not a whole new window), then when the option value changes, the optionchangedsignal will be emitted, and you can connect that to a handler in the HKM. That would get the new string from the optionsDB, and wouldn't know anything about the UI widget that was used to set it.
the Option functor is used in KeyOption à Text Input box in OptionsWnd created by me. I Call the Option functor every Time à Key is pressed an when i Leave the window. When à Key is pressed the Value is evaluated and when i leave the window the Key combination is computed. I Hope i can Set 2 Option functors to à edit. in this or à similar Way the computed Key String will Be Set in the window and stored in the options db.
Storing Text values in the options db makes it user readable on hd.

I didn't dicuss it in the design above, but yes, you'd need to actually connect the keyboard accelerator signal to something to make the hotkey do something. In the above discussion, it would involve connecting the accelerator signal to the command signal that would be publically exposed by calling GetCommandSignal.

As far as I can tell, there's no way to get the functions to which a signal is connected from the signal itself or from the connection object.

But you can store this information yourself... boost::signals::connection can be stored by value, so you can have an std::multimap<std::string, boost::signals::connection> or std::multimap<HotKey, boost::signals::connection> or somesuch. Whenever a connection is made using GG::Connect, a boost::signals::connection is returned, which you can insert into an std::multimap or std::map<std::string, std::set<boost::signals::connection> > or similar.

You could then look up the appropriate signals to disconnect when a hotkey binding is changed.
It should Be something like this:

Code: Select all

Vector<sig?> s = m_connection.get_connection().data->getsomevector()
for(int i =0...
m_connection.connect(...,s[i]
I don't think that's possible. I might be wrong, though... You can review the boost documentation about signals here.
Maybe i could assign à Signal to another, i don't Know if it overwrites the assigned functions.
Otherwise i could use some code undocumented Direct from the Header from boost.
If that doesnt help Too, i could only make à getsignal function and compute the reconnection
On every window seperately.
Or i create à New Signal and Store the old connection in it.
I think that would Be the Best Way to manipulate Signals.

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#22 Post by strooka »

No After Reading boost Doc i'll Write à wrapper connect func for the Windows creating à Signal connected to àn arbitrary Key which isnt used; Store this Signal in hkm and creating à Second Signal connected to à Key that is used and to the () Operator of the First Signal. Altering Key Input is Done by reconnecting the Signals calling the operator. It Sounds à Bit complicated but this is the only Way to modify Signals.
The GGK_WORLD keys would Be good for this .

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Keybord Bindings

#23 Post by Geoff the Medio »

strooka wrote:the Option functor is used in KeyOption à Text Input box in OptionsWnd created by me. I Call the Option functor every Time à Key is pressed an when i Leave the window. When à Key is pressed the Value is evaluated and when i leave the window the Key combination is computed. I Hope i can Set 2 Option functors to à edit. in this or à similar Way the computed Key String will Be Set in the window and stored in the options db.
That was very hard to follow due to language issues, so I'm not sure what you're planning, but: You don't need two SetOptionFunctor connected to an edit. If you modify the value in the OptionsDB, the OptionChangeSignal will be emitted, and you can connect that to update the GUI.
Storing Text values in the options db makes it user readable on hd.
If you define operator << and >> appropriately, the OptionsDB contents will be readable even if you store HotKey values directly, rather than converting to string first. The point of operator >> is that you convert the value of the object to a string (stream). Make that converted value readable, and it'll be readable in config.xml where option values are stored. Again, look at StreamableColor which stores its value (4 ints: r, g, b, a components) as something that looks like "(23, 53, 122, 0)" and reads in similarly-formatted texts, parses it and uses the resulting values its member variables.
Maybe i could assign à Signal to another, i don't Know if it overwrites the assigned functions.
Otherwise i could use some code undocumented Direct from the Header from boost.
If that doesnt help Too, i could only make à getsignal function and compute the reconnection
On every window seperately.
Or i create à New Signal and Store the old connection in it.
I think that would Be the Best Way to manipulate Signals.
[...]
No After Reading boost Doc i'll Write à wrapper connect func for the Windows creating à Signal connected to àn arbitrary Key which isnt used; Store this Signal in hkm and creating à Second Signal connected to à Key that is used and to the () Operator of the First Signal. Altering Key Input is Done by reconnecting the Signals calling the operator. It Sounds à Bit complicated but this is the only Way to modify Signals.
The GGK_WORLD keys would Be good for this .
If you want to disconnect a signal from a function, you need to store the boost::signals::connection and call its disconnect() function. Connecting a signal to multiple functions without disconnecting any will result in the signal calling all connected functions when it emits.

Are you even reading my suggestions about how to set this up? You seem to be insistent on connecting signals to window member functions from within the HotKeyManager, which is a bad idea. As I've said repeatedly, don't do it.

I'm not sure why you're proposing to use signals connected to unused / arbitrary keys, but it's not necessary and a bad idea. If you need an intermediate signal to connect to for some purpose, just make a boost::signal ... it doesn't need to be associated with any GG::Key code.

It sounds a bit like you're edging towards what I've been suggesting for several posts, which is to have a CommandSignal publically available from the HKM which is connected inside UI classes by their own init code, and do connections between keyboard accelerator signals and the commandsignal internally in the HKM.

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#24 Post by strooka »

Yah i needed à Little Time for it :mrgreen:

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#25 Post by strooka »

I'm debugging it right now. The last Thing i have to figure out is capturing Key Input and assign it to the desired Option in Option db when editing à Key combination in the options wnd.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Keybord Bindings

#26 Post by Geoff the Medio »

strooka wrote:... capturing Key Input and assign it to the desired Option in Option db when editing à Key combination in the options wnd.
The way I'd do this is to have a custom OptionsWnd control for hotkey binding that shows a textual representation of the bound hotkey, and is clickable to configure the hotkey. If clicked, a modal dialog would pop up, which would say "Press Desired Hotkey" or somesuch, and which would close itself on the next non-modkey keypress event. It would record what that keypress event GG::Key was, and what modkeys were pressed at the same time, and return those to the calling function, which would store them and assign them as the bound hotkey.
Attachments
hotkey confugration widget mockup for options screen
hotkey confugration widget mockup for options screen
freeorion_hotkey_configuration_mockup.png (7.78 KiB) Viewed 1003 times

planetbaker
Space Floater
Posts: 29
Joined: Sun Jan 24, 2010 11:42 am
Location: Sol d

Re: Keybord Bindings

#27 Post by planetbaker »

Geoff the Medio wrote:
strooka wrote:... capturing Key Input and assign it to the desired Option in Option db when editing à Key combination in the options wnd.
The way I'd do this is to have a custom OptionsWnd control for hotkey binding that shows a textual representation of the bound hotkey, and is clickable to configure the hotkey. If clicked, a modal dialog would pop up, which would say "Press Desired Hotkey" or somesuch, and which would close itself on the next non-modkey keypress event. It would record what that keypress event GG::Key was, and what modkeys were pressed at the same time, and return those to the calling function, which would store them and assign them as the bound hotkey.
^Like that or even close automatically after a key combination was pressed. At least that's how I'd expect it to work in an interactive way and as it's known from other games with such feature.
Unless stated explicitly and differently, any patches or artwork I should post in this forum are licensed under GPL v2 or - at your discretion - any later version of the GPL.

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#28 Post by strooka »

i've done debugging it so far that i can run it and capture a sample key in map wnd that is connected with hotkeymanager and call a function.


SUCCESS :mrgreen: :mrgreen:


just the options wnd dialog needs some editing.

User avatar
strooka
Space Kraken
Posts: 165
Joined: Tue Jun 23, 2009 5:34 pm
Location: Bielefeld, Germany

Re: Keybord Bindings

#29 Post by strooka »

Ok, geoff then do it. I want to Focus on 3D Code.
Tomorrow when i Access my Data i will post the Release Version. The issues that remain are capturing Mouse Input to Pop up the dlg that captures the Key and there is an issue i where i give up:
when you for example define Key "à" for galaxy Zoom in and you are in Research wnd the Galaxy will Zoom when Pressing a.
That means when you define keys to Be used in hkm, they will Be in global scope.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Keybord Bindings

#30 Post by Geoff the Medio »

strooka wrote:...capturing Mouse Input to Pop up the dlg that captures the Key...
Have a look to see how it's done for the ColorOption and the ColorSelector it pops up.
when you for example define Key "à" for galaxy Zoom in and you are in Research wnd the Galaxy will Zoom when Pressing a.
That means when you define keys to Be used in hkm, they will Be in global scope.
This issue was discussed earlier in my first post, with the stuff about having a state machine for hotkey enabling / disabling. For an initial version, setting up a state machine isn't necessary, and it would probably be sufficient to have a function in the HKM like "SetUIMode" which would take a string or enum that indicates the UI mode, which would be one of several options like GalaxyMap, ResearchScreen, ProductionScreen, etc. When adding a hotkeyable command to the KHM, there would be an option to specify the mode(s) in which the command is active. So for the zoom command, you'd specify that it works when in GalaxyMap or ProductionScreen modes. Then when switching between UI modes (eg. opening or closing the production screen), the HKM's SetUIMode would be called to tell the HKM the current mode. These calls would probably be put in the MapWnd's functions that do the changing between modes.

Alternatively, there could be more than one UI mode active at a time, so you could have HKM functions to "EnableUIMode" and "DisableUIMode" which would take a string and enable/disable the commands that have that string. Each string would have only one mode label. When in production mode, which is sort of a substate of galaxy map, you'd have both map and production hotkeys active. This might create problems if we wanted some map commands to be not active when in production, though...

Post Reply