Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
sonnykr
Level 7

[Solved] Continuous button press

Hey All,

How can continuous button press events be received when the user press and hold a button on the remote? I am getting only one roUniversalControlEvent when the button is pressed and hold for some time.

I have a custom grid, and I would like to scroll through the grid continuously by holding the up/down button in the remote, without multiple button press.

Thanks.
0 Kudos
8 Replies
Komag
Level 9

Re: Continuous button press

There is a separate code for button release, so you just check whether they pressed the button down and didn't let go yet.

Here's my note of button codes:
Back 0,100; Up 2,102; Down 3,103; Left 4,104; Right 5,105; Select(OK) 6,106; Instant Replay 7,107; Rewind 8,108; Fast Forward 9,109' Info 10,110; Backspace (not on remote) 11,111; Play 13,113; A 17,117; B 18,118

The first number is the press code, the second number is the release code (always 100 more)
0 Kudos
sonnykr
Level 7

Re: Continuous button press

Awesome. Thanks KOMAG!
0 Kudos
NewManLiving
Level 7

Re: Continuous button press

Simple Grid demos three styles
1 - Using Associative Arrays as objects
2- Scrolling using region offsetting
3- Monitoring user button presses to navigate the grid

If you are just interested in the navigation then go to
GridModule:EventLoop Use arrow fw and rw keys to navigate

Quickly put together but adequately demonstrates one method

Sub Main() 

l_ds = CreateObject( "roDeviceInfo" ).GetDisplaySize()
l_dw = l_ds.w
l_dh = l_ds.h

' Application Globals ( you can create a global object which is a better solution )
m.BkgColor = &hFFFFFFFF
m.Screen = CreateObject( "roScreen", True, l_dw, l_dh )
m.Port = CreateObject( "roMessagePort" )
m.Screen.SetMessagePort( m.Port )

' Create an instance of the grid module
l_module = NewGridModule()
if l_module.Create()
l_module.EventLoop()
else
print "NewGridModule Failed"
end if

l_module.Release()

End Sub


'***************************** Grid Module Object ***********************************************************************

Function NewGridModule() As Object

return {

' Reference to globals declared in main
' They must be referenced during creation, as the m pointer can only point to the AA's members
' once created. However, Screen: and Port: are members referencing the globals so they can be safely used
' once assigned
Screen: m.Screen
Port: m.Port

' Member Variable - our simplegird and a timer
SimpleGrid: Invalid
Timer: Invalid

' Member Functions
Create: grid_module_create
Initialize: grid_module_initialize
Release: grid_module_release
EventLoop: grid_module_event_loop

}
End Function

' All objects work the same, create, initialize, release
Function grid_module_create() As Boolean
if not m.Initialize()
m.Release()
return False
end if
return True
End Function

Function grid_module_initialize() As Boolean

m.SimpleGrid = NewSimpleGrid()
if not m.SimpleGrid.Create() then return False

m.Timer = CreateObject( "roTimeSpan" )

l_ds = CreateObject( "roDeviceInfo" ).GetDisplaySize()
l_dw = l_ds.w
l_dh = l_ds.h

l_x = l_dw / 2 - m.SimpleGrid.GetWidth() / 2
l_y = l_dh / 2 - m.SimpleGrid.GetHeight() / 2
m.SimpleGrid.MoveTo( l_x, l_y )

return True
End Function

Function grid_module_release() As Void
if m.SimpleGrid <> Invalid
m.SimpleGrid.Release()
m.SimpleGrid = Invalid
end if

m.Timer = Invalid

End Function

Function grid_module_event_loop() As Boolean

if m.SimpleGrid = Invalid then return False

l_kp_BK = 0
l_kp_LT = 4
l_kp_RT = 5
l_kp_RW = 8
l_kp_FF = 9

' Frame rates and scroll pause
l_fastRate = 4
l_normalRate = 16
l_scrollPause = 175
' lastkey saves the last button pressed until the button-up event
l_lastKey = -1
l_index = -1

m.Timer.Mark()

