Create an account


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Visualizing Keybinds

#1
Hi folks, I've been speaking with a lot of new players and one of the first conversations that comes up is keybinds. Many, if not all seasoned players have custom keybind configurations, you can find many of them here on the forums or elsewhere. However, to understand them you have to read through the cfg and try to make sense of them in you head.

That's difficult, it should be easier to visualize and share keybind configurations.

I had started to address this problem in the Nexuiz days with the following tool: http://toolz.nexuizninjaz.com/keybinds/

Here is a screenshot for reference:

[Image: gSI7CDa.png]

This tool actually uses a custom XML format I refer to as KBML (KeyBoard Markup Language), Example Here. These KBML files can be generated from cfg files through a parser I wrote in PHP.

This project, like many of my projects was never complete, partially due to time, partially due to sloppy coding.

I would like to reboot this project for Xonotic and create a few custom redux keybinds for new players and seasoned players alike.

Here's the old ugly code: https://github.com/z/keybindx

I'm hoping that maybe this post will stir up interest and help motivate me in taking the next steps to create a usable tool.

Any developers interested in helping?
Any players have suggestions or feedback?
Reply

#2
f11 isnt bound Smile
[Image: 38443.png]
Reply

#3
You can check in but you can never check out Tongue
Reply

#4
Great idea! I think I can help.

I'm seeing the potential to make it a two-way tool:

The user provides the current config.cfg
The app parses that cfg and draws the keyboard labeled with the functions.
If they need that to communicate with others, they can do a screenshot.

Also, the user can drag and drop the functions from a menu (where functions are categorized) to the on-screen keyboard.
And the app would output the config.cfg with the new assignment.

Should this be part of the game config menu?

Or how about write the whole thing in HTML/javascript (no PHP) so you can just host the static content as a tool page on the official website (or for the users to download and run it in their own browsers)?
Reply

#5
(04-04-2015, 01:40 AM)BuddyFriendGuy Wrote: The user provides the current config.cfg
The app parses that cfg and draws the keyboard labeled with the functions.
If they need that to communicate with others, they can do a screenshot.

This is technically already support, the screenshot mechanism could be done with a headless browser.

(04-04-2015, 01:40 AM)BuddyFriendGuy Wrote: Also, the user can drag and drop the functions from a menu (where functions are categorized) to the on-screen keyboard.
And the app would output the config.cfg with the new assignment.

This is the part I didn't complete yet.

(04-04-2015, 01:40 AM)BuddyFriendGuy Wrote: Should this be part of the game config menu?

We we need to find someone that could code this.

(04-04-2015, 01:40 AM)BuddyFriendGuy Wrote: Or how about write the whole thing in HTML/javascript (no PHP) so you can just host the static content as a tool page on the official website (or for the users to download and run it in their own browsers)?

The parser would have to be rewritten and we'd still need an API for a datastore to share keybinds (at minimum). Without the API, data could be stored in local storage. KBML is arguably more human readable, but if this were rewritten in Javascript, I think I would prefer to parse the cfgs into JSON.

However, this is possible and I have been writing a lot of Javascript lately so it wouldn't be unreasonable.

Another point I had brought up in conversion with Mario, is that KBML supports additional attributes not defined in cfg files... but I was thinking perhaps using a specially formatted comment string this could be preserved.

Code:
<key id="key_1" title="I need help" action="say_team I need help!" color="C2DBF2"/>

would translate into:

Code:
bind 1 "say_team I need help!" // %['I need help', 'C2DBF2']

As an example.
Reply

#6
To expedite this process, I think it makes sense to create a display only version of the tool available on the new 'tools' section on xonotic.org.

This should display at minimum:
- the default keybinds
- an alternative (redux) version of a weapon configuration as shown above.

Future configurations that will be nice to have are:
- video editing keybinds
- map debugging / bot waypoint keybinds
- gametype specific binds

