ID:1863765
 
This was an attempt to replace Forum_Account's keyboardlib, which I hate with a burning passion.

I haven't taken the time to document this, and I haven't put it to any serious use. If any of you can comb through this and learn something, you are more than welcome to use it. Yes, I typed this all by hand over the course of about 2 days.

It allows you to track multi-taps on kepresses, track the hold time of the keypress, and instead of defining behavior under the client or mob, necessitating lengthy if-chains, it allows you to use a controller datum to set up keybind rules. A keybind is just a named action that's been associated to a key.

You actually don't have to associate binds to keys at all. Instead, you can trap keypresses and filter them by associated metadata using the key_category()/key_name()/name2keycode()/char2keycode() pseudofunctions I supplied for you. There are shortcuts to getting the typed representation of the character given shift state, capslock state, etc. That function is key_char().

I also rebound Mouse functions so that they could be intercepted by the controller datum and handled there directly prior to passing the functions over to the normal call chain.

Keybind objects allow you to bind a function and object on which actions will be called, they also allow you to specify repeating behaviors with custom delays. Normally, however, a bind is simply associated with a keycode internally and then processed. Binds CAN be associated to multiple keycodes at a time, so you can use a single bind object for W and UP_ARROW and NUMPAD_8 at the same time. Binds can also be handled by overriding BindDown/BindUp/BindRepeat on the controller.



#define MOUSE_BUTTON1       1
#define MOUSE_BUTTON2 2
#define MOUSE_BUTTON3 3
#define KEY_BACKSPACE 8
#define KEY_TAB 9
#define KEY_CENTER 12
#define KEY_RETURN 13
#define KEY_SHIFT 16
#define KEY_CTRL 17
#define KEY_ALT 18
#define KEY_PAUSE 19
#define KEY_ESCAPE 27
#define KEY_SPACE 32
#define KEY_PGUP 33
#define KEY_PGDN 34
#define KEY_END 35
#define KEY_HOME 36
#define KEY_LEFT 37
#define KEY_UP 38
#define KEY_RIGHT 39
#define KEY_DOWN 40
#define KEY_INSERT 45
#define KEY_DELETE 46
#define KEY_0 48
#define KEY_1 49
#define KEY_2 50
#define KEY_3 51
#define KEY_4 52
#define KEY_5 53
#define KEY_6 54
#define KEY_7 55
#define KEY_8 56
#define KEY_9 57
#define KEY_A 65
#define KEY_B 66
#define KEY_C 67
#define KEY_D 68
#define KEY_E 69
#define KEY_F 70
#define KEY_G 71
#define KEY_H 72
#define KEY_I 73
#define KEY_J 74
#define KEY_K 75
#define KEY_L 76
#define KEY_M 77
#define KEY_N 78
#define KEY_O 79
#define KEY_P 80
#define KEY_Q 81
#define KEY_R 82
#define KEY_S 83
#define KEY_T 84
#define KEY_U 85
#define KEY_V 86
#define KEY_W 87
#define KEY_X 88
#define KEY_Y 89
#define KEY_Z 90
#define KEY_LWIN 91
#define KEY_RWIN 92
#define KEY_SELECT 93
#define KEY_NUMPAD_0 96
#define KEY_NUMPAD_1 97
#define KEY_NUMPAD_2 98
#define KEY_NUMPAD_3 99
#define KEY_NUMPAD_4 100
#define KEY_NUMPAD_5 101
#define KEY_NUMPAD_6 102
#define KEY_NUMPAD_7 103
#define KEY_NUMPAD_8 104
#define KEY_NUMPAD_9 105
#define KEY_MULTIPLY 106
#define KEY_ADD 107
#define KEY_SUBTRACT 109
#define KEY_DECIMAL 110
#define KEY_DIVIDE 111
#define KEY_F1 112
#define KEY_F2 113
#define KEY_F3 114
#define KEY_F4 115
#define KEY_F5 116
#define KEY_F6 117
#define KEY_F7 118
#define KEY_F8 119
#define KEY_F9 120
#define KEY_F10 121
#define KEY_F11 122
#define KEY_F12 123
#define KEY_SEMICOLON 186
#define KEY_EQUAL 187
#define KEY_COMMA 188
#define KEY_DASH 189
#define KEY_PERIOD 190
#define KEY_SLASH 191
#define KEY_GRAVE 192
#define KEY_OPEN_BRACKET 219
#define KEY_BACKSLASH 220
#define KEY_CLOSE_BRACKET 221
#define KEY_SINGLE_QUOTE 222

#define CATEGORY_NONE 0
#define CATEGORY_MODIFIER 1
#define CATEGORY_CONTROL 2
#define CATEGORY_FUNCTION 4
#define CATEGORY_NUMPAD 8
#define CATEGORY_ALPHA 16
#define CATEGORY_NUMERIC 32
#define CATEGORY_SYMBOL 64
#define CATEGORY_MOUSE 128

#ifndef STATIC

#define STATIC 0
#define CLICK 1
#define DBLCLICK 2
// Don't define these unless you really need them. They will cause additional network overhead that could otherwise be avoided.
#define MOUSEDOWN 4
#define MOUSEUP 8
#define MOUSEDROP 16
#define MOUSEDRAG 32
#define MOUSEENTERED 64
#define MOUSEEXITED 128
#define MOUSEMOVE 256

#endif

#define key_category(keycode) __key_category[keycode]
#define key_name(keycode) __key_names[keycode]
#define name2keycode(name) __keycode_names[name]
#define char2keycode(char) __keycode_chars[char]

proc
key_char(keycode,shift=0,capslock=0,raw=0)
if(key_category(keycode)==CATEGORY_ALPHA)
shift &= ~capslock
if(shift)
if(raw&&(key_category(keycode)&CATEGORY_SYMBOL))
switch(keycode)
if(KEY_7)
. = "&"
if(KEY_COMMA)
. = "<"
if(KEY_PERIOD)
. = ">"
else
. = __key_chars_shift[keycode]
else
. = __key_chars_shift[keycode]
else
. = __key_chars[keycode]

