From 59e791db82f1b590ca3554b9daf06bc10349a9bb Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 31 Jan 2016 14:56:05 -0800 Subject: [PATCH] feat: support numeric input for keyboard only devices --- base | 2 +- frontend/device/kindle/device.lua | 2 + frontend/device/kindle/keyboard_layout.lua | 14 ++ frontend/device/sdl/device.lua | 6 + frontend/device/sdl/keyboard_layout.lua | 14 ++ frontend/ui/widget/inputtext.lua | 40 +++-- frontend/ui/widget/physicalkeyboard.lua | 172 +++++++++++++++++++++ frontend/ui/widget/virtualkeyboard.lua | 4 +- 8 files changed, 235 insertions(+), 19 deletions(-) create mode 100644 frontend/device/kindle/keyboard_layout.lua create mode 100644 frontend/device/sdl/keyboard_layout.lua create mode 100644 frontend/ui/widget/physicalkeyboard.lua diff --git a/base b/base index e7c0c2fee..8b751543a 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit e7c0c2fee99e0162b568dec97a351e226697a4a2 +Subproject commit 8b751543a9292315fedc6d6e95fcf333bbd4f7e9 diff --git a/frontend/device/kindle/device.lua b/frontend/device/kindle/device.lua index 21009dbc5..6429c0928 100644 --- a/frontend/device/kindle/device.lua +++ b/frontend/device/kindle/device.lua @@ -108,6 +108,7 @@ function KindleDXG:init() device = self, event_map = require("device/kindle/event_map_keyboard"), } + self.keyboard_layout = require("device/kindle/keyboard_layout") self.input.open("/dev/input/event0") self.input.open("/dev/input/event1") Kindle.init(self) @@ -124,6 +125,7 @@ function Kindle3:init() device = self, event_map = require("device/kindle/event_map_keyboard"), } + self.keyboard_layout = require("device/kindle/keyboard_layout") self.input.open("/dev/input/event0") self.input.open("/dev/input/event1") Kindle.init(self) diff --git a/frontend/device/kindle/keyboard_layout.lua b/frontend/device/kindle/keyboard_layout.lua new file mode 100644 index 000000000..f0931bbd4 --- /dev/null +++ b/frontend/device/kindle/keyboard_layout.lua @@ -0,0 +1,14 @@ +return { + [1] = { + "Q", "W", "E", "R", "T", "Y", "U", "I", "Q", "P", + }, + [2] = { + "A", "S", "D", "F", "G", "H", "J", "K", "L", "Del", + }, + [3] = { + "Z", "X", "C", "V", "B", "N", "M", ".", "Sym", "Enter", + }, + [4] = { + "Sym", "Alt", "space", "Aa", "Home", "Back", + }, +} diff --git a/frontend/device/sdl/device.lua b/frontend/device/sdl/device.lua index e924ea519..93bb5ec9a 100644 --- a/frontend/device/sdl/device.lua +++ b/frontend/device/sdl/device.lua @@ -16,6 +16,10 @@ local Device = Generic:new{ needsScreenRefreshAfterResume = no, } +if os.getenv("DISABLE_TOUCH") == "1" then + Device.isTouchDevice = no +end + function Device:init() -- allows to set a viewport via environment variable -- syntax is Lua table syntax, e.g. EMULATE_READER_VIEWPORT="{x=10,w=550,y=5,h=790}" @@ -42,6 +46,8 @@ function Device:init() } end + self.keyboard_layout = require("device/sdl/keyboard_layout") + if portrait then self.input:registerEventAdjustHook(self.input.adjustTouchSwitchXY) self.input:registerEventAdjustHook( diff --git a/frontend/device/sdl/keyboard_layout.lua b/frontend/device/sdl/keyboard_layout.lua new file mode 100644 index 000000000..c6ae47a87 --- /dev/null +++ b/frontend/device/sdl/keyboard_layout.lua @@ -0,0 +1,14 @@ +return { + [1] = { + "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", + }, + [2] = { + "A", "S", "D", "F", "G", "H", "J", "K", "L", "Del", + }, + [3] = { + "Z", "X", "C", "V", "B", "N", "M", ".", "Sym", "Enter", + }, + [4] = { + "Sym", "Alt", "space", "Aa", "Home", "Back", + }, +} diff --git a/frontend/ui/widget/inputtext.lua b/frontend/ui/widget/inputtext.lua index bc01827a7..7008c25ca 100644 --- a/frontend/ui/widget/inputtext.lua +++ b/frontend/ui/widget/inputtext.lua @@ -1,15 +1,15 @@ local InputContainer = require("ui/widget/container/inputcontainer") +local FrameContainer = require("ui/widget/container/framecontainer") local ScrollTextWidget = require("ui/widget/scrolltextwidget") local TextBoxWidget = require("ui/widget/textboxwidget") -local FrameContainer = require("ui/widget/container/framecontainer") -local VirtualKeyboard = require("ui/widget/virtualkeyboard") local GestureRange = require("ui/gesturerange") +local Blitbuffer = require("ffi/blitbuffer") local UIManager = require("ui/uimanager") local Device = require("device") -local Screen = require("device").screen +local Screen = Device.screen local Font = require("ui/font") local util = require("ffi/util") -local Blitbuffer = require("ffi/blitbuffer") +local Keyboard local InputText = InputContainer:new{ text = "", @@ -32,10 +32,10 @@ local InputText = InputContainer:new{ focused = true, } -function InputText:init() - self:initTextBox(self.text) - self:initKeyboard() - if Device:isTouchDevice() then +-- only use PhysicalKeyboard if the device does not have touch screen +if Device.isTouchDevice() then + Keyboard = require("ui/widget/virtualkeyboard") + function InputText:initEventListener() self.ges_events = { TapTextBox = { GestureRange:new{ @@ -45,6 +45,21 @@ function InputText:init() } } end + + function InputText:onTapTextBox() + if self.parent.onSwitchFocus then + self.parent:onSwitchFocus(self) + end + end +else + Keyboard = require("ui/widget/physicalkeyboard") + function InputText:initEventListener() end +end + +function InputText:init() + self:initTextBox(self.text) + self:initKeyboard() + self:initEventListener() end function InputText:initTextBox(text) @@ -112,20 +127,13 @@ function InputText:initKeyboard() if self.input_type == "number" then keyboard_layout = 3 end - self.keyboard = VirtualKeyboard:new{ + self.keyboard = Keyboard:new{ layout = keyboard_layout, inputbox = self, width = Screen:getWidth(), - height = math.max(Screen:getWidth(), Screen:getHeight())*0.33, } end -function InputText:onTapTextBox() - if self.parent.onSwitchFocus then - self.parent:onSwitchFocus(self) - end -end - function InputText:unfocus() self.focused = false self[1].color = Blitbuffer.gray(0.5) diff --git a/frontend/ui/widget/physicalkeyboard.lua b/frontend/ui/widget/physicalkeyboard.lua new file mode 100644 index 000000000..a3ea05772 --- /dev/null +++ b/frontend/ui/widget/physicalkeyboard.lua @@ -0,0 +1,172 @@ +local CenterContainer = require("ui/widget/container/centercontainer") +local BottomContainer = require("ui/widget/container/bottomcontainer") +local TopContainer = require("ui/widget/container/topcontainer") +local WidgetContainer = require("ui/widget/container/widgetcontainer") +local InputContainer = require("ui/widget/container/inputcontainer") +local FrameContainer = require("ui/widget/container/framecontainer") +local HorizontalGroup = require("ui/widget/horizontalgroup") +local HorizontalSpan = require("ui/widget/horizontalspan") +local VerticalGroup = require("ui/widget/verticalgroup") +local TextWidget = require("ui/widget/textwidget") +local Blitbuffer = require("ffi/blitbuffer") +local Device = require("device") +local Font = require("ui/font") +local Screen = Device.screen +local Geom = require("ui/geometry") +local util = require("util") +local DEBUG = require("dbg") + + +local PhysicalNumericKey = WidgetContainer:new{ + key = nil, + label = nil, + physical_key_label = nil, + + keyboard = nil, + callback = nil, + mapping = nil, + + width = nil, + height = nil, + bordersize = 2, + face = Font:getFace("infont", 22), + pkey_face = Font:getFace("infont", 14), +} + +function PhysicalNumericKey:init() + local label_widget = TextWidget:new{ + text = self.label, + face = self.face, + } + self[1] = FrameContainer:new{ + margin = 0, + bordersize = self.bordersize, + background = Blitbuffer.COLOR_WHITE, + radius = 5, + padding = 0, + CenterContainer:new{ + dimen = Geom:new{ + w = self.width - 2*self.bordersize, + h = self.height - 2*self.bordersize, + }, + VerticalGroup:new{ + label_widget, + TextWidget:new{ + fgcolor = Blitbuffer.COLOR_GREY, + text = self.physical_key_label, + face = self.pkey_face, + }, + } + }, + } + self.dimen = Geom:new{ + w = self.width, + h = self.height, + } +end + +-- start of PhysicalKeyboard + +local PhysicalKeyboard = InputContainer:new{ + is_always_active = true, + inputbox = nil, -- expect ui/widget/inputtext instance + bordersize = 2, + padding = 2, + height = math.max(Screen:getWidth(), Screen:getHeight())*0.33, + key_padding = Screen:scaleBySize(6), +} + +function PhysicalKeyboard:init() + local all_keys = {} + for _,row in ipairs(Device.keyboard_layout) do + util.arrayAppend(all_keys, row) + end + self.key_events = { + KeyPress = { { all_keys }, } + } + + self.dimen = Geom:new{ w = 0, h = 0 } + + self:setType(self.inputbox.input_type) +end + +function PhysicalKeyboard:setType(t) + if t == "number" then + self.mapping = { + {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"} + } + self.key_transformer = {} + for i,row in ipairs(self.mapping) do + for j,key in ipairs(row) do + local pkey = Device.keyboard_layout[i][j] + self.key_transformer[pkey] = self.mapping[i][j] + end + end + self:setupNumericMappingUI() + else + -- default mapping + self.mapping = Device.keyboard_layout + end +end + +function PhysicalKeyboard:onKeyPress(ev) + local key = ev.key + if key == "Back" then + DEBUG("TODO: exit keyboard") + elseif key == "Del" then + self.inputbox:delChar() + else + if self.key_transformer then + key = self.key_transformer[key] + end + self.inputbox:addChar(key) + end +end + +function PhysicalKeyboard:setupNumericMappingUI() + local key_rows = VerticalGroup:new{} + local key_margin = 1 + local row_len = #self.mapping[1] + local base_key_width = math.floor((self.width - row_len*(self.key_padding+2*key_margin) - 2*self.padding)/10) + local base_key_height = math.floor((self.height - self.key_padding - 2*self.padding)/4) + local key_width = math.floor(base_key_width + self.key_padding) + + for i, kb_row in ipairs(self.mapping) do + local row = HorizontalGroup:new{} + for j, key in ipairs(kb_row) do + if j > 1 then + table.insert(row, HorizontalSpan:new{width=key_margin*2}) + end + table.insert(row, PhysicalNumericKey:new{ + label = key, + physical_key_label = Device.keyboard_layout[i][j], + width = key_width, + height = base_key_height, + }) + end + table.insert(key_rows, row) + end + + local keyboard_frame = FrameContainer:new{ + margin = 0, + bordersize = 0, + radius = 0, + padding = self.padding, + TopContainer:new{ + dimen = Geom:new{ + w = self.width - 2*self.bordersize -2*self.padding, + h = self.height - 2*self.bordersize -2*self.padding, + }, + key_rows, + } + } + + self[1] = BottomContainer:new{ + dimen = Screen:getSize(), + keyboard_frame, + } + + self.dimen = keyboard_frame:getSize() +end + +return PhysicalKeyboard diff --git a/frontend/ui/widget/virtualkeyboard.lua b/frontend/ui/widget/virtualkeyboard.lua index ca08c3397..0dccc69f5 100644 --- a/frontend/ui/widget/virtualkeyboard.lua +++ b/frontend/ui/widget/virtualkeyboard.lua @@ -10,8 +10,8 @@ local ImageWidget = require("ui/widget/imagewidget") local TextWidget = require("ui/widget/textwidget") local Font = require("ui/font") local Geom = require("ui/geometry") -local Screen = require("device").screen local Device = require("device") +local Screen = Device.screen local GestureRange = require("ui/gesturerange") local UIManager = require("ui/uimanager") local DEBUG = require("dbg") @@ -26,7 +26,7 @@ local VirtualKey = InputContainer:new{ callback = nil, width = nil, - height = nil, + height = math.max(Screen:getWidth(), Screen:getHeight())*0.33, bordersize = 2, face = Font:getFace("infont", 22), }