It's occurred to me that we need to better document how to use all the various weapon related cvars and aliases, such as: prevweap, lastweap, bestweapon, cl_weaponpriority*, weapon_group_*, impulse *

Does anyone have interest in helping me build out a few configuration files that I can parse into KBML to display on the site and offer for download?

I'm also interested in hearing other suggestions for keybinds.
Reply

#7
-z-, sorry for the late reply. I didn't disappear. I spent some time on QC this weekend, and will probably give your idea a try this coming weekend.

(04-04-2015, 09:47 AM)-z- Wrote:
(04-04-2015, 01:40 AM)BuddyFriendGuy Wrote: The user provides the current config.cfg
The app parses that cfg and draws the keyboard labeled with the functions.
If they need that to communicate with others, they can do a screenshot.
This is technically already support, the screenshot mechanism could be done with a headless browser.
I see. Wonderful!

(04-04-2015, 09:47 AM)-z- Wrote:
(04-04-2015, 01:40 AM)BuddyFriendGuy Wrote: Also, the user can drag and drop the functions from a menu (where functions are categorized) to the on-screen keyboard.
And the app would output the config.cfg with the new assignment.
This is the part I didn't complete yet.
I think I can help with this part. I do need a list of things (say, categorized commands) to drag from.

(04-04-2015, 09:47 AM)-z- Wrote:
(04-04-2015, 01:40 AM)BuddyFriendGuy Wrote: Should this be part of the game config menu?
We we need to find someone that could code this.

I gave QC a quick read but didn't see drag and drop event support in the menu system (can somebody verify this?). I don't think I'm ready to write that.

That said, even visualization of the current setting is helpful.

(04-04-2015, 09:47 AM)-z- Wrote: The parser would have to be rewritten and we'd still need an API for a datastore to share keybinds (at minimum). Without the API, data could be stored in local storage. KBML is arguably more human readable, but if this were rewritten in Javascript, I think I would prefer to parse the cfgs into JSON.

I don't quite understand why we need a datastore? I was thinking a textbox input/output so users can copy and paste. No?

(04-04-2015, 09:47 AM)-z- Wrote: Another point I had brought up in conversion with Mario, is that KBML supports additional attributes not defined in cfg files... but I was thinking perhaps using a specially formatted comment string this could be preserved.

Code:
<key id="key_1" title="I need help" action="say_team I need help!" color="C2DBF2"/>

would translate into:

Code:
bind 1 "say_team I need help!" // %['I need help', 'C2DBF2']

Excellent idea!
Reply

#8
(04-06-2015, 02:55 AM)BuddyFriendGuy Wrote: I don't quite understand why we need a datastore? I was thinking a textbox input/output so users can copy and paste. No?

For sharing keybinds. We have a hard limit in characters we can put in the address bar and it's not something we'd want to stuff a bunch of data into anyway, an id that can pull the data from the datastore would be much better.
Reply

#9
Just a quick update on the progress of this project.

I've created a new repo on my personal github, https://github.com/z/kbx -- you can watch development progress here.

Most development will take place there until it reaches a certain level of maturity to be integrated into the xonotic.org/tools page.

So far, I have gutted the old HTML/CSS and written a JSON definition ( http://z.github.io/kbx/data/ninja_binds.txt ) that applies to the HTML.

Live Demo: http://z.github.io/kbx/

Next steps are to create a cfg -> JSON parser and a cfg generator from the JSON.
Reply

#10
Just a quick update. I rigged up some rudimentary front-end functionality to allow you to paste in your CFG to have it parsed into KBX JSON and visualize it. You can then edit titles, actions and colors of the keys. Optionally, you can output a new CFG file.
Reply

#11
nice work. keep it up or else i'll crack the whip on you again Tongue
[Image: 38443.png]
Reply

#12
One hurdle I noticed is aliases to other bind

set nn_lHere "^2{@^7%l^2}; g_waypointsprite_team_here" for example.

The JSON should should support optional aliases references for producing a CFG.

BuddyFriendGuy, would you will will at mimimum to map titles to actions?

I can handle the the alias portion,
Reply

#13
(05-19-2015, 12:59 AM)-z- Wrote: One hurdle I noticed is aliases to other bind

set nn_lHere "^2{@^7%l^2}; g_waypointsprite_team_here" for example.

The JSON should should support optional aliases references for producing a CFG.

BuddyFriendGuy, would you will will at mimimum to map titles to actions?

I can handle the the alias portion,

I'd be happy to help out, but will need... er... a complete and grammatical sentence to really know what you mean. Smile (I bet it's the late night coding.)
Reply