var/list
__key_category = list(CATEGORY_MOUSE,CATEGORY_MOUSE,CATEGORY_MOUSE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_CONTROL,CATEGORY_CONTROL|CATEGORY_SYMBOL,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_SYMBOL|CATEGORY_NUMPAD,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_MODIFIER,
CATEGORY_MODIFIER,CATEGORY_MODIFIER,CATEGORY_CONTROL,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_CONTROL,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_CONTROL|CATEGORY_SYMBOL,
CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_CONTROL|CATEGORY_NUMPAD,CATEGORY_NONE,CATEGORY_NUMERIC|CATEGORY_SYMBOL,
CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NUMERIC|CATEGORY_SYMBOL,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,
CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,
CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_ALPHA,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NUMERIC|CATEGORY_NUMPAD,
CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_NUMERIC|CATEGORY_NUMPAD,CATEGORY_SYMBOL|CATEGORY_NUMPAD,CATEGORY_SYMBOL|CATEGORY_NUMPAD,CATEGORY_NONE,CATEGORY_SYMBOL|CATEGORY_NUMPAD,CATEGORY_SYMBOL|CATEGORY_NUMPAD,CATEGORY_SYMBOL|CATEGORY_NUMPAD,CATEGORY_FUNCTION,
CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_FUNCTION,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,
CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,
CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,
CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,
CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_SYMBOL,CATEGORY_SYMBOL,CATEGORY_SYMBOL,CATEGORY_SYMBOL,CATEGORY_SYMBOL,CATEGORY_SYMBOL,CATEGORY_SYMBOL,
CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,
CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_NONE,CATEGORY_SYMBOL,CATEGORY_SYMBOL,CATEGORY_SYMBOL,CATEGORY_SYMBOL)

__key_names = list("mouse1","mouse2","mouse3",null,null,null,null,"backspace","tab",null,null,"center","return",null,null,"shift",
"ctrl","alt","pause",null,null,null,null,null,null,null,"escape",null,null,null,null,"space",
"page up","page down","end","home","left","up","right","down",null,null,null,null,"insert","delete",null,"0",
"1","2","3","4","5","6","7","8","9",null,null,null,null,null,null,null,
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p",
"q","r","s","t","u","v","w","x","y","z","lwin","rwin","select",null,null,"numpad 0",
"numpad 1","numpad 2","numpad 3","numpad 4","numpad 5","numpad 6","numpad 7","numpad 8","numpad 9","numpad multiply","numpad add",null,"numpad subtract","numpad decimal","numpad divide","f1",
"f2","f3","f4","f5","f6","f7","f8","f9","f10","f11","f12",null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,"semicolon","equal","comma","dash","period","slash","grave",
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,"open bracket","backslash","close bracket","single quote")

__key_chars = list(null,null,null,null,null,null,null,null,"\t",null,null,null,"\n",null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null," ",
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"0",
"1","2","3","4","5","6","7","8","9",null,null,null,null,null,null,null,
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p",
"q","r","s","t","u","v","w","x","y","z",null,null,null,null,null,"0",
"1","2","3","4","5","6","7","8","9","*","+",null,"-",".","/",null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,";","=",",","-",".","/","`",
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,"\[","\\","]","'")

__key_chars_shift = list(null,null,null,null,null,null,null,null,null,null,null,null,"\n",null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null," ",
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,")",
"!","@","#","$","%","^","&amp;","*","(",null,null,null,null,null,null,null,
"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
"Q","R","S","T","U","V","W","X","Y","Z",null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,"*","+",null,"-",null,"/",null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,":","+","&lt;","_","&gt;","?","~",
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,"{","|","}","\"")

__keycode_names = list("mouse1"=MOUSE_BUTTON1,"mouse2"=MOUSE_BUTTON2,"mouse3"=MOUSE_BUTTON3,"backspace"=KEY_BACKSPACE,"tab"=KEY_TAB,"center"=KEY_CENTER,"return"=KEY_RETURN,"shift"=KEY_SHIFT,
"ctrl"=KEY_CTRL,"alt"=KEY_ALT,"pause"=KEY_PAUSE,"escape"=KEY_ESCAPE,"space"=KEY_SPACE,
"page up"=KEY_PGUP,"page down"=KEY_PGDN,"end"=KEY_END,"home"=KEY_HOME,"left"=KEY_LEFT,"right"=KEY_RIGHT,"down"=KEY_DOWN,"insert"=KEY_INSERT,"delete"=KEY_DELETE,"0"=KEY_0,
"1"=KEY_1,"2"=KEY_2,"3"=KEY_3,"4"=KEY_4,"5"=KEY_5,"6"=KEY_6,"7"=KEY_7,"8"=KEY_8,"9"=KEY_9,
"a"=KEY_A,"b"=KEY_B,"c"=KEY_C,"d"=KEY_D,"e"=KEY_E,"f"=KEY_F,"g"=KEY_G,"h"=KEY_H,"i"=KEY_I,"j"=KEY_J,"k"=KEY_J,"l"=KEY_L,"m"=KEY_M,"n"=KEY_N,"o"=KEY_O,"p"=KEY_P,
"q"=KEY_Q,"r"=KEY_R,"s"=KEY_S,"t"=KEY_T,"u"=KEY_U,"v"=KEY_V,"w"=KEY_W,"x"=KEY_X,"y"=KEY_Y,"z"=KEY_Z,"lwin"=KEY_LWIN,"rwin"=KEY_RWIN,"select"=KEY_SELECT,"numpad 0"=KEY_NUMPAD_0,
"numpad 1"=KEY_NUMPAD_1,"numpad 2"=KEY_NUMPAD_2,"numpad 3"=KEY_NUMPAD_3,"numpad 4"=KEY_NUMPAD_4,"numpad 5"=KEY_NUMPAD_5,"numpad 6"=KEY_NUMPAD_6,"numpad 7"=KEY_NUMPAD_7,"numpad 8"=KEY_NUMPAD_8,"numpad 9"=KEY_NUMPAD_9,"numpad multiply"=KEY_MULTIPLY,"numpad add"=KEY_ADD,"numpad subtract"=KEY_SUBTRACT,"numpad decimal"=KEY_DECIMAL,"numpad divide"=KEY_DIVIDE,
"f1"=KEY_F1,"f2"=KEY_F2,"f3"=KEY_F3,"f4"=KEY_F4,"f5"=KEY_F5,"f6"=KEY_F6,"f7"=KEY_F7,"f8"=KEY_F8,"f9"=KEY_F9,"f10"=KEY_F10,"f11"=KEY_F11,"f12"=KEY_F12,
"semicolon"=KEY_SEMICOLON,"equal"=KEY_EQUAL,"comma"=KEY_COMMA,"dash"=KEY_DASH,"period"=KEY_PERIOD,"slash"=KEY_SLASH,"grave"=KEY_GRAVE,
"open bracket"=KEY_OPEN_BRACKET,"backslash"=KEY_BACKSLASH,"close bracket"=KEY_CLOSE_BRACKET,"single quote"=KEY_SINGLE_QUOTE)

