Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
sonnykr
Visitor

[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 8
Komag
Roku Guru

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
Visitor

Re: Continuous button press

Awesome. Thanks KOMAG!
0 Kudos
NewManLiving
Visitor

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
Visitor

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
Visitor

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
Visitor

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
Roku Guru

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
Need Assistance?
Welcome to the Roku Community! Feel free to search our Community for answers or post your question to get help.

Become a Roku Streaming Expert!

Share your expertise, help fellow streamers, and unlock exclusive rewards as part of the Roku Community. Learn more.