while( True )
' Cannot use wait to do this must be always polling
l_msg = m.Port.GetMessage()
' The user pressed a button
if type( l_msg ) = "roUniversalControlEvent"

l_index = l_msg.GetInt()
l_lastKey = l_index

if l_index = l_kp_LT

m.SimpleGrid.ScrollLeft( l_normalRate )

else if l_index = l_kp_RT

m.SimpleGrid.ScrollRight( l_normalRate )

else if l_index = l_kp_RW

m.SimpleGrid.ScrollLeft( l_fastRate )

else if l_index = l_kp_FF

m.SimpleGrid.ScrollRight( l_fastRate )

else if l_index = l_kp_BK

exit while
' The user released a button, set lastkey to -1
else if l_index >= 100

l_lastKey = -1

end if
' Reset the timer regardless of what comes in
m.Timer.Mark()
' user is holding down button because l_lastkey <> -1
' Once the initial pause elapsed then check last key
else if ( l_lastKey >= 0 and m.Timer.TotalMilliseconds() >= l_scrollPause )

if l_lastKey = l_kp_LT
m.SimpleGrid.ScrollLeft( l_normalRate )
else if l_lastKey = l_kp_RT
m.SimpleGrid.ScrollRight( l_normalRate )
else if l_lastKey = l_kp_RW
m.SimpleGrid.ScrollLeft( l_fastRate )
else if l_lastKey = l_kp_FF
m.SimpleGrid.ScrollRight( l_fastRate )
end if

end if

end while

return True
End Function

'***************************************************************************************************************

'********************* Simple Grid Object **************************************************************************
' This grid uses region offsetting to intrinsically scroll the grid
' It also demontrates how to create simple objects using an AA
Function NewSimpleGrid() As Object

return {
' Reference member to global variable. Must be assigned here, once created the m pointer only points to members
' within this AA. Since it now has a member which references a global you can use it safely
Screen: m.Screen
BkgColor: m.BkgColor

' Variable members
Count: 5
GridX: 0
GridY: 0
Width: 150
Height: 100
Margin: 10
Buffer: Invalid
Region: Invalid

' Functions which act upon the variable members. Any function assigned to a function pointer member
' can access any other member ( variables and functions ) via the m pointer.
Create: simple_grid_create
Initialize: simple_grid_initialize
Release: simple_grid_release
MoveTo: simple_grid_move_to
GetWidth: simple_grid_get_width
GetHeight: simple_grid_get_height
Draw: simple_grid_draw
ScrollLeft: simple_grid_scroll_left
ScrollRight: simple_grid_scroll_right
}

End Function

' Once the function is assigned to a function pointer of the AA then all members can be accessed with the m ( this ) pointer
Function simple_grid_create() As Boolean
if not m.Initialize()
m.Release()
return False
end if
return True
End Function

Function simple_grid_initialize() As Boolean
' Insure everything is released. This is important if you use sprites.
' They must be explicitly removed
m.Release()
' Calculate the buffer size and create the buffer
l_w = m.Count * ( m.Width + m.Margin )
m.Buffer = CreateObject( "roBitmap", { width: l_w, height: m.Height, AlphaEnable: True } )
if m.Buffer = Invalid then return False
m.Buffer.Clear( &hC0C0C0FF )

' Create the region same size as the buffer, but minus the end margin . SetWrap to true
m.Region = CreateObject( "roRegion", m.Buffer, 0, 0, l_w - m.Margin, m.Height )
if m.Region = Invalid then return False
m.Region.SetWrap( True )

' Create the font and get it's static one-line-height / 2 for centering
l_font = CreateObject( "roFontRegistry" ).GetDefaultFont( 50, True, False )
l_strh = l_font.GetOneLineHeight() / 2

' Grid poster size and offsets ( all precalulated for optimization )
l_offset = m.Width + m.Margin
l_cw = m.Width / 2
l_ch = m.Height / 2
l_x = 0
l_y = 0