__keycode_chars = list(" "=KEY_SPACE,
"0"=KEY_0,")"=KEY_0,
"1"=KEY_1,"2"=KEY_2,"3"=KEY_3,"4"=KEY_4,"5"=KEY_5,"6"=KEY_6,"7"=KEY_7,"8"=KEY_8,"9"=KEY_9,"!"=KEY_1,"@"=KEY_2,"#"=KEY_3,"$"=KEY_4,"%"=KEY_5,"^"=KEY_6,"&amp;"=KEY_7,"*"=KEY_8,"("=KEY_9,
"a"=KEY_A,"b"=KEY_B,"c"=KEY_C,"d"=KEY_D,"e"=KEY_E,"f"=KEY_F,"g"=KEY_G,"h"=KEY_H,"i"=KEY_I,"j"=KEY_J,"k"=KEY_J,"l"=KEY_L,"m"=KEY_M,"n"=KEY_N,"o"=KEY_O,"p"=KEY_P,
"q"=KEY_Q,"r"=KEY_R,"s"=KEY_S,"t"=KEY_T,"u"=KEY_U,"v"=KEY_V,"w"=KEY_W,"x"=KEY_X,"y"=KEY_Y,"z"=KEY_Z,
"A"=KEY_A,"B"=KEY_B,"C"=KEY_C,"D"=KEY_D,"E"=KEY_E,"F"=KEY_F,"G"=KEY_G,"H"=KEY_H,"I"=KEY_I,"J"=KEY_J,"K"=KEY_J,"L"=KEY_L,"M"=KEY_M,"N"=KEY_N,"O"=KEY_O,"P"=KEY_P,
"Q"=KEY_Q,"R"=KEY_R,"S"=KEY_S,"T"=KEY_T,"U"=KEY_U,"V"=KEY_V,"W"=KEY_W,"X"=KEY_X,"Y"=KEY_Y,"Z"=KEY_Z,
";"=KEY_SEMICOLON,"="=KEY_EQUAL,","=KEY_COMMA,"-"=KEY_DASH,"."=KEY_PERIOD,"/"=KEY_SLASH,"`"=KEY_GRAVE,
":"=KEY_SEMICOLON,"+"=KEY_EQUAL,"&lt;"=KEY_COMMA,"_"=KEY_DASH,"&gt;"=KEY_PERIOD,"?"=KEY_SLASH,"~"=KEY_GRAVE,
"\["=KEY_OPEN_BRACKET,"\\"=KEY_BACKSLASH,"]"=KEY_CLOSE_BRACKET,"'"=KEY_SINGLE_QUOTE,
"{"=KEY_OPEN_BRACKET,"|"=KEY_BACKSLASH,"}"=KEY_CLOSE_BRACKET,"\""=KEY_SINGLE_QUOTE)

/* keynum = list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
65,66,67,68,69,79,71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,
145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,
161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,
177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,
209,210,211,212,213,214,215,216,217,218,219,220,221,222)*/


#define MULTITAP_DELAY 1.5

client
var/tmp
list/active_keys = list()
browser
browser_version = 0
// focus
controller/controller
proc
getKeyState(Keycode)
. = active_keys[key_name(Keycode)]

setController(controller/Controller,Force=FALSE)
if(controller&&!controller.Surrender(Controller,Force)) return FALSE
if(Controller&&!Controller.Override(controller,Force)) return FALSE
Controller.owner = src
var/keycode
if(controller&&Controller)
for(var/keyname in active_keys)
keycode = name2keycode(keyname)
controller.KeyUp(keycode)
Controller.KeyDown(keycode)
else if(controller)
for(var/keyname in active_keys)
keycode = name2keycode(keyname)
controller.KeyUp(keycode)
else if(Controller)
for(var/keyname in active_keys)
keycode = name2keycode(keyname)
Controller.KeyDown(keycode)
controller = Controller

verb
/* LostFocus()
set hidden = 1
set instant = 1
focus = null

FocusChanged(elem as text)
set hidden = 1
set instant = 1
focus = elem*/


setBrowser(Browser as text,Version as num)
set hidden = 1
set instant = 1
browser = Browser
browser_version = Version

ClearKeys()
set instant = 1
set hidden = 1
for(var/keyname in active_keys)
KeyUp(name2keycode(keyname))

KeyDown(keycode as num)
set instant = 1
set hidden = 1
if(keycode>0&&keycode<223)
active_keys[key_name(keycode)] = 1
if(controller)
controller.KeyDown(keycode)
/*switch(keycode)
if(KEY_W)
while(active_keys[key_name(keycode)])
North()
sleep(TICK_LAG)
if(KEY_A)
while(active_keys[key_name(keycode)])
West()
sleep(TICK_LAG)
if(KEY_S)
while(active_keys[key_name(keycode)])
South()
sleep(TICK_LAG)
if(KEY_D)
while(active_keys[key_name(keycode)])
East()
sleep(TICK_LAG)
if(KEY_1)
var/ability/jutak/ability1/a = new()
a.onUse(mob)
if(KEY_2)
var/ability/jutak/ability2/a = new()
a.onUse(mob)
if(KEY_3)
var/ability/jutak/ability3/a = new()
a.onUse(mob)
if(KEY_O)
var/status_effect/timed/stun/s = new()
var/mob/combatant/c = mob
c.AddStatusEffect(s)
if(KEY_P)
var/status_effect/ticker/knockback/k = new(4,GetMouseAng(),16)
var/mob/combatant/c = mob
c.AddStatusEffect(k)*/


KeyUp(keycode as num)
set instant = 1
set hidden = 1
if(keycode>0&&keycode<223)
active_keys -= key_name(keycode)
if(controller)
controller.KeyUp(keycode)

