vqwerty.lua 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. -- vqwerty: a panel with virtual keyboard; injects keys into lovr event queue
  2. local chui = require'chui'
  3. local panel = chui.panel{
  4. palette = chui.palettes[9],
  5. }
  6. -- keyboard layout definition
  7. -- single-press special keys are in <>, long-hold special keys are in []
  8. local layout_text_str = [[
  9. <escape> <f1> <f2> <f3> <f4> <f5> <f6> <f7> <f8> <f9> <f10> <f11> <f12>
  10. ` 1 2 3 4 5 6 7 8 9 0 - = <backspace>
  11. <tab> q w e r t y u i o p [ ] \
  12. [capslock] a s d f g h j k l ; ' <enter>
  13. [lshift] z x c v b n m , . / [rshift]
  14. [lctrl] [lalt] space [ralt] [rctrl]
  15. ]]
  16. local layout_shift_str = [[
  17. <escape> <f1> <f2> <f3> <f4> <f5> <f6> <f7> <f8> <f9> <f10> <f11> <f12>
  18. ~ ! @ # $ % ^ & * ( ) _ + <backspace>
  19. <tab> Q W E R T Y U I O P < } |
  20. [capslock] A S D F G H J K L : " <enter>
  21. [lshift] Z X C V B N M < > ? [rshift]
  22. [lctrl] [lalt] space [ralt] [rctrl]
  23. ]]
  24. local function splitLayout(str)
  25. local tbl = {}
  26. local row = 1
  27. local col
  28. for row_str in str:gmatch('[^\r\n]+') do
  29. col = 1
  30. for key in row_str:gmatch('%S+') do
  31. tbl[row] = tbl[row] or {}
  32. tbl[row][col] = key
  33. col = col + 1
  34. end
  35. row = row + 1
  36. end
  37. return tbl
  38. end
  39. local layout_text = splitLayout(layout_text_str)
  40. local layout_shift = splitLayout(layout_shift_str)
  41. local modifiers = {
  42. ctrl = false, shift = false, alt = false, capslock = false
  43. }
  44. local function textinputCB(self)
  45. local text = self.data.text
  46. if modifiers.shift then
  47. text = self.data.shift
  48. elseif modifiers.capslock then
  49. text = text:upper()
  50. end
  51. lovr.event.push('textinput', text)
  52. lovr.event.push('keypressed', self.text)
  53. lovr.event.push('keyreleased', self.text)
  54. end
  55. local function keypressCB(self)
  56. lovr.event.push('keypressed', self.text)
  57. lovr.event.push('keyreleased', self.text)
  58. end
  59. local function toggleCB(self, state)
  60. -- remove l/r prefix of alt, shift, ctrl
  61. local modifier = self.text == 'capslock' and 'capslock' or self.text:sub(2, #self.text)
  62. modifiers[modifier] = state
  63. if state then
  64. lovr.event.push('keypressed', self.text)
  65. else
  66. lovr.event.push('keyreleased', self.text)
  67. end
  68. if modifier == 'shift' then -- update keyboard to alternative caps
  69. for _, widget in ipairs(panel.widgets) do
  70. widget.text = state and widget.data.shift or widget.data.text
  71. end
  72. end
  73. end
  74. -- roll out the keyboard keys from the layout definition
  75. for row = 1, #layout_text do
  76. for col = 1, #layout_text[row] do
  77. local text = layout_text[row][col]
  78. local shift = layout_shift[row][col]
  79. local btn
  80. if text:find('<%S+>') then -- special key like <esc>, send short press
  81. btn = panel:button{ text=text:sub(2, #text - 1), span=1.2, callback=keypressCB }
  82. shift = shift:sub(2, #text - 1)
  83. elseif text:find('%[%S+%]') then -- modifier keys like <lctrl>, toggle status
  84. btn = panel:toggle{ text=text:sub(2, #text - 1), span=2, callback=toggleCB }
  85. shift = shift:sub(2, #text - 1)
  86. elseif text == 'space' then -- space is a placeholder for ' '
  87. btn = panel:button{ text=' ', span=9, callback=textinputCB, thickness=0.2 }
  88. shift = ' '
  89. else -- normal letter-inserting button
  90. btn = panel:button{ text=text, span=1, callback=textinputCB }
  91. end
  92. -- the btn.data is unused in chui lib, we're free to use it for virutal keyboard
  93. btn.data = { text = btn.text, shift = shift }
  94. end
  95. if row < #layout_text then
  96. panel:row()
  97. end
  98. end
  99. panel:layout()
  100. return panel