#14
Currently it's producing an array

Code:
[{"key_tab":{"title":"+showscores","action":"+showscores","color":""}},{"key_enter":{"title":"+jump","action":"+jump","color":""}},{"key_esc":{"title":"togglemenu","action":"togglemenu","color":""}},{"key_space_bar":{"title":"+jump","action":"+jump","color":""}},{"key_0":{"title":"weapon_group_0","action":"weapon_group_0","color":""}},{"key_1":{"title":"weapon_group_1","action":"weapon_group_1","color":""}},{"key_2":{"title":"weapon_group_2","action":"weapon_group_2","color":""}},{"key_3":{"title":"weapon_group_3","action":"weapon_group_3","color":""}},{"key_4":{"title":"weapon_group_4","action":"weapon_group_4","color":""}},{"key_5":{"title":"weapon_group_5","action":"weapon_group_5","color":""}},{"key_6":{"title":"weapon_group_6","action":"weapon_group_6","color":""}},{"key_7":{"title":"weapon_group_7","action":"weapon_group_7","color":""}},{"key_8":{"title":"weapon_group_8","action":"weapon_group_8","color":""}},{"key_9":{"title":"weapon_group_9","action":"weapon_group_9","color":""}},{"key_backtick":{"title":"toggleconsole","action":"toggleconsole","color":""}},{"key_a":{"title":"+moveleft","action":"+moveleft","color":""}},{"key_d":{"title":"+moveright","action":"+moveright","color":""}},{"key_e":{"title":"+hook","action":"+hook","color":""}},{"key_f":{"title":"+use","action":"+use","color":""}},{"key_g":{"title":"dropweapon","action":"dropweapon","color":""}},{"key_i":{"title":"+show_info","action":"+show_info","color":""}},{"key_m":{"title":"+hud_panel_radar_maximized","action":"+hud_panel_radar_maximized","color":""}},{"key_q":{"title":"weaplast","action":"weaplast","color":""}},{"key_r":{"title":"reload","action":"reload","color":""}},{"key_s":{"title":"+back","action":"+back","color":""}},{"key_t":{"title":"messagemode","action":"messagemode","color":""}},{"key_u":{"title":"+con_chat_maximize","action":"+con_chat_maximize","color":""}},{"key_v":{"title":"+button8","action":"+button8","color":""}},{"key_w":{"title":"+forward","action":"+forward","color":""}},{"key_y":{"title":"messagemode2","action":"messagemode2","color":""}},{"key_z":{"title":"messagemode2","action":"messagemode2","color":""}},{"key_tilde":{"title":"toggleconsole","action":"toggleconsole","color":""}},{"key_backspace":{"title":"dropweapon","action":"dropweapon","color":""}},{"key_up":{"title":"+forward","action":"+forward","color":""}},{"key_down":{"title":"+back","action":"+back","color":""}},{"key_left":{"title":"+moveleft","action":"+moveleft","color":""}},{"key_right":{"title":"+moveright","action":"+moveright","color":""}},{"key_alt":{"title":"+showaccuracy","action":"+showaccuracy","color":""}},{"key_shift":{"title":"+crouch","action":"+crouch","color":""}},{"key_f1":{"title":"vyes","action":"vyes","color":""}},{"key_f2":{"title":"vno","action":"vno","color":""}},{"key_f3":{"title":"spec","action":"spec","color":""}},{"key_f4":{"title":"ready","action":"ready","color":""}},{"key_f5":{"title":"menu_showteamselect","action":"menu_showteamselect","color":""}},{"key_f6":{"title":"team_auto","action":"team_auto","color":""}},{"key_f7":{"title":"menu_showsandboxtools","action":"menu_showsandboxtools","color":""}},{"key_f10":{"title":"menu_showquitdialog","action":"menu_showquitdialog","color":""}},{"key_f11":{"title":"disconnect","action":"disconnect","color":""}},{"key_f12":{"title":"screenshot","action":"screenshot","color":""}},{"key_pause":{"title":"pause","action":"pause","color":""}},{"key_num_0":{"title":"messagemode","action":"messagemode","color":""}},{"key_num_1":{"title":"+userbind 1","action":"+userbind 1","color":""}},{"key_num_2":{"title":"+userbind 2","action":"+userbind 2","color":""}},{"key_num_3":{"title":"+userbind 3","action":"+userbind 3","color":""}},{"key_num_4":{"title":"+userbind 4","action":"+userbind 4","color":""}},{"key_num_5":{"title":"+userbind 6","action":"+userbind 6","color":""}},{"key_num_6":{"title":"+userbind 7","action":"+userbind 7","color":""}},{"key_num_7":{"title":"+userbind 9","action":"+userbind 9","color":""}},{"key_num_8":{"title":"+userbind 10","action":"+userbind 10","color":""}},{"key_num_9":{"title":"+userbind 11","action":"+userbind 11","color":""}},{"key_num_period":{"title":"messagemode2","action":"messagemode2","color":""}},{"key_num_slash":{"title":"+userbind 13","action":"+userbind 13","color":""}},{"key_num_multiply":{"title":"+userbind 12","action":"+userbind 12","color":""}},{"key_num_minus":{"title":"+userbind 18","action":"+userbind 18","color":""}},{"key_num_plus":{"title":"+userbind 17","action":"+userbind 17","color":""}},{"key_num_enter":{"title":"+userbind 16","action":"+userbind 16","color":""}},{"key_mouse1":{"title":"+fire","action":"+fire","color":""}},{"key_mouse2":{"title":"+fire2","action":"+fire2","color":""}},{"key_mouse3":{"title":"togglezoom","action":"togglezoom","color":""}},{"key_mouse_wheel_up":{"title":"weapnext","action":"weapnext","color":""}},{"key_mouse_wheel_down":{"title":"weapprev","action":"weapprev","color":""}},{"key_mouse4":{"title":"weaplast","action":"weaplast","color":""}},{"key_mouse5":{"title":"+hook","action":"+hook","color":""}},{"key_joy1":{"title":"+crouch","action":"+crouch","color":""}},{"key_joy2":{"title":"+jump","action":"+jump","color":""}},{"key_joy3":{"title":"weapprev","action":"weapprev","color":""}},{"key_joy4":{"title":"weapnext","action":"weapnext","color":""}},{"key_joy5":{"title":"+fire2","action":"+fire2","color":""}},{"key_joy6":{"title":"+fire","action":"+fire","color":""}},{"key_joy7":{"title":"+zoom","action":"+zoom","color":""}},{"key_joy8":{"title":"dropweapon","action":"dropweapon","color":""}},{"key_joy9":{"title":"menu_showteamselect","action":"menu_showteamselect","color":""}},{"key_joy10":{"title":"+show_info","action":"+show_info","color":""}},{"key_joy11":{"title":"+showscores","action":"+showscores","color":""}},{"key_joy12":{"title":"+con_chat_maximize","action":"+con_chat_maximize","color":""}}]