New()
new/browser(src,"jsbrowser",'JSinterface.html')
..()

#ifdef CLICK
Click(atom/object,location,control,params)
if(controller&&controller.mouse_control&CLICK)
. = controller.onClick(object,location,control,params)
else
. = object.Click(location,control,params)
#endif

#ifdef DBLCLICK
DblClick(atom/object,location,control,params)
if(controller&&controller.mouse_control&DBLCLICK)
. = controller.onDblClick(object,location,control,params)
else
. = object.DblClick(location,control,params)
#endif

#ifdef MOUSEDOWN
MouseDown(atom/object,location,control,params)
if(controller&&controller.mouse_control&MOUSEDOWN)
. = controller.onMouseDown(object,location,control,params)
else
. = object.MouseDown(location,control,params)

if(!.)
var/list/l = params2list(params)
if(l["left"]=="1")
KeyDown(MOUSE_BUTTON1)
if(l["right"]=="1")
KeyDown(MOUSE_BUTTON2)
if(l["middle"]=="1")
KeyDown(MOUSE_BUTTON3)
#endif

#ifdef MOUSEUP
MouseUp(atom/object,location,control,params)
var/list/l = params2list(params)
if(active_keys[key_name(MOUSE_BUTTON1)])
if(l["left"]=="1")
KeyUp(MOUSE_BUTTON1)
if(active_keys[key_name(MOUSE_BUTTON2)])
if(l["right"]=="1")
KeyUp(MOUSE_BUTTON2)
if(active_keys[key_name(MOUSE_BUTTON3)])
if(l["middle"]=="1")
KeyUp(MOUSE_BUTTON3)

if(controller&&controller.mouse_control&MOUSEUP)
. = controller.onMouseUp(object,location,control,params)
else
. = object.MouseUp(location,control,params)
#endif

