Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion code/_global_vars/client.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ var/global/list/_kbMap = list(
"SPACEBAR" = "Space",
"ALT" = "Alt",
"SHIFT" = "Shift",
"CONTROL" = "Ctrl"
"CONTROL" = "Ctrl",
"ENTER" = "Return",
"TAB" = "Tab",
"BACKSPACE" = "Back"
)

// Without alt, shift, ctrl and etc because its not necessary
Expand Down
10 changes: 10 additions & 0 deletions code/_helpers/global_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ var/global/list/child_stance_limbs = list(

// TODO: Replace keybinding datums with keybinding decls to make this unnecessary.
var/global/list/hotkey_keybinding_list_by_key = list() // Replace this with just looping over all keybinding decls (as below) in a 'reset hotkeys' proc.
var/global/list/hotkey_keybinding_list_by_key_focused = list()
var/global/list/keybindings_by_name = list() // Replace this with just decl lookups.
/proc/makeDatumRefLists()
// Keybindings
Expand All @@ -60,9 +61,18 @@ var/global/list/keybindings_by_name = list() // Replace this with just decl look
ASSERT(keybinding.name)
var/datum/keybinding/instance = new keybinding
global.keybindings_by_name[instance.name] = instance
var/classic_stored = FALSE
if(length(instance.classic_keys))
classic_stored = TRUE
for(var/bound_key in instance.classic_keys)
global.hotkey_keybinding_list_by_key_focused[bound_key] += list(instance.name)
if(length(instance.hotkey_keys))
for(var/bound_key in instance.hotkey_keys)
global.hotkey_keybinding_list_by_key[bound_key] += list(instance.name)
if(!classic_stored)
global.hotkey_keybinding_list_by_key_focused[bound_key] += list(instance.name)



/proc/get_playable_species()
var/static/list/_playable_species // A list of ALL playable species, whitelisted, latejoin or otherwise. (read: non-restricted)
Expand Down
128 changes: 123 additions & 5 deletions code/controllers/subsystems/input.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,137 @@ SUBSYSTEM_DEF(input)
priority = SS_PRIORITY_INPUT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY

var/list/macro_set
/// 'Hard-wired' macros that have special behaviour.
var/list/core_macro_set
/// Macros for capturing modifier keys. These are always applied.
var/list/modifier_set
/// Typecache of all unprintable keys that are safe for classic to bind
var/list/unprintables_cache
/// Macro IDs we shouldn't clear during client.clear_macros()
var/list/protected_macro_ids
/// Keys with global warnings associated with them.
var/list/warn_keys
/// Fully reserved blacklisted keys
var/list/blacklisted_keys

/datum/controller/subsystem/input/Initialize()
setup_default_macro_sets()
refresh_client_macro_sets()

warn_keys = list(
"C" = "Interferes with the ability to copy text from the chatbox.",
"V" = "Interferes with the ability to paste text into the chatbox."
)
// This should include everything in core_macro_set
blacklisted_keys = list(
"Back" = "Hardwired to Clear Input",
"Tab" = "Hardwired to Focus Chat"
//Escape can't be bound as it's the 'unbind' key during setup.
)

return ..()

// This is for when macro sets are eventualy datumized
/datum/controller/subsystem/input/proc/setup_default_macro_sets()
macro_set = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
"Back" = "\".winset \\\"outputwindow.input.text=\\\"\\\"\\\"\""
core_macro_set = list(
// These could probably just be put in the skin. I actually don't understand WHY they aren't just in the skin. Besides the use of defines for Tab.
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"Escape" = "Reset-Held-Keys",
)
modifier_set = list(
//We need to force these to capture them for macro modifiers.
"Alt" = "\"KeyDown Alt\"",
"Alt+UP" = "\"KeyUp Alt\"",
"Ctrl" = "\"KeyDown Ctrl\"",
"Ctrl+UP" = "\"KeyUp Ctrl\"",
)
// This list may be out of date, and may include keys not actually legal to bind?
// The only full list is from 2008. http://www.byond.com/docs/notes/macro.html
unprintables_cache = list(
// Modifiers. Not actually ON the list, but still safe as they're. Special.
"Shift" = TRUE,
"Ctrl" = TRUE,
"Alt" = TRUE,
// Arrow Keys
"North" = TRUE,
"West" = TRUE,
"East" = TRUE,
"South" = TRUE,
// Numpad-Lock Disabled
"Northwest" = TRUE, // KP_Home
"Northeast" = TRUE, // KP_PgUp
"Center" = TRUE,
"Southwest" = TRUE, // KP_End
"Southeast" = TRUE, // KP_PgDn
// Keys you really shouldn't touch, but are technically unprintable
"Return" = TRUE,
"Escape" = TRUE,
"Delete" = TRUE,
// Things I'm not sure BYOND actually supports anymore.
"Select" = TRUE,
"Execute" = TRUE,
"Snapshot" = TRUE,
"Attn" = TRUE,
"CrSel" = TRUE,
"ExSel" = TRUE,
"ErEOF" = TRUE,
"Zoom" = TRUE,
"PA1" = TRUE,
"OEMClear" = TRUE,
// Things the modern ref says is okay
"Pause" = TRUE,
"Play" = TRUE,
"Insert" = TRUE,
"Help" = TRUE,
"LWin" = TRUE,
"RWin" = TRUE,
"Apps" = TRUE,
"Numpad0" = TRUE,
"Numpad1" = TRUE,
"Numpad2" = TRUE,
"Numpad3" = TRUE,
"Numpad4" = TRUE,
"Numpad5" = TRUE,
"Numpad6" = TRUE,
"Numpad7" = TRUE,
"Numpad8" = TRUE,
"Numpad9" = TRUE,
"Multiply" = TRUE,
"Add" = TRUE,
"Separator" = TRUE,
"Subtract" = TRUE,
"Decimal" = TRUE,
"Divide" = TRUE,
"F1" = TRUE,
"F2" = TRUE,
"F3" = TRUE,
"F4" = TRUE,
"F5" = TRUE,
"F6" = TRUE,
"F7" = TRUE,
"F8" = TRUE,
"F9" = TRUE,
"F10" = TRUE,
"F11" = TRUE,
"F12" = TRUE,
"F13" = TRUE,
"F14" = TRUE,
"F15" = TRUE,
"F16" = TRUE,
"F17" = TRUE,
"F18" = TRUE,
"F19" = TRUE,
"F20" = TRUE,
"F21" = TRUE,
"F22" = TRUE,
"F23" = TRUE,
"F24" = TRUE,
)
// Macro IDs we don't delete on wipe, Usually stuff baked into the skin, or that we have to be more careful with.
protected_macro_ids = list(
"PROTECTED-Shift",
"PROTECTED-ShiftUp"
)

// Badmins just wanna have fun ♪
Expand Down
2 changes: 2 additions & 0 deletions code/modules/client/client_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,5 @@
var/next_move_dir_sub
/// Movement dir of the most recently pressed movement key. Used in cardinal-only movement mode.
var/last_move_dir_pressed
/// Semaphore for macro updates, so that they all complete and don't stomp over each other.
var/updating_macros = 0
16 changes: 6 additions & 10 deletions code/modules/client/client_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,8 @@
var/list/communication_hotkeys = list()
for(var/key in D.key_bindings)
for(var/kb_name in D.key_bindings[key])
if(!prefs.hotkeys && !SSinput.unprintables_cache[key])
continue
switch(kb_name)
if("north")
movement_keys[key] = NORTH
Expand All @@ -662,24 +664,18 @@
winset(src, "default-\ref[key]", "parent=default;name=[key];command=.me")
communication_hotkeys += key

// winget() does not work for F1 and F2
for(var/key in communication_hotkeys)
if(!(key in list("F1","F2")) && !winget(src, "default-\ref[key]", "command"))
to_chat(src, SPAN_WARNING("You probably entered the game with a different keyboard layout.\n<a href='byond://?src=\ref[src];reset_macros=1'>Please switch to the English layout and click here to fix the communication hotkeys.</a>"))
break

/client/proc/get_byond_membership()
return prefs?.is_byond_member || IsByondMember()

Check warning on line 668 in code/modules/client/client_procs.dm

View workflow job for this annotation

GitHub Actions / OpenDream

OD2801: /client.IsByondMember() is unsupported: OpenDream has no premium tier.

/client/proc/set_right_click_menu_mode(shift_only)
if(shift_only)
winset(src, "mapwindow.map", "right-click=true")
winset(src, "ShiftUp", "is-disabled=false")
winset(src, "Shift", "is-disabled=false")
winset(src, "default.PROTECTED-Shift", "command=\".winset :map.right-click=false\nKeyDown Shift\"")
winset(src, "default.PROTECTED-ShiftUp", "command=\".winset :map.right-click=true\nKeyUp Shift\"")
else
winset(src, "mapwindow.map", "right-click=false")
winset(src, "default.Shift", "is-disabled=true")
winset(src, "default.ShiftUp", "is-disabled=true")
winset(src, "default.PROTECTED-Shift", "command=\"KeyDown Shift\"")
winset(src, "default.PROTECTED-ShiftUp", "command=\"KeyUp Shift\"")

/client/verb/drop_item()
set hidden = 1
Expand Down
85 changes: 80 additions & 5 deletions code/modules/client/preference_setup/controls/01_keybindings.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/datum/preferences
/// Whether or not this client has standard hotkeys enabled
var/hotkeys = TRUE
/// Focus Chat masked-out hotkey nag.
var/focus_chat_hotkey_nag = TRUE
/// Custom Keybindings
var/list/key_bindings = list()

Expand Down Expand Up @@ -50,13 +52,60 @@
/datum/category_item/player_setup_item/controls
abstract_type = /datum/category_item/player_setup_item/controls

/datum/category_group/player_setup_category/controls/content(mob/user)
. = ""
for(var/datum/category_item/player_setup_item/PI in items)
. += "[PI.content(user)]<br>"

/datum/category_item/player_setup_item/controls/hotkey_mode
name = "Hotkey Mode"
sort_order = 1

/datum/category_item/player_setup_item/controls/hotkey_mode/load_preferences(datum/pref_record_reader/R)
pref.hotkeys = R.read("hotkey_mode")

/datum/category_item/player_setup_item/controls/hotkey_mode/save_preferences(datum/pref_record_writer/writer)
writer.write("hotkey_mode", pref.hotkeys)

/datum/category_item/player_setup_item/controls/hotkey_mode/sanitize_preferences()
pref.hotkeys = sanitize_bool(pref.hotkeys, TRUE)

/datum/category_item/player_setup_item/controls/hotkey_mode/content(mob/user)
return "<center><b>Hotkey Mode:</b><a href='byond://?src=\ref[src]'>[pref.hotkeys ? "Hotkey" : "Focus Chat"]</a></center>"

/datum/category_item/player_setup_item/controls/hotkey_mode/OnTopic(href, list/href_list, mob/user)
pref.hotkeys = !pref.hotkeys
user.client.set_macros()
return TOPIC_REFRESH

/datum/category_item/player_setup_item/controls/focus_chat_hotkey_nag
name = "Focus Chat Masked Hotkey Nag"
sort_order = 2

/datum/category_item/player_setup_item/controls/focus_chat_hotkey_nag/load_preferences(datum/pref_record_reader/R)
pref.focus_chat_hotkey_nag = R.read("focus_chat_hotkey_nag")

/datum/category_item/player_setup_item/controls/focus_chat_hotkey_nag/save_preferences(datum/pref_record_writer/writer)
writer.write("focus_chat_hotkey_nag", pref.focus_chat_hotkey_nag)

/datum/category_item/player_setup_item/controls/focus_chat_hotkey_nag/sanitize_preferences()
pref.focus_chat_hotkey_nag = sanitize_bool(pref.focus_chat_hotkey_nag, TRUE)

/datum/category_item/player_setup_item/controls/focus_chat_hotkey_nag/content(mob/user)
return "<center><b>Masked Hotkey Warning:</b><a href='byond://?src=\ref[src]'>[pref.focus_chat_hotkey_nag ? "Enabled" : "Disabled"]</a></center>"

/datum/category_item/player_setup_item/controls/focus_chat_hotkey_nag/OnTopic(href, list/href_list, mob/user)
pref.focus_chat_hotkey_nag = !pref.focus_chat_hotkey_nag
return TOPIC_REFRESH

/datum/category_item/player_setup_item/controls/keybindings
name = "Keybindings"
sort_order = 1
sort_order = 3

/datum/category_item/player_setup_item/controls/keybindings/load_preferences(datum/pref_record_reader/R)
pref.key_bindings = R.read("key_bindings")


/datum/category_item/player_setup_item/controls/keybindings/sanitize_preferences()
pref.key_bindings = sanitize_keybindings(pref.key_bindings)
pref.check_keybindings()
Expand Down Expand Up @@ -93,7 +142,12 @@
var/datum/keybinding/kb = i
if(!length(user_binds[kb.name]) || (user_binds[kb.name][1] == "Unbound" && length(user_binds[kb.name]) == 1))
. += "<tr><td width='40%'>[kb.full_name]</td><td width='15%'><a class='fluid' href='byond://?src=\ref[src];preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a></td>"
var/list/default_keys = pref.hotkeys ? kb.hotkey_keys : kb.classic_keys
var/list/default_keys
if(pref.hotkeys)
default_keys = kb.hotkey_keys
else
default_keys = kb.classic_keys || kb.hotkey_keys

var/class
if(user_binds[kb.name] ~= default_keys)
class = "class='linkOff fluid'"
Expand Down Expand Up @@ -198,7 +252,20 @@

if(global._kbMap[new_key])
new_key = global._kbMap[new_key]

if(SSinput.blacklisted_keys[new_key])
alert(user, "Warning: \[[new_key]\] can't be rebound:\n[SSinput.blacklisted_keys[new_key]]","Bind Error", "Cancel")
show_browser(user, null, "window=capturekeypress")
return TOPIC_REFRESH
if(SSinput.warn_keys[new_key])
var/response = alert(user, "Warning: Binding the key \[[new_key]\] can cause issues:\n[SSinput.warn_keys[new_key]]","Bind Warning", "Cancel", "Bind Anyways")
if(response != "Bind Anyways")
show_browser(user, null, "window=capturekeypress")
return TOPIC_REFRESH
if(!pref.hotkeys && !SSinput.unprintables_cache[new_key])
var/response = alert(user, "Notice: Binding the key \[[new_key]\] will have no effect, as you are in Focus Chat mode.","Bind Warning", "Cancel", "Bind Anyways")
if(response != "Bind Anyways")
show_browser(user, null, "window=capturekeypress")
return TOPIC_REFRESH
var/full_key
switch(new_key)
if("Alt")
Expand All @@ -223,7 +290,10 @@
return TOPIC_REFRESH

if("keybindings_reset")
pref.key_bindings = deepCopyList(global.hotkey_keybinding_list_by_key)
if(pref.hotkeys)
pref.key_bindings = deepCopyList(global.hotkey_keybinding_list_by_key)
else
pref.key_bindings = deepCopyList(global.hotkey_keybinding_list_by_key_focused)
user.client.set_macros()
return TOPIC_REFRESH

Expand All @@ -239,7 +309,12 @@
pref.key_bindings -= old_key

var/datum/keybinding/kb = global.keybindings_by_name[kb_name]
for(var/key in kb.hotkey_keys)
var/list/default_keys
if(pref.hotkeys)
default_keys = kb.hotkey_keys
else
default_keys = kb.classic_keys || kb.hotkey_keys
for(var/key in default_keys)
pref.key_bindings[key] += list(kb_name)
pref.key_bindings[key] = sortTim(pref.key_bindings[key], /proc/cmp_text_asc)
user.client.set_macros()
Expand Down
14 changes: 0 additions & 14 deletions code/modules/keybindings/binds/client.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,6 @@
abstract_type = /datum/keybinding/client
category = CATEGORY_CLIENT

/datum/keybinding/client/hotkey_mode
hotkey_keys = list("Tab")
name = "hotkey_mode"
full_name = "Toggle Hotkeys"

/datum/keybinding/client/hotkey_mode/down(client/user)
if(user.prefs)
user.prefs.hotkeys = !user.prefs.hotkeys
if(user.prefs.hotkeys)
winset(user, null, "outputwindow.input.background-color=[COLOR_INPUT_DISABLED];mapwindow.map.focus=true")
else
winset(user, null, "outputwindow.input.background-color=[COLOR_INPUT_ENABLED];outputwindow.input.focus=true")
return TRUE

/datum/keybinding/client/admin_help
hotkey_keys = list("F1")
name = "admin_help"
Expand Down
Loading
Loading