Your Digital Media Has Never Looked So Good

 
sonnykr
Topic Author
Posts: 70
Joined: Thu Jun 12, 2014 11:57 am

[Solved] Continuous button press

Thu Feb 12, 2015 8:40 pm

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.
Last edited by sonnykr on Tue Apr 14, 2015 10:45 am, edited 1 time in total.
 
User avatar
Komag
Posts: 808
Joined: Fri Aug 22, 2014 3:42 am

Re: Continuous button press

Thu Feb 12, 2015 9:07 pm

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)
 
sonnykr
Topic Author
Posts: 70
Joined: Thu Jun 12, 2014 11:57 am

Re: Continuous button press

Fri Feb 13, 2015 7:38 am

Awesome. Thanks KOMAG!
 
User avatar
NewManLiving
Posts: 452
Joined: Fri Aug 02, 2013 6:14 pm

Re: Continuous button press

Fri Feb 13, 2015 9:55 am

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

'*****************************************************************************************************************************
Last edited by NewManLiving on Fri Feb 13, 2015 7:20 pm, edited 3 times in total.
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
 
Rek
Posts: 97
Joined: Mon Jul 08, 2013 9:22 am

Re: Continuous button press

Fri Feb 13, 2015 10:14 am

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
 
User avatar
NewManLiving
Posts: 452
Joined: Fri Aug 02, 2013 6:14 pm

Re: Continuous button press

Wed Apr 01, 2015 12:37 pm

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 )
 
sonnykr
Topic Author
Posts: 70
Joined: Thu Jun 12, 2014 11:57 am

Re: Continuous button press

Tue Apr 14, 2015 10:45 am

Thank you Guys!
 
pdineshkumar55
Posts: 29
Joined: Thu Jun 25, 2015 12:56 am

Re: Continuous button press

Thu May 16, 2019 11:05 am

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.
 
User avatar
Komag
Posts: 808
Joined: Fri Aug 22, 2014 3:42 am

Re: [Solved] Continuous button press

Thu May 16, 2019 8:54 pm

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()

Who is online

Users browsing this forum: No registered users and 7 guests