#ifdef MOUSEDRAG
MouseDrag(atom/src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
if(controller&&controller.mouse_control&MOUSEDRAG)
. = controller.onMouseDrag(over_object,src_location,over_location,src_control,over_control,params)
else
. = src_object.MouseDrag(over_object,src_location,over_location,src_control,over_control,params)
#endif

#ifdef MOUSEDROP
MouseDrop(atom/src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
if(controller&&controller.mouse_control&MOUSEDROP)
. = controller.onMouseDrop(over_object,src_location,over_location,src_control,over_control,params)
else
. = src_object.MouseDrop(over_object,src_location,over_location,src_control,over_control,params)
#endif

#ifdef MOUSEENTERED
MouseEntered(atom/object,location,control,params)
if(controller&&controller.mouse_control&MOUSEENTERED)
. = controller.onMouseEntered(object,location,control,params)
else
. = object.MouseEntered(location,control,params)
#endif

#ifdef MOUSEEXITED
MouseExited(atom/object,location,control,params)
if(controller&&controller.mouse_control&MOUSEEXITED)
. = controller.onMouseExited(object,location,control,params)
else
. = object.MouseExited(location,control,params)
#endif

#ifdef MOUSEMOVE
MouseMove(atom/object,location,control,params)
if(controller&&controller.mouse_control&MOUSEMOVE)
. = controller.onMouseMove(object,location,control,params)
else
. = object.MouseMove(location,control,params)
#endif

controller
var/tmp
client/owner
list/registry[222]
list/binds = list()
mouse_control = STATIC
proc
setBind(Bind)
var/len = args.len

for(var/count=2;count<=len;count++)
registry[args[count]] = Bind

if(!binds[Bind])
binds[Bind] = void

AddBind(keybind/Bind)
var/len = args.len
var/keybind/override
if(len==1)
var/keybind/old = binds[Bind.id]
if(old)
for(var/keycode in Bind.keycodes)
override = registry[keycode]
if(override)
if(override==old.id) continue
override = binds[override]
override.Unbind(keycode)
if(override.keycodes==null)
binds -= override.id
registry[keycode] = old.id
old.Bind(keycode)
old.repeat_delay = Bind.repeat_delay || old.repeat_delay
old.first_repeat_delay = Bind.first_repeat_delay || old.first_repeat_delay
old.call_func = Bind.call_func || old.call_func
old.call_obj = Bind.call_obj || old.call_obj
. = old
else
for(var/keycode in Bind.keycodes)
override = registry[keycode]
if(override)
override = binds[override]
override.Unbind(keycode)
if(override.keycodes==null)
binds -= override.id
registry[keycode] = Bind.id
binds[Bind.id] = Bind
. = Bind
else
var/keybind/old = binds[Bind]
var/keycode
if(old)
for(var/count=2;count<=len;count++)
keycode = args[count]
override = registry[keycode]
if(override)
if(override==old.id) continue
override = binds[override]
override.Unbind(keycode)
if(override.keycodes==null)
binds -= override.id
registry[keycode] = Bind
old.Bind(keycode)
. = old
else
Bind = new(Bind)
binds[Bind.id] = Bind
for(var/count=2;count<=len;count++)
keycode = args[count]
registry[keycode] = Bind.id
Bind.Bind(keycode)
. = Bind

RemoveBind(keybind/Bind)
var/len = args.len
if(len==1)
if(isnum(Bind))

else if(istext(Bind))
Bind = binds[Bind]
for(var/keycode in Bind.keycodes)
registry[keycode] = null
binds -= Bind
else
var/keycode
if(isnum(Bind))
var/keybind/override
for(var/count=1;count<=len;count++)
keycode = args[count]
override = registry[keycode]
if(override)
override = binds[keycode]
override.Unbind(keycode)
if(override.keycodes==null)
binds -= override.id
return
else if(istext(Bind))
Bind = binds[Bind]
for(var/count=2;count<=len;count++)
keycode = args[count]
registry[keycode] = null
Bind.Unbind(keycode)

KeyDown(Keycode)
var/bind = registry[Keycode]
if(bind)
. = BindDown(binds[bind],Keycode)
else
. = FALSE

KeyUp(Keycode)
var/bind = registry[Keycode]
if(bind)
. = BindUp(binds[bind],Keycode)
else
. = FALSE

BindDown(keybind/Bind,Keycode)
var/time = world.time
if(Bind.keyevent)
if(Bind.keyevent.state) return FALSE
if(Bind.keyevent.press_time>Bind.keyevent.release_time) return
if(time-Bind.keyevent.release_time<=MULTITAP_DELAY)
Bind.keyevent.taps += 1
else
Bind.keyevent.taps = 1
else
Bind.keyevent = new()
Bind.keyevent.press_time = time
Bind.keyevent.state = TRUE
if(Bind.call_obj&&Bind.call_func)
call(Bind.call_obj,Bind.call_func)(src,Bind,Keycode)
if(Bind.first_repeat_delay&&Bind.repeat_delay)
spawn()
sleep(Bind.first_repeat_delay)
call(Bind.call_obj,Bind.call_func)(src,Bind,Keycode)
while(Bind.keyevent.state&&Bind.keyevent.press_time==time)
BindRepeat(Bind,Keycode)
sleep(Bind.repeat_delay)
else if(Bind.first_repeat_delay&&Bind.repeat_delay)
spawn()
sleep(Bind.first_repeat_delay)
while(Bind.keyevent.state&&Bind.keyevent.press_time==time)
BindRepeat(Bind,Keycode)
sleep(Bind.repeat_delay)
. = TRUE

BindUp(keybind/Bind,Keycode)
for(var/v in Bind.keycodes)
if(owner.active_keys[key_name(v)])
return FALSE
var/time = world.time
if(!Bind.keyevent)
Bind.keyevent = new()
Bind.keyevent.press_time = time
Bind.keyevent.release_time = time
Bind.keyevent.state = FALSE
Bind.keyevent.release_time = time
if(Bind.call_obj&&Bind.call_func)
call(Bind.call_obj,Bind.call_func)(src,Bind,Keycode)
. = TRUE

BindRepeat(keybind/Bind,Keycode)
if(Bind.call_obj&&Bind.call_func)
call(Bind.call_obj,Bind.call_func)(src,Bind,Keycode)
. = TRUE

onClick(atom/object,location,control,params)
. = object.Click(location,control,params)

onDblClick(atom/object,location,control,params)
. = object.DblClick(location,control,params)

onMouseDown(atom/object,location,control,params)
. = object.MouseDown(location,control,params)

onMouseUp(atom/object,location,control,params)
. = object.MouseUp(location,control,params)

onMouseDrag(atom/src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
. = src_object.MouseDrag(over_object,src_location,over_location,src_control,over_control,params)

onMouseDrop(atom/src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
. = src_object.MouseDrop(over_object,src_location,over_location,src_control,over_control,params)

onMouseEntered(atom/object,location,control,params)
. = object.MouseEntered(location,control,params)

onMouseExited(atom/object,location,control,params)
. = object.MouseExited(location,control,params)

onMouseMove(atom/object,location,control,params)
. = object.MouseMove(location,control,params)

Override(controller/Controller,Force=FALSE)
return TRUE

Surrender(controller/Controller,Force=FALSE)
return TRUE

New(client/Owner)
..()
owner = Owner

keybind
var/tmp
id
list/keycodes
keyevent/keyevent

first_repeat_delay
repeat_delay

call_func
datum/call_obj
proc
Bind(keycode)
if(keycodes==null)
keycodes = keycode
. = 1
else if(!islist(keycodes))
if(keycodes!=keycode)
keycodes = list(keycodes,keycode)
. = 1
else
. = 0
else
. = keycodes.len
keycodes |= keycode
. = keycodes.len - .

Unbind(keycode)
if(islist(keycodes))
. = keycodes.Remove(keycode)
if(keycodes.len==1)
keycodes = keycodes[1]
else
if(keycodes==keycode)
keycodes = null
. = 1
else
. = 0

New(Id,Keycodes,FirstDelay=0,Delay=0,CallFunc=null,CallObj=null)
id = Id
keycodes = Keycodes
first_repeat_delay = FirstDelay
repeat_delay = Delay
call_func = CallFunc
call_obj = CallObj
..()

keyevent
var/tmp
press_time
release_time = -1.#INF
taps = 1
state = TRUE

New(Time,Taps=1,State=TRUE)
press_time = Time
taps = Taps
state = State


Open your interface file in a text editor (back it up first, ya dingus), and copy and paste these macro definitions under whatever macro set you want to use as your primary macro set. If you use this library, you should always have ALL macros active. Don't mess with them during runtime, because that's what keybind and controller swaps are for.

macro "TYPE_NAME_HERE"
elem
name = "BACK"
command = "KeyDown 8"
is-disabled = false
elem
name = "BACK+UP"
command = "KeyUp 8"
is-disabled = false
elem
name = "TAB"
command = "KeyDown 9"
is-disabled = false
elem
name = "TAB+UP"
command = "KeyUp 9"
is-disabled = false
elem
name = "CENTER"
command = "KeyDown 13"
is-disabled = false
elem
name = "CENTER+UP"
command = "KeyUp 13"
is-disabled = false
elem
name = "RETURN"
command = "KeyDown 13"
is-disabled = false
elem
name = "RETURN+UP"
command = "KeyUp 13"
is-disabled = false
elem
name = "PAUSE"
command = "KeyDown 19"
is-disabled = false
elem
name = "PAUSE+UP"
command = "KeyUp 19"
is-disabled = false
elem
name = "ESCAPE"
command = "KeyDown 27"
is-disabled = false
elem
name = "ESCAPE+UP"
command = "KeyUp 27"
is-disabled = false
elem
name = "SPACE"
command = "KeyDown 32"
is-disabled = false
elem
name = "SPACE+UP"
command = "KeyUp 32"
is-disabled = false
elem
name = "NORTHEAST"
command = "KeyDown 33"
is-disabled = false
elem
name = "NORTHEAST+UP"
command = "KeyUp 33"
is-disabled = false
elem
name = "SOUTHEAST"
command = "KeyDown 34"
is-disabled = false
elem
name = "SOUTHEAST+UP"
command = "KeyUp 34"
is-disabled = false
elem
name = "SOUTHWEST"
command = "KeyDown 35"
is-disabled = false
elem
name = "SOUTHWEST+UP"
command = "KeyUp 35"
is-disabled = false
elem
name = "NORTHWEST"
command = "KeyDown 36"
is-disabled = false
elem
name = "NORTHWEST+UP"
command = "KeyUp 36"
is-disabled = false
elem
name = "WEST"
command = "KeyDown 37"
is-disabled = false
elem
name = "WEST+UP"
command = "KeyUp 37"
is-disabled = false
elem
name = "NORTH"
command = "KeyDown 38"
is-disabled = false
elem
name = "NORTH+UP"
command = "KeyUp 38"
is-disabled = false
elem
name = "EAST"
command = "KeyDown 39"
is-disabled = false
elem
name = "EAST+UP"
command = "KeyUp 39"
is-disabled = false
elem
name = "SOUTH"
command = "KeyDown 40"
is-disabled = false
elem
name = "SOUTH+UP"
command = "KeyUp 40"
is-disabled = false
elem
name = "INSERT"
command = "KeyDown 45"
is-disabled = false
elem
name = "INSERT+UP"
command = "KeyUp 45"
is-disabled = false
elem
name = "DELETE"
command = "KeyDown 46"
is-disabled = false
elem
name = "DELETE+UP"
command = "KeyUp 46"
is-disabled = false
elem
name = "0"
command = "KeyDown 48"
is-disabled = false
elem
name = "0+UP"
command = "KeyUp 48"
is-disabled = false
elem
name = "1"
command = "KeyDown 49"
is-disabled = false
elem
name = "1+UP"
command = "KeyUp 49"
is-disabled = false
elem
name = "2"
command = "KeyDown 50"
is-disabled = false
elem
name = "2+UP"
command = "KeyUp 50"
is-disabled = false
elem
name = "3"
command = "KeyDown 51"
is-disabled = false
elem
name = "3+UP"
command = "KeyUp 51"
is-disabled = false
elem
name = "4"
command = "KeyDown 52"
is-disabled = false
elem
name = "4+UP"
command = "KeyUp 52"
is-disabled = false
elem
name = "5"
command = "KeyDown 53"
is-disabled = false
elem
name = "5+UP"
command = "KeyUp 53"
is-disabled = false
elem
name = "6"
command = "KeyDown 54"
is-disabled = false
elem
name = "6+UP"
command = "KeyUp 54"
is-disabled = false
elem
name = "7"
command = "KeyDown 55"
is-disabled = false
elem
name = "7+UP"
command = "KeyUp 55"
is-disabled = false
elem
name = "8"
command = "KeyDown 56"
is-disabled = false
elem
name = "8+UP"
command = "KeyUp 56"
is-disabled = false
elem
name = "9"
command = "KeyDown 57"
is-disabled = false
elem
name = "9+UP"
command = "KeyUp 57"
is-disabled = false
elem
name = "A"
command = "KeyDown 65"
is-disabled = false
elem
name = "A+UP"
command = "KeyUp 65"
is-disabled = false
elem
name = "B"
command = "KeyDown 66"
is-disabled = false
elem
name = "B+UP"
command = "KeyUp 66"
is-disabled = false
elem
name = "C"
command = "KeyDown 67"
is-disabled = false
elem
name = "C+UP"
command = "KeyUp 67"
is-disabled = false
elem
name = "D"
command = "KeyDown 68"
is-disabled = false
elem
name = "D+UP"
command = "KeyUp 68"
is-disabled = false
elem
name = "E"
command = "KeyDown 69"
is-disabled = false
elem
name = "E+UP"
command = "KeyUp 69"
is-disabled = false
elem
name = "F"
command = "KeyDown 70"
is-disabled = false
elem
name = "F+UP"
command = "KeyUp 70"
is-disabled = false
elem
name = "G"
command = "KeyDown 71"
is-disabled = false
elem
name = "G+UP"
command = "KeyUp 71"
is-disabled = false
elem
name = "H"
command = "KeyDown 72"
is-disabled = false
elem
name = "H+UP"
command = "KeyUp 72"
is-disabled = false
elem
name = "I"
command = "KeyDown 73"
is-disabled = false
elem
name = "I+UP"
command = "KeyUp 73"
is-disabled = false
elem
name = "J"
command = "KeyDown 74"
is-disabled = false
elem
name = "J+UP"
command = "KeyUp 74"
is-disabled = false
elem
name = "K"
command = "KeyDown 75"
is-disabled = false
elem
name = "K+UP"
command = "KeyUp 75"
is-disabled = false
elem
name = "L"
command = "KeyDown 76"
is-disabled = false
elem
name = "L+UP"
command = "KeyUp 76"
is-disabled = false
elem
name = "M"
command = "KeyDown 77"
is-disabled = false
elem
name = "M+UP"
command = "KeyUp 77"
is-disabled = false
elem
name = "N"
command = "KeyDown 78"
is-disabled = false
elem
name = "N+UP"
command = "KeyUp 78"
is-disabled = false
elem
name = "O"
command = "KeyDown 79"
is-disabled = false
elem
name = "O+UP"
command = "KeyUp 79"
is-disabled = false
elem
name = "P"
command = "KeyDown 80"
is-disabled = false
elem
name = "P+UP"
command = "KeyUp 80"
is-disabled = false
elem
name = "Q"
command = "KeyDown 81"
is-disabled = false
elem
name = "Q+UP"
command = "KeyUp 81"
is-disabled = false
elem
name = "R"
command = "KeyDown 82"
is-disabled = false
elem
name = "R+UP"
command = "KeyUp 82"
is-disabled = false
elem
name = "S"
command = "KeyDown 83"
is-disabled = false
elem
name = "S+UP"
command = "KeyUp 83"
is-disabled = false
elem
name = "T"
command = "KeyDown 84"
is-disabled = false
elem
name = "T+UP"
command = "KeyUp 84"
is-disabled = false
elem
name = "U"
command = "KeyDown 85"
is-disabled = false
elem
name = "U+UP"
command = "KeyUp 85"
is-disabled = false
elem
name = "V"
command = "KeyDown 86"
is-disabled = false
elem
name = "V+UP"
command = "KeyUp 86"
is-disabled = false
elem
name = "W"
command = "KeyDown 87"
is-disabled = false
elem
name = "W+UP"
command = "KeyUp 87"
is-disabled = false
elem
name = "X"
command = "KeyDown 88"
is-disabled = false
elem
name = "X+UP"
command = "KeyUp 88"
is-disabled = false
elem
name = "Y"
command = "KeyDown 89"
is-disabled = false
elem
name = "Y+UP"
command = "KeyUp 89"
is-disabled = false
elem
name = "Z"
command = "KeyDown 90"
is-disabled = false
elem
name = "Z+UP"
command = "KeyUp 90"
is-disabled = false
elem
name = "LWIN"
command = "KeyDown 91"
is-disabled = false
elem
name = "LWIN+UP"
command = "KeyUp 91"
is-disabled = false
elem
name = "RWIN"
command = "KeyDown 92"
is-disabled = false
elem
name = "RWIN+UP"
command = "KeyUp 92"
is-disabled = false
elem
name = "APPS"
command = "KeyDown 93"
is-disabled = false
elem
name = "APPS+UP"
command = "KeyUp 93"
is-disabled = false
elem
name = "NUMPAD0"
command = "KeyDown 96"
is-disabled = false
elem
name = "NUMPAD0+UP"
command = "KeyUp 96"
is-disabled = false
elem
name = "NUMPAD1"
command = "KeyDown 97"
is-disabled = false
elem
name = "NUMPAD1+UP"
command = "KeyUp 97"
is-disabled = false
elem
name = "NUMPAD2"
command = "KeyDown 98"
is-disabled = false
elem
name = "NUMPAD2+UP"
command = "KeyUp 98"
is-disabled = false
elem
name = "NUMPAD3"
command = "KeyDown 99"
is-disabled = false
elem
name = "NUMPAD3+UP"
command = "KeyUp 99"
is-disabled = false
elem
name = "NUMPAD4"
command = "KeyDown 100"
is-disabled = false
elem
name = "NUMPAD4+UP"
command = "KeyUp 100"
is-disabled = false
elem
name = "NUMPAD5"
command = "KeyDown 101"
is-disabled = false
elem
name = "NUMPAD5+UP"
command = "KeyUp 101"
is-disabled = false
elem
name = "NUMPAD6"
command = "KeyDown 102"
is-disabled = false
elem
name = "NUMPAD6+UP"
command = "KeyUp 102"
is-disabled = false
elem
name = "NUMPAD7"
command = "KeyDown 103"
is-disabled = false
elem
name = "NUMPAD7+UP"
command = "KeyUp 103"
is-disabled = false
elem
name = "NUMPAD8"
command = "KeyDown 104"
is-disabled = false
elem
name = "NUMPAD8+UP"
command = "KeyUp 104"
is-disabled = false
elem
name = "NUMPAD9"
command = "KeyDown 105"
is-disabled = false
elem
name = "NUMPAD9+UP"
command = "KeyUp 105"
is-disabled = false
elem
name = "MULTIPLY"
command = "KeyDown 106"
is-disabled = false
elem
name = "MULTIPLY+UP"
command = "KeyUp 106"
is-disabled = false
elem
name = "ADD"
command = "KeyDown 107"
is-disabled = false
elem
name = "ADD+UP"
command = "KeyUp 107"
is-disabled = false
elem
name = "SUBTRACT"
command = "KeyDown 109"
is-disabled = false
elem
name = "SUBTRACT+UP"
command = "KeyUp 109"
is-disabled = false
elem
name = "DECIMAL"
command = "KeyDown 110"
is-disabled = false
elem
name = "DECIMAL+UP"
command = "KeyUp 110"
is-disabled = false
elem
name = "DIVIDE"
command = "KeyDown 111"
is-disabled = false
elem
name = "DIVIDE+UP"
command = "KeyUp 111"
is-disabled = false
elem
name = "F1"
command = "KeyDown 112"
is-disabled = false
elem
name = "F1+UP"
command = "KeyUp 112"
is-disabled = false
elem
name = "F2"
command = "KeyDown 113"
is-disabled = false
elem
name = "F2+UP"
command = "KeyUp 113"
is-disabled = false
elem
name = "F3"
command = "KeyDown 114"
is-disabled = false
elem
name = "F3+UP"
command = "KeyUp 114"
is-disabled = false
elem
name = "F4"
command = "KeyDown 115"
is-disabled = false
elem
name = "F4+UP"
command = "KeyUp 115"
is-disabled = false
elem
name = "F5"
command = "KeyDown 116"
is-disabled = false
elem
name = "F5+UP"
command = "KeyUp 116"
is-disabled = false
elem
name = "F6"
command = "KeyDown 117"
is-disabled = false
elem
name = "F6+UP"
command = "KeyUp 117"
is-disabled = false
elem
name = "F7"
command = "KeyDown 118"
is-disabled = false
elem
name = "F7+UP"
command = "KeyUp 118"
is-disabled = false
elem
name = "F8"
command = "KeyDown 119"
is-disabled = false
elem
name = "F8+UP"
command = "KeyUp 119"
is-disabled = false
elem
name = "F9"
command = "KeyDown 120"
is-disabled = false
elem
name = "F9+UP"
command = "KeyUp 120"
is-disabled = false
elem
name = "F10"
command = "KeyDown 121"
is-disabled = false
elem
name = "F10+UP"
command = "KeyUp 121"
is-disabled = false
elem
name = "F11"
command = "KeyDown 122"
is-disabled = false
elem
name = "F11+UP"
command = "KeyUp 122"
is-disabled = false
elem
name = "F12"
command = "KeyDown 123"
is-disabled = false
elem
name = "F12+UP"
command = "KeyUp 123"
is-disabled = false
elem
name = ";"
command = "KeyDown 186"
is-disabled = false
elem
name = ";+UP"
command = "KeyUp 186"
is-disabled = false
elem
name = "="
command = "KeyDown 187"
is-disabled = false
elem
name = "=+UP"
command = "KeyUp 187"
is-disabled = false
elem
name = ","
command = "KeyDown 188"
is-disabled = false
elem
name = ",+UP"
command = "KeyUp 188"
is-disabled = false
elem
name = "-"
command = "KeyDown 189"
is-disabled = false
elem
name = "-+UP"
command = "KeyUp 189"
is-disabled = false
elem
name = "."
command = "KeyDown 190"
is-disabled = false
elem
name = ".+UP"
command = "KeyUp 190"
is-disabled = false
elem
name = "/"
command = "KeyDown 191"
is-disabled = false
elem
name = "/+UP"
command = "KeyUp 191"
is-disabled = false
elem
name = "`"
command = "KeyDown 192"
is-disabled = false
elem
name = "`+UP"
command = "KeyUp 192"
is-disabled = false
elem
name = "["
command = "KeyDown 219"
is-disabled = false
elem
name = "[+UP"
command = "KeyUp 219"
is-disabled = false
elem
name = "\\"
command = "KeyDown 220"
is-disabled = false
elem
name = "\\+UP"
command = "KeyUp 220"
is-disabled = false
elem
name = "]"
command = "KeyDown 221"
is-disabled = false
elem
name = "]+UP"
command = "KeyUp 221"
is-disabled = false
elem
name = "'"
command = "KeyDown 222"
is-disabled = false
elem
name = "'+UP"
command = "KeyUp 222"
is-disabled = false
elem
name = "ALT"
command = "KeyDown 18"
is-disabled = false
elem
name = "CTRL"
command = "KeyDown 17"
is-disabled = false
elem
name = "SHIFT"
command = "KeyDown 16"
is-disabled = false
elem
name = "ALT+UP"
command = "KeyUp 18"
is-disabled = false
elem
name = "CTRL+UP"
command = "KeyUp 17"
is-disabled = false
elem
name = "SHIFT+UP"
command = "KeyUp 16"
is-disabled = false


Lastly, you need this for some stuff that I define in the controller for extra features: "JSinterface.html"

Hide a browser element behind your map and call it "jsbrowser".

<!DOCTYPE html>
<HTML>
<HEAD>
<META http-equiv="X-UA-Compatible" content="IE=edge">
<STYLE type="text/css">
body {
background-color:#000000;
margin: 0px;
}
</STYLE>
</HEAD>
</HTML>
<BODY>
</BODY>
<SCRIPT type="text/javascript">
var browsername;

function get_browser_info(){
var ua=navigator.userAgent,tem,M=ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem=/\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'Internet Explorer',version:(tem[1]||'')};
}
if(M[1]==='Chrome'){
tem=ua.match(/\bOPR\/(\d+)/)
if(tem!=null) {return {name:'Opera', version:tem[1]};}
}
M=M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem=ua.match(/version\/(\d+)/i))!=null) {M.splice(1,1,tem[1]);}
var ret = {
name: M[0],
version: M[1]
};
if(ret.name==="MSIE"&&ret.version==="7")
{
ret.name = "Internet Explorer";
if(typeof navigator.maxTouchPoints !="undefined") ret.version = "11";
else if(document.all && window.matchMedia) ret.version = "10";
else if(XDomainRequest && window.msPerformance) ret.version = "9";
else if(XDomainRequest) ret.version = "8";
else if(document.documentElement && typeof document.documentElement.style.maxHeight!="undefined") ret.version = "7";
else if(document.compatMode && document.all) ret.version = "6"; //uhh?
else if(window.createPopup) ret.version = "5.5";
else if(document.all) ret.version = "4";
}
return ret;
}