less than optimal for future features... but we know arrays or ordered, so it's say to say index 0 is guaranteed. if index 1 exists, then aliases exists!
Reply

#15
on it.
Reply

#16
Alright, I wrote the script to map common actions to readable titles (in branch actoin_to_title):

Code:
var category_action_title = {

    "movement": {
        "+forward": "⏶",
        "+back": "⏷",
        "+moveleft": "⏴",
        "+moveright": "⏵",

        "+jump": "jump",
        "+crouch": "crouch",
    },

    "camera": {
        "+left": "↶",
        "+right": "↷",
        "+roll_left": "⟲",
        "+roll_right": "⟳",

        "toggle chase_active": "3rd person view",
    },

    "program_control": {
        "pause": "pause",
        "disconnect": "leave",
        "menu_showquitdialog": "quit",
        "toggleconsole": "console",
        "togglemenu": "menu",
    },

    "recording": {
        "screenshot": "screenshot",
    },

    "tactic_info": {
        "+hud_panel_radar_maximized": "radar max",
    },

    "chat": {
        "messagemode": "chat (public)",
        "messagemode2": "chat (team)",
        "+con_chat_maximize": "chat history",
    },

    "game_participation": {
        "ready": "ready",
        "spec": "spec",
        "menu_showteamselect": "team menu",
        "team_auto": "auto team",
    },

    "game_info": {
        "+showaccuracy": "accuracy",
        "+show_info": "server info",
        "+showscores": "scores",
    },


    "vote": {
        "vno": "vote no",
        "vyes": "vote yes",
    },

    "weapon_action": {
        "+fire": "primary fire",
        "+fire2": "secondary fire",
        "reload": "reload",
        "dropweapon": "drop weapon",

        "+hook": "hook",
        "+use": "drop item",
        "+jetpack": "jet pack",
        "+button8": "drag object",


        "togglezoom": "toggle zoom",
        "+zoom": "hold zoom",

        "weapprev": "previous weapon",
        "weapnext": "next weapon",
        "weaplast": "last weapon",
        "bestweapon": "best weapon",
    },

    "weapon": {
        "weapon_group_1": "Blaster",
        "weapon_group_2": "Shotgun",
        "weapon_group_3": "Machine Gun",
        "weapon_group_4": "Mortar",
        "weapon_group_5": "Electro",
        "weapon_group_6": "Crylink",
        "weapon_group_7": "Vortex",
        "weapon_group_8": "Hagar",
        "weapon_group_9": "Devasator",
        "weapon_group_0": "Hook",
    },

    "misc": {
        "+userbind 1": "",
        "+userbind 2": "",
        "+userbind 3": "",
        "+userbind 4": "",
        "+userbind 6": "",
        "+userbind 7": "",
        "+userbind 9": "",
        "+userbind 10": "",
        "+userbind 11": "",
        "+userbind 12": "",
        "+userbind 13": "",
        "+userbind 16": "",
        "+userbind 17": "",
        "+userbind 18": "",


        "menu_showsandboxtools": "menu sandbox",
    },

};

Each category's color is predefined in css. (So users don't have to pick a color for each key.)

Code:
/* action groups */

.actionCategory_movement {
  background-color: rgb(208, 223, 89);
}
.actionCategory_camera {

}
.actionCategory_program_control {
  background-color: rgb(245, 141, 128);
}
.actionCategory_recording {

}
.actionCategory_tactical_info {

}
.actionCategory_chat {
  background-color: rgb(194, 219, 242);
}
.actionCategory_game_participation {
  background-color: rgb(250, 176, 127);
}
.actionCategory_game_info {

}
.actionCategory_game_vote {

}
.actionCategory_weapon_action {
  background-color: rgb(85, 186, 99);
}
.actionCategory_weapon {
  background-color: rgb(152, 209, 169);
}
.actionCategory_misc {
  background-color: rgb(186, 176, 191);
}

The vanilla config looks like this:

   

TODO:
  • I'm not good at picking colors so you may want to fix the CSS.
  • The dialog box don't go away after parsing.
  • What do you think about my previous organization of the menu in branch "user_provided_config"? I think a drop-down menu makes it a bit more intuitive.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

Forum software by © MyBB original theme © iAndrew 2016, remixed by -z-