-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlinuxfix.lua
More file actions
142 lines (127 loc) · 6.93 KB
/
Copy pathlinuxfix.lua
File metadata and controls
142 lines (127 loc) · 6.93 KB
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
70
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
_addon.name = 'linuxfix'
_addon.version = '0.5.0'
_addon.author = 'Rubenator,Surik,BeYoNDLiFe'
--[[
Do not bother using this if you are on Windows.
This addon will need to be autoloaded via your init.
This code has only been tested with fairly standard en-US keyboards.
This addon restores full keyboard functionality in Windower with newer versions of Wine and bypasses the need to build your own version of Wine with a specific commit reverted.
It also remaps Windows key bindings and makes them functional again with the exception of bindings with multiple modifiers such as %^!1 (Ctrl+Super+Alt+1). The listbinds command is only capable of returning a single modifier and thus they cannot be remapped correctly.
It reads and parses the content of the 'listbinds' command anytime it runs and forwards the keys as appropriate to the client. It also hides the output of this command to avoid console spam.
It's not a fix since it doesn't actually repair the original issue of the keybinds using raw keyboard input but it does work nicely as a workaround.
When there are a left and right version of a key such as lctrl and rctrl windower sends the lctrl dik even when the right key has been pressed. This also applies to enter and numpadenter.
While the correct keys are in the table below, windower will just use the left version.
For lack of a better method of keeping the keybinds up to date, the list is refreshed every time you press a key. This was done because Gearswap files frequently rebind keys between jobs.
Since this caused significant lag, a limit was placed so it could not run more than once per second. This limit can be modified using the 'check_rate' variable.
The binds are also now added to a table and don't have to be parsed everytime you press a key which has reduced overhead as well.
Big shoutout and thanks to Rubenator, he took the awful code Surik and BeYoNDLiFe gave him and made it so much better.
]]--
check_rate = 1
require('luau')
mods = S{}
keybinds = {}
last_state = T{}
local dik_lookup = T{[-1]='sysrq', [1]='escape', [2]='1', [3]='2', [4]='3', [5]='4', [6]='5', [7]='6', [8]='7', [9]='8', [10]='9', [11]='0', [12]='-', [13]='=', [14]='backspace', [15]='tab', [16]='q', [17]='w', [18]='e', [19]='r', [20]='t', [21]='y', [22]='u', [23]='i', [24]='o', [25]='p', [26]='[', [27]=']', [28]='enter', [30]='a', [31]='s', [32]='d', [33]='f', [34]='g', [35]='h', [36]='j', [37]='k', [38]='l', [39]="\\;", [40]="'", [41]='`', [43]='\\\\', [44]='z', [45]='x', [46]='c', [47]='v', [48]='b', [49]='n', [50]='m', [51]=',', [52]='.', [53]='/', [54]='rshift', [55]='numpad*', [57]='space', [58]='capslock', [59]='f1', [60]='f2', [61]='f3', [62]='f4', [63]='f5', [64]='f6', [65]='f7', [66]='f8', [67]='f9', [68]='f10', [69]='numlock', [70]='scrolllock', [71]='numpad7', [72]='numpad8', [73]='numpad9', [74]='numpad-', [75]='numpad4', [76]='numpad5', [77]='numpad6', [78]='numpad+', [79]='numpad1', [80]='numpad2', [81]='numpad3', [82]='numpad0', [83]='numpad.', [86]='oem_102', [87]='f11', [88]='f12', [100]='f13', [101]='f14', [102]='f15', [112]='kana', [115]='abnt_c1', [121]='convert', [123]='noconvert', [125]='yen', [126]='abnt_c2', [141]='numpadequals', [145]='at', [146]='colon', [147]='underline', [148]='kanji', [149]='stop', [150]='ax', [151]='unlabeled', [153]='nexttrack', [156]='numpadenter', [157]='rctrl', [160]='mute', [161]='calculator', [162]='playpause', [164]='mediastop', [174]='volumedown', [176]='volumeup', [178]='webhome', [179]='numpadcomma', [181]='numpad/', [183]='sysrq', [184]='rmenu', [197]='pause', [199]='home', [200]='up', [201]='pageup', [203]='left', [205]='right', [207]='end', [208]='down', [209]='pagedown', [210]='insert', [211]='delete', [220]='rwin', [222]='power', [223]='sleep', [227]='wake', [229]='websearch', [230]='webfavorites', [231]='webrefresh', [232]='webstop', [233]='', [234]='webback', [235]='mycomputer', [236]='mail', [237]='mediaselect'}
local mod_lookup = T{[29]='Ctrl', [42]='Shift', [56]='Alt', [219]='Windows', [221]='Apps'}
key_lookup = T{}
name_lookup = T{}
last_update = nil
do
key_lookup:update(dik_lookup:map(function(name) return {name=name} end))
key_lookup:update(mod_lookup:map(function(name) return {name=name, mod=true} end))
for dik, data in pairs(key_lookup) do
name_lookup[data.name] = {mod=data.mod, dik=dik}
end
end
windower.register_event('keyboard',function(dik,pressed)
if pressed == last_state[dik] then return end
last_state[dik] = pressed
local key_data = key_lookup[dik]
if not key_data then return end
if key_data.mod then
if pressed then
mods:add(key_data.name)
else
mods:remove(key_data.name)
end
send_key_state(key_data, pressed)
elseif pressed then
if not last_update or os.clock() - last_update > check_rate then
windower.send_command('listbinds')
end
local command = check_bind(key_data)
if command then
windower.send_command(command)
else
send_key_state(key_data, pressed)
end
else
send_key_state(key_data, pressed)
end
end)
function check_bind(key_data)
local binds = keybinds[key_data.name]
if not binds then return false end
local info = windower.ffxi.get_info()
local chat_open = info and info.chat_open
--if chat_open == nil then return false end
binds = binds:filter(function(bind)
return (bind.chat_state == nil or chat_open and bind.chat_state == 'ChatOnly' or not chat_open) and (bind.mods:length() == bind.mods:intersection(mods):length())
end)
local number_of_binds = binds:length()
if number_of_binds == 0 then
return false
else
return binds:first().command
end
end
function send_key_state(key_data, pressed)
windower.send_command('setkey %s %s':format(key_data.name, pressed and "down" or "up"))
end
windower.register_event('incoming text', function(original, modified, color, color_m, blocked)
if color ~= 141 then return end
if ListBinds then
if original == '===== Done Listing Currently Bound Keys =====' then
ListBinds = false
for _,binds in pairs(new_keybinds) do
binds:sort(function(a,b) return a.mods:length() > b.mods:length() end)
end
keybinds = new_keybinds
else
add_bind(original)
end
return true
elseif original == '===== Listing Currently Bound Keys =====' then
last_update = os.clock()
new_keybinds = {}
ListBinds = true
return true
end
end)
local chat_states = {['(NoChat)']='NoChat', ['(ChatOnly)']='ChatOnly'}
function add_bind(original)
local bind, command = original:match('^([^:]*): (.*)$')
bind = bind:gsub('^%-', 'minus'):gsub('%-%-', '-minus')
parts = bind:split('-'):map(string.gsub-{'minus', '-'})
local chat_state, key
local mods = S{}
for _,part in pairs(parts) do
if chat_states[part] then
chat_state = chat_states[part]
elseif part ~= '' then
local key_data = name_lookup[part]
if key_data then
if key_data.mod then
mods:add(part)
else
key = part
end
end
end
end
if not new_keybinds[key] then
new_keybinds[key] = L{}
end
new_keybinds[key]:append({key=key, mods=mods, chat_state=chat_state, command=command})
end
windower.send_command('listbinds')