function CallVerb() {
var locstr = "byond://winset?command=" + encodeURIComponent(arguments[0]);
for(var count=1;count<arguments.length;count++) {
locstr += " " + encodeURIComponent(arguments[count]);
}
window.location = locstr;
}

function WinSet() {
var locstr = "byond://winset?id=" + encodeURIComponent(arguments[0]);
for(var count=1;count<arguments.length;count+=2) {
locstr += "&" + encodeURIComponent(arguments[count]) + "=" + encodeURIComponent(arguments[count+1]);
}
window.location = locstr;
}

function Output() {
window.location = "byond://winset?command=.output " + encodeURIComponent(arguments[0]) + " " + encodeURIComponent(arguments[1]);
}

function BrowserInit(BrowserName) {
if(typeof browsername!=="undefined") return;
var browser = get_browser_info();
browsername = BrowserName;
CallVerb("browserconfirm",BrowserName);
CallVerb("setBrowser","\""+browser.name+"\"",browser.version);
//window.setInterval(CheckFocus,100);
}

var focuselem;

function CheckFocus() {
window.location = "byond://winget?callback=UpdateFocus&id=&property=focus";
}

function CheckWindow(data) {
winvis = data['is-visible'];
}

function UpdateFocus(data) {
if(focuselem!==data.focus) {
focuselem = data.focus;
if(focuselem==="")
{
CallVerb("LostFocus");
}
else
{
CallVerb("FocusChanged",focuselem);
}
}
}

