Hi again,
I have made my first attempted changes to the AutoSkin applet to try to make it respond to keyboard (ir-keytable) KEY_UP, KEY_DOWN, KEY_RIGHT and KEY_PLAY events.
I have no coding experience, so apologies in advance if answers should be very obvious!
My first problem is identifying a jive/ui/Framework function that returns a key name (similar to getIRCodes for arrow_up, arrow_down, arrow_right and play remote button presses).
I tried getAction, as it looked like it should return Keycode for key press actions:
but I was wrong as the log shows:Code:function getAction(self, event) local eventType = event:getType() local action = nil if eventType == jive.ui.EVENT_KEY_PRESS then action = self.inputToActionMap.keyActionMappings.press[event:getKeycode()] elseif eventType == jive.ui.EVENT_GESTURE then action = self.inputToActionMap.gestureActionMappings[event:getGesture()] elseif eventType == jive.ui.EVENT_KEY_HOLD then action = self.inputToActionMap.keyActionMappings.hold[event:getKeycode()] elseif eventType == jive.ui.EVENT_CHAR_PRESS then action = self.inputToActionMap.charActionMappings.press[string.char(event:getUnicode())] elseif eventType == jive.ui.EVENT_IR_PRESS then action = inputToActionMap.irActionMappings.press[self:getIRButtonName(event:getIRCode())] elseif eventType == jive.ui.EVENT_IR_HOLD then action = inputToActionMap.irActionMappings.hold[self:getIRButtonName(event:getIRCode())] end return action end
tail -f /var/log/jivelite.log
20210103 15:19:51.416 DEBUG jivelite.ui - Widget.lua:437 Creating widget action listener for action: (go_home) from source: [...pplets/ChooseMusicSource/ChooseMusicSourceApplet.lua]:767
20210103 15:19:51.416 DEBUG jivelite.ui - Widget.lua:437 Creating widget action listener for action: (go) from source: [/opt/jivelite/share/jive/jive/ui/Slider.lua]:108
20210103 15:19:51.416 DEBUG jivelite.ui - Widget.lua:437 Creating widget action listener for action: (play) from source: [/opt/jivelite/share/jive/jive/ui/Slider.lua]:109
20210103 15:19:51.416 DEBUG jivelite.ui - Widget.lua:437 Creating widget action listener for action: (page_up) from source: [/opt/jivelite/share/jive/jive/ui/Textarea.lua]:129
20210103 15:19:51.416 DEBUG jivelite.ui - Widget.lua:437 Creating widget action listener for action: (page_down) from source: [/opt/jivelite/share/jive/jive/ui/Textarea.lua]:130
20210103 15:19:51.416 DEBUG jivelite.ui - Framework.lua:780 Translated action title_left_press to back
20210103 15:19:51.417 DEBUG jivelite.ui - Framework.lua:780 Translated action title_right_press to go_now_playing
Can anyone suggest where I should find the function that returns key press events?
Here's the complete code for the first draft of the revised applet:
I also tried consuming from event.lua directly like so:Code:--[[ =head1 NAME applets.AutoSkin.AutoSkinApplet - An applet to select different SqueezePlay skins =head1 DESCRIPTION This applet allows the SqueezePlay skin to be selected. =head1 FUNCTIONS Applet related methods are described in L<jive.Applet>. AutoSkinApplet overrides the following methods: =cut --]] local ipairs, pairs = ipairs, pairs local oo = require("loop.simple") local Applet = require("jive.Applet") local Framework = require("jive.ui.Framework") local Surface = require("jive.ui.Surface") local jiveMain = jiveMain local appletManager = appletManager local debug = require("jive.utils.debug") module(..., Framework.constants) oo.class(_M, Applet) --service method function getActiveSkinType(self) return self.mode end function init(self, ...) -- skins, could be configurable via settings local touchSkin = "touch" local remoteSkin = "remote" --temp workaround, until it is resolved how to avoid self.mode being null on startup --if not self.mode then -- self.mode = nil --end if not self.irBlacklist then self.irBlacklist = {} -- see jive.irMap_default for defined buttons for x, button in ipairs({ "arrow_up", "arrow_down", -- "arrow_left", "arrow_right", "play", -- "add", -- "now_playing", }) do local irCodes = Framework:getIRCodes(button) for name, irCode in pairs(irCodes) do self.irBlacklist[irCode] = button end end end local eatIREvents = false if not self.keyBlacklist then self.keyBlacklist = {} -- see share/jive/jive/ui/Textinput.lua for defined keys for x, key in ipairs({ "KEY_UP", "KEY_DOWN", -- "KEY_LEFT", "KEY_RIGHT", "KEY_PLAY", }) do local keyCodes = Framework:getAction(key) for name, keyCode in pairs(keyCodes) do self.keyBlacklist[keyCode] = key end end end local eatKEYEvents = false Framework:addListener(EVENT_IR_ALL, function(event) -- ignore initial keypress after switching from touch to IR control if eatIREvents then if event:getType() == EVENT_IR_UP then eatIREvents = false end return EVENT_CONSUME elseif self:changeSkin(remoteSkin) and self.irBlacklist[event:getIRCode()] ~= nil then log:warn("ignore me - key " .. self.irBlacklist[event:getIRCode()] .. " is context sensitive") eatIREvents = true return EVENT_CONSUME end return EVENT_UNUSED end, -100) Framework:addListener(EVENT_KEY_ALL, function(event) -- ignore initial keypress after switching from touch to KEY control if eatKEYEvents then if event:getType() == EVENT_KEY_UP then eatKEYEvents = false end return EVENT_CONSUME elseif self:changeSkin(remoteSkin) and self.keyBlacklist[event:getKeycode()] ~= nil then log:warn("ignore me - key " .. self.keyBlacklist[event:getKeycode()] .. " is context sensitive") eatKEYEvents = true return EVENT_CONSUME end return EVENT_UNUSED end, -100) Framework:addListener(EVENT_MOUSE_ALL, function(event) -- ignore event when switching from remote to touch: we don't know what we're touching -- wake up if in screensaver mode - this is a non critical action if self:changeSkin(touchSkin) and not appletManager:callService("isScreensaverActive") then log:warn("ignore me - I don't know what I'm touching!") return EVENT_CONSUME end return EVENT_UNUSED end, -100) return self end function changeSkin(self, skinType) if self.mode == skinType then return false end local skinName = appletManager:callService("getSelectedSkinNameForType", skinType) if jiveMain:getSelectedSkin() == skinName then self.mode = skinType -- needed for inital setting of mode at start. log:debug("skin already selected, not switching: ", skinName) return false end log:info(self,":changeSkin ",skinName,":",skinType) local img1 = _capture("foo") self.mode = skinType jiveMain:setSelectedSkin(skinName) local img2 = _capture("bar") Framework:_startTransition(self._transitionFadeIn(img1, img2)) return true end function _capture(name) local sw, sh = Framework:getScreenSize() local img = Surface:newRGB(sw, sh) Framework:draw(img) return img end function _transitionFadeIn(oldImage, newImage) -- use a fast transition local startT local transitionDuration = 100 local remaining = transitionDuration local sw, sh = Framework:getScreenSize() local scale = (transitionDuration * transitionDuration * transitionDuration) / sw local animationCount = 0 local scale = 255 / transitionDuration return function(widget, surface) if animationCount == 0 then --getting start time on first loop avoids initial delay that can occur startT = Framework:getTicks() end local x = remaining * scale newImage:blit(surface, 0, 0) oldImage:blitAlpha(surface, 0, 0, x) local elapsed = Framework:getTicks() - startT remaining = transitionDuration - elapsed if remaining <= 0 then Framework:_killTransition() end animationCount = animationCount + 1 end end --[[ =head1 LICENSE Copyright 2010 Logitech. All Rights Reserved. This file is licensed under BSD. Please see the LICENSE file for details. =cut --]]
Code:-- local keyCodes = Framework:getAction(key) -- -- for name, keyCode in pairs(keyCodes) do -- self.keyBlacklist[keyCode] = key local keyCode = Event:getKeycode(key) for name, keyCode do self.keyBlacklist[keyCode] = key end end end
BR.
Results 51 to 55 of 55
Thread: JiveLite
-
2021-01-03, 08:38 #51
- Join Date
- Sep 2015
- Posts
- 218
attempted changes to AutoSkin applet
Last edited by Learnincurve; 2021-01-03 at 09:21.
-
2021-01-04, 07:40 #52
- Join Date
- Sep 2015
- Posts
- 218
Update: Applet now loading.
I saw some basic coding errors in yesterday's attempt and tried a really simple version with extra debug logging and a key listener based on the mouse listener, to avoid all the IR related code:
Code:--[[ =head1 NAME applets.AutoSkin.AutoSkinApplet - An applet to select different SqueezePlay skins =head1 DESCRIPTION This applet allows the SqueezePlay skin to be selected. =head1 FUNCTIONS Applet related methods are described in L<jive.Applet>. AutoSkinApplet overrides the following methods: =cut --]] local ipairs, pairs = ipairs, pairs local oo = require("loop.simple") local Applet = require("jive.Applet") local Framework = require("jive.ui.Framework") local Surface = require("jive.ui.Surface") local jiveMain = jiveMain local appletManager = appletManager local debug = require("jive.utils.debug") module(..., Framework.constants) oo.class(_M, Applet) --service method function getActiveSkinType(self) return self.mode end function init(self, ...) -- skins, could be configurable via settings local touchSkin = "touch" local remoteSkin = "remote" local eatKEYEvents = false --temp workaround, until it is resolved how to avoid self.mode being null on startup --if not self.mode then -- Shouldn't be necessary if we look for any key event to trigger the "remote" skin. Looks like irBlacklist is empty by default --end -- -- if not self.irBlacklist then -- self.irBlacklist = {} -- -- -- see jive.irMap_default for defined buttons -- for x, button in ipairs({ -- "arrow_up", -- "arrow_down", -- -- "arrow_left", -- "arrow_right", -- "play", -- -- "add", -- -- "now_playing", -- }) do -- local irCodes = Framework:getIRCodes(button) -- -- for name, irCode in pairs(irCodes) do -- self.irBlacklist[irCode] = button -- end -- end -- -- end -- -- local eatIREvents = false -- Framework:addListener(EVENT_IR_ALL, -- function(event) -- -- ignore initial keypress after switching from touch to IR control -- if eatIREvents then -- -- if event:getType() == EVENT_IR_UP then -- eatIREvents = false -- end -- return EVENT_CONSUME -- -- elseif self:changeSkin(remoteSkin) and self.irBlacklist[event:getIRCode()] ~= nil then -- -- log:warn("ignore me - key " .. self.irBlacklist[event:getIRCode()] .. " is context sensitive") -- eatIREvents = true -- return EVENT_CONSUME -- -- end -- -- return EVENT_UNUSED -- end, -- -100) -- log:debug("Initiating AutoSkin applet") Framework:addListener(EVENT_KEY_ALL, function(event) -- ignore initial keypress after switching from touch to KEY control log:debug("Key event listener starting") if eatKEYEvents then log:debug("Key event detected") if event:getType() == EVENT_KEY_UP then eatKEYEvents = false log:debug("EVENT_KEY_UP event detected") end return EVENT_CONSUME -- wake up if in screensaver mode - this is a non critical action if self:changeSkin(remoteSkin) and not appletManager:callService("isScreensaverActive") then log:warn("ignore me - I'm just waking up!") eatKEYEvents = true return EVENT_CONSUME end end return EVENT_UNUSED end, -100) --Base the key listener on the mouse/(touch) listener for now Framework:addListener(EVENT_MOUSE_ALL, function(event) -- ignore event when switching from remote to touch: we don't know what we're touching -- wake up if in screensaver mode - this is a non critical action log:debug("Mouse/Touch event detected") if self:changeSkin(touchSkin) and not appletManager:callService("isScreensaverActive") then log:warn("ignore me - I don't know what I'm touching!") return EVENT_CONSUME end return EVENT_UNUSED end, -100) return self end function changeSkin(self, skinType) if self.mode == skinType then return false end local skinName = appletManager:callService("getSelectedSkinNameForType", skinType) if jiveMain:getSelectedSkin() == skinName then self.mode = skinType -- needed for inital setting of mode at start. log:debug("skin already selected, not switching: ", skinName) return false end log:info(self,":changeSkin ",skinName,":",skinType) local img1 = _capture("foo") self.mode = skinType jiveMain:setSelectedSkin(skinName) local img2 = _capture("bar") Framework:_startTransition(self._transitionFadeIn(img1, img2)) return true end function _capture(name) local sw, sh = Framework:getScreenSize() local img = Surface:newRGB(sw, sh) Framework:draw(img) return img end function _transitionFadeIn(oldImage, newImage) -- use a fast transition local startT local transitionDuration = 100 local remaining = transitionDuration local sw, sh = Framework:getScreenSize() local scale = (transitionDuration * transitionDuration * transitionDuration) / sw local animationCount = 0 local scale = 255 / transitionDuration return function(widget, surface) if animationCount == 0 then --getting start time on first loop avoids initial delay that can occur startT = Framework:getTicks() end local x = remaining * scale newImage:blit(surface, 0, 0) oldImage:blitAlpha(surface, 0, 0, x) local elapsed = Framework:getTicks() - startT remaining = transitionDuration - elapsed if remaining <= 0 then Framework:_killTransition() end animationCount = animationCount + 1 end end --[[ =head1 LICENSE Copyright 2010 Logitech. All Rights Reserved. This file is licensed under BSD. Please see the LICENSE file for details. =cut --]]
1. First keystroke loads new skin over screensaver (clock). Should be ignored f screensaver is active?
2. There should be a timer to revert to the touch skin after a given # of seconds?
3. After a few keystrokes (not yet sure how many, the listener seems to crash, so that further keystrokes are not detected.
I'll continue to fumble around, but if anyone has any tips...Last edited by Learnincurve; 2021-01-05 at 03:00.
-
2021-01-26, 04:07 #53
- Join Date
- Sep 2015
- Posts
- 218
Fumbling produced the following small step closer:
Here's the key listener code as it stands, including a simple timer, lifted from the screensaver applet:
Code:31 --Timer declaration: 32 local Timer = require("jive.ui.Timer") ... ... 101 102 Framework:addListener(EVENT_KEY_ALL, 103 -- We don't want double events, so only respond when key is pressed 104 105 function(event) 106 -- ignore initial keypress after switching from touch to KEY control. eatKEYEvents initally set FALSE, jumping first if 107 log:debug("Key event listener starting") 108 if eatKEYEvents then 109 log:debug("Key event detected") 110 111 --jump out again if this is an UP event, we only want to respond once to each keypress 112 if event:getType() == EVENT_KEY_UP then 113 eatKEYEvents = false 114 log:debug("EVENT_KEY_UP event detected. ignoring as we only want DOWN's") 115 end 116 --if eatKEYEVENTS is TRUE and this is a DOWN event, we consume the event, leaving nothing. So don't act on this keypress. 117 log:debug("key DOWN detected and eatKEYEvents is set. If we consume this no action is performed ") 118 -- return EVENT_CONSUME 119 120 elseif self:changeSkin(remoteSkin) and not appletManager:callService("isScreensaverActive") then 121 log:debug("no screensaver, accepting key event") 122 eatKEYEvents = true 123 -- return EVENT_UNUSED 124 --Experimental Timer code from here 125 self.timer = Timer(6000, function() self:changeSkin(touchSkin) end, true) 126 log:debug("starting timer") 127 self.timer:start() 128 129 -- -- listener to restart skin-switcher timer 130 Framework:addListener(bit.bor(ACTION, EVENT_KEY_ALL), 131 function(event) 132 -- restart timer if it is running 133 log:debug("another key event detected - resetting timer") 134 self.timer:setInterval(6000) 135 return EVENT_UNUSED 136 end, 137 true 138 ) 139 --To here 140 end 141 142 log:debug("screensaver active, ignoring key event") 143 return EVENT_UNUSED 144 end, 145 -100) 146
If the screensaver is running, the initial keypress only wakes from screensaver, leaving the skin unchanged.
If on the main home screen, arrow keys navigate within the loaded skin, but don't change it (not sure why this is happening, but can live with it).
First "Go" event seems to trigger the skin change. The timer runs (currently set to 6 seconds)
The timer is NOT resetting/restarting with multiple events, so, after six seconds the touch skin is reloaded. I'll need to do some more fumbling around with the following
Code:-- -- listener to restart skin-switcher timer 130 Framework:addListener(bit.bor(ACTION, EVENT_KEY_ALL), 131 function(event) 132 -- restart timer if it is running 133 log:debug("another key event detected - resetting timer") 134 self.timer:setInterval(6000) 135 return EVENT_UNUSED
Simple questions: If I move the single line self.timer:setInterval(6000) to above line 125, does that reset the running timer if there is one and ignore if there isn't, or do I need to explicitly check for a running timer first (if so, how)? Does it need to run from within function(event)
BR.Last edited by Learnincurve; 2021-01-26 at 06:26.
-
2021-01-30, 03:54 #54
- Join Date
- Sep 2015
- Posts
- 218
Almost there now
I'm very close to making this work now. Here's the uncleaned code so far:
Code:--[[ =head1 NAME applets.AutoSkin.AutoSkinApplet - An applet to select different SqueezePlay skins =head1 DESCRIPTION This applet allows the SqueezePlay skin to be selected. =head1 FUNCTIONS Applet related methods are described in L<jive.Applet>. AutoSkinApplet overrides the following methods: =cut --]] local ipairs, pairs = ipairs, pairs local oo = require("loop.simple") local Applet = require("jive.Applet") local Framework = require("jive.ui.Framework") local Surface = require("jive.ui.Surface") local jiveMain = jiveMain local appletManager = appletManager local debug = require("jive.utils.debug") --Timer declaration added by Marius local Timer = require("jive.ui.Timer") local interval = 6000 module(..., Framework.constants) oo.class(_M, Applet) --service method function getActiveSkinType(self) return self.mode end function init(self, ...) -- skins, could be configurable via settings local touchSkin = "touch" local remoteSkin = "remote" local eatKEYEvents = "false" --initiate the timer self.timer = Timer(interval, function() self:changeSkin(touchSkin) end, true) --temp workaround, until it is resolved how to avoid self.mode being null on startup --if not self.mode then -- Shouldn't be necessary if we look for any key event to trigger the "remote" skin. Looks like irBlacklist is empty by default --end -- -- if not self.irBlacklist then -- self.irBlacklist = {} -- -- -- see jive.irMap_default for defined buttons -- for x, button in ipairs({ -- "arrow_up", -- "arrow_down", -- -- "arrow_left", -- "arrow_right", -- "play", -- -- "add", -- -- "now_playing", -- }) do -- local irCodes = Framework:getIRCodes(button) -- -- for name, irCode in pairs(irCodes) do -- self.irBlacklist[irCode] = button -- end -- end -- -- end -- -- local eatIREvents = false -- Framework:addListener(EVENT_IR_ALL, -- function(event) -- -- ignore initial keypress after switching from touch to IR control -- if eatIREvents then -- -- if event:getType() == EVENT_IR_UP then -- eatIREvents = false -- end -- return EVENT_CONSUME -- -- elseif self:changeSkin(remoteSkin) and self.irBlacklist[event:getIRCode()] ~= nil then -- -- log:warn("ignore me - key " .. self.irBlacklist[event:getIRCode()] .. " is context sensitive") -- eatIREvents = true -- return EVENT_CONSUME -- -- end -- -- return EVENT_UNUSED -- end, -- -100) -- log:debug("Initiating AutoSkin applet") Framework:addListener(EVENT_KEY_ALL, -- We don't want double events, so only respond when key is pressed function(event) -- ignore initial keypress after switching from touch to KEY control. eatKEYEvents initally set FALSE, jumping first if log:debug("Key event detected") --reset the timer whenever any key is pressed self.timer:setInterval(interval) if eatKEYEvents then log:debug("eatKEYEvent is true") --jump out again if this is an UP event, we only want to respond once to each keypress if event:getType() == EVENT_KEY_UP then log:debug("Key UP event detected. Resetting EatKEYEvents to False") eatKEYEvents = false end --if eatKEYEVENTS is TRUE and this is a DOWN event, we consume the event, leaving nothing. So don't act on this keypress. log:debug("key DOWN detected and eatKEYEvents is set. If we consume this no action is performed ") -- return EVENT_CONSUME --removing this for now as it seemed to consume all remaining events --otherwise change the skin to the remote skin for the preset time if no screensaver is running elseif self:changeSkin(remoteSkin) and not appletManager:callService("isScreensaverActive") then log:debug("no screensaver - accepting key event, setting eatKEYEvents to true, starting timer and changing to remote skin") eatKEYEvents = true -- return EVENT_UNUSED --commented out because of duplication in timer --Experimental Timer code from here -- self.timer = Timer(6000, function() self:changeSkin(touchSkin) end, true) -- moved to initialisation log:debug("starting timer") self.timer:start() -- listener to restart skin-switcher timer --not at all sure about this as it looks as if we never trigger it from here and there's allready a key event listener running. Can we move the interval reset to the beginning of this section? -- Framework:addListener(bit.bor(ACTION, EVENT_KEY_ALL), -- function(event) -- --restart timer if it is running --log:debug("another key event detected - resetting timer") --self.timer:setInterval(6000) --return EVENT_UNUSED -- end, -- true --) --To here end --If none of the above are true, the screensaver must be active log:debug("screensaver active, ignoring key event") return EVENT_UNUSED end, -100) --Base the key listener on the mouse/(touch) listener for now Framework:addListener(EVENT_MOUSE_ALL, function(event) -- ignore event when switching from remote to touch: we don't know what we're touching -- wake up if in screensaver mode - this is a non critical action log:debug("Mouse/Touch event detected") if self:changeSkin(touchSkin) and not appletManager:callService("isScreensaverActive") then log:debug("no screensaver, accepting touch event") return EVENT_CONSUME end log:debug("screensaver active, ignoring touch event") return EVENT_UNUSED end, -100) return self end function changeSkin(self, skinType) if self.mode == skinType then return false end local skinName = appletManager:callService("getSelectedSkinNameForType", skinType) if jiveMain:getSelectedSkin() == skinName then self.mode = skinType -- needed for inital setting of mode at start. log:debug("skin already selected, not switching: ", skinName) return false end log:info(self,":changeSkin ",skinName,":",skinType) local img1 = _capture("foo") self.mode = skinType jiveMain:setSelectedSkin(skinName) local img2 = _capture("bar") Framework:_startTransition(self._transitionFadeIn(img1, img2)) return true end function _capture(name) local sw, sh = Framework:getScreenSize() local img = Surface:newRGB(sw, sh) Framework:draw(img) return img end function _transitionFadeIn(oldImage, newImage) -- use a fast transition local startT local transitionDuration = 100 local remaining = transitionDuration local sw, sh = Framework:getScreenSize() local scale = (transitionDuration * transitionDuration * transitionDuration) / sw local animationCount = 0 local scale = 255 / transitionDuration return function(widget, surface) if animationCount == 0 then --getting start time on first loop avoids initial delay that can occur startT = Framework:getTicks() end local x = remaining * scale newImage:blit(surface, 0, 0) oldImage:blitAlpha(surface, 0, 0, x) local elapsed = Framework:getTicks() - startT remaining = transitionDuration - elapsed if remaining <= 0 then Framework:_killTransition() end animationCount = animationCount + 1 end end 114,47 43%
-
2021-01-30, 03:54 #55
- Join Date
- Sep 2015
- Posts
- 218
...continued from previous post:
The main problem now is that I have misunderstood
EVENT_KEY_UP, EVENT_KEY_DOWN events, which I thought were repectively key release and key press and which I tried to use to filter so that only one event per keypress should be acted on.
How should this be done? Can I use something like:
Code:int pressed () { SDL_Event event; while(SDL_PollEvent(&event) ) { if(event.type == SDLK_KEYDOWN) { switch(event.key.keysym.sym) { case SDLK_RETURN: doStuff = 1 break; default: break; } } if(event.type == SDLK_KEYUP) { switch(event.key.keysym.sym) { case SDLK_RETURN: doStuff = 0; break; default: break; } } } }
I am also working on a tweak to HDSkin, for fonts and icons to be clear from a distance when using the remote. I'll publish everything here when I'm finished.