' Draw in the faux grid displaying it's index centered
for l_i = 1 to m.Count
m.Buffer.DrawRect( l_x, l_y, m.Width, m.Height, &h8D798BFF )
l_str = l_i.ToStr()
l_strw = l_font.GetOneLineWidth( l_str, m.Width )
m.Buffer.DrawText( l_str, l_x + ( l_cw - l_strw / 2 ), l_y + ( l_ch - l_strh ), &h606060FF, l_font )
l_x = l_x + l_offset
end for

m.Buffer.Finish()

return True

End Function

Function simple_grid_release() As Void
m.Buffer = Invalid
m.Region = Invalid
End Function

Function simple_grid_move_to( a_x As Integer, a_y As Integer, a_isDraw = True As Boolean ) As Boolean
if m.Buffer = Invalid then return False

m.GridX = a_x
m.GridY = a_y
if a_isDraw then m.Draw()

return True
End Function

Function simple_grid_draw() As Boolean
if m.Region = Invalid then return False
m.Screen.Clear( m.BkgColor )
m.Screen.DrawObject( m.GridX, m.GridY, m.Region )
m.Screen.SwapBuffers()
return True
End Function

Function simple_grid_get_width() As Integer
if m.Region = Invalid then return -1
return m.Region.GetWidth()
End Function

Function simple_grid_get_height() As Integer
if m.Region = Invalid then return -1
return m.Region.GetHeight()
End Function

Function simple_grid_scroll_left( a_frames = 16 As Integer ) As Boolean
if m.Region = Invalid then return False

l_offset = 0
l_prevset = 0
l_offdiff = 0

l_columnWidth = m.Width + m.Margin

for l_i = 1 to a_frames

l_offset = int( l_columnWidth * l_i / a_frames )
l_offdiff = l_offset - l_prevset
l_prevset = l_offset

m.Region.Offset( -l_offdiff, 0, 0, 0 )
m.Region.Finish()
m.Draw()

end for

return True
End Function

Function simple_grid_scroll_right( a_frames = 16 As Integer ) As Boolean
if m.Region = Invalid then return False

l_offset = 0
l_prevset = 0
l_offdiff = 0

l_columnWidth = m.Width + m.Margin

for l_i = 1 to a_frames

l_offset = int( l_columnWidth * l_i / a_frames )
l_offdiff = l_offset - l_prevset
l_prevset = l_offset

m.Region.Offset( l_offdiff, 0, 0, 0 )
m.Region.Finish()
m.Draw()

end for

return True
End Function

'*****************************************************************************************************************************
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos
Rek
Level 7

Re: Continuous button press

It's worth pointing out that you can get the button codes from the brightscript core library:


Library "v30/bslCore.brs"

function main()
keyCodes = bslUniversalControlEventCodes()
buttonUpPressed = keyCodes.button_up_pressed
buttonUpReleased = keyCodes.button_up_released
end function
0 Kudos
NewManLiving
Level 7

Re: Continuous button press

Yes I know. You can also make use of the global AA. But this is primarily to show how to use the m pointer, region Offsetting and AA objects
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos
sonnykr
Level 7

Re: Continuous button press

Thank you Guys!
0 Kudos

Re: Continuous button press

"Rek" wrote:
It's worth pointing out that you can get the button codes from the brightscript core library:


Library "v30/bslCore.brs"

function main()
  keyCodes = bslUniversalControlEventCodes()
  buttonUpPressed   = keyCodes.button_up_pressed
  buttonUpReleased = keyCodes.button_up_released
end function


Hi Rek,
How can I match these button released values on onkeyEvent() called? Then only I can know is the button released or not.
onkeyEvent gives only key press event only. Not the button press and release value to match and make our logic.
Thank you.
I am using Roku 4 - 4400X Model.
0 Kudos
Komag
Level 9

Re: [Solved] Continuous button press

evnt = port.GetMessage()
'IF evnt <> INVALID THEN PRINT "evnt" evnt ", Type(evnt) = " Type(evnt) ' This prints everything (mainly button presses/releases)
IF (Type(evnt) = "roUniversalControlEvent") THEN controls(evnt) ' CONTROL EVENTS - REMOTE ' Only send remote button press events to controls()
0 Kudos