function jsCall(FuncName) {
window[FuncName].apply(null,Array.prototype.slice.call(arguments,2));
}
</SCRIPT>
</HTML>


Also, to get the browser to work properly, you'll need a copy of my unreleased BrowserLib:

client
var
list/browsers = list()
timer = 0
verb
browserconfirm(browser as text)
set hidden = 1
var/browser/b = browsers[browser]
if(!b.initialized)
b.Initialized()
proc
CallJS(browser,function,arguments)
var/browser/b = browsers[browser]
b.CallJS(function,arguments)

Del()
for(var/browser/b in browsers)
b.Cleanup()
. = ..()

browser
var/tmp
id
client/client
initialized = 0
proc
Initialized()
initialized = 1

CallJS(Function,Arguments)
set waitfor = 0
if(islist(Arguments))
Arguments = list2params(Arguments)
while(!initialized)
sleep(TICK_LAG)
client << output("[Function]&[Arguments]","[id]:jsCall")

New(client/Client,Id,Page,list/Resources=null)
Client.browsers[Id] = src
client = Client
id = Id
for(var/v in Resources)
client << browse_rsc(v)
spawn()
while(!initialized)
client << browse(Page,"window=[id]")
while(!initialized)
sleep(10)
client << output(id,"[id]:BrowserInit")
sleep(50)

Cleanup()
client = null
Dammit, how many 'null's did I type already. 1, 2, 3, 4...

Looks pretty nifty. I've never really used his keyboard lib, but I'll try this out when I get a chance.
The structure is more the interesting thing. The actual code itself is very much in need of some TLC.
This is quite insane
I cannot wait to read through this and apply it to my project; Too busy right now, but man oh man do I have something in store for my sunday night.
This is why I don't really add in diagonal movements. The amount of work it takes is insannnnnne.

Same for double tap to dash features.
Seems way more complicated then FA's lol.
Seems way more complicated then FA's lol.

Yeah. It is, which is why it's not getting the library treatment and not getting the go-ahead in any of my projects. This particular piece of code needs major revisions. I just thought the defines and macro definitions in particular might be of use to someone.