How to read keypress from exclusive external USB keypad .

dinge
Posts: 6
Joined: Friday 05th June 2020 7:37pm

How to read keypress from exclusive external USB keypad .

Post by dinge » Saturday 06th June 2020 8:11pm

Hello gambasers
*trying to
-use USB external keypad
-make it exclusive to gambas program
-read keypress events

*problem
Cannot figure out how to use ioctl correct way
despite reading ioctl italian cdrom control gambas program.
I get no hold on how to write structure and pass correct arguments to ioctl.

*raw code with only essential code steps
' Gambas class file
Library "libc:6"
Public Extern ioctl(di As Integer, req As Integer, arg As Long) As Integer
Public usbdev As File

Public Struct input_event
ev As Byte
End Struct

Public Struct ev
type As Byte
code As Byte
value As Integer
End Struct

Public Enum EVIOCGNAME = &90
Public Enum EVIOCGRAB = &01

Public Sub Main
'raw code to show flow commands that works
'used lsusb to get usb device then vendor id and then get eventid
'---------chmod with root permission to use /dev/input/eventid
cmdshell = "sudo -S chmod 644 /dev/input/" & eventid
Shell "echo " & <yourpassword> & " | " & cmdshell

'----------open event assigned to keypad device
eventdev = "/dev/input/ & eventid"
usbdev = Open eventdev FOR READ WATCH

'----------Here i am stuck cannot grab device
'found in c program : result =ioctl(fd,EVIOCGRAB,1);
'gambas
result = ioctl(usbdev.handle, EVIOCGRAB,1)
'gives always -1 which is an error
'how to know what error and why

'----Here also stuck cannot get name from keypad device
'found in c program : result = ioctl(usbdev.handle,EVIOCGNAME(SizeOf(name)),name)
Tried many different ways each time error
I don't know how to declare the right way in the Gambas class and how to
translate -- EVIOCGNAME(SizeOf(name)),name -- into gambas syntax for ioctl.

End
Public Sub File_read()

'----Here i am stuck not able to read EV_KEY events and code
'if i press keypad then a file_read happens and gambas error is given
Read #usbdev, input_event.ev, -256
'Tried many different ways each time read error

value2 = input_event.ev[0].value
If (value2 <> " " And input_event.ev[1].value = 1 And input_event.ev[1].type = 1) Then
Message(" code: " & input_event.ev[1].code)
Endif

End

'-----------------------INFORMATION GATHERED-----------------
from input.h , keyboard.h , input-events-codes.h
This is the way you get the kernel generated information back
caused by the received input (eg. a keypress)

struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};

/* get event bits */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len)

/* I suppose i have to understand it this way
_IOC_READ = READ the /dev/input/eventX by file.handle from opened device eventfile
'E' = EVIOCGBIT
'ev' = EV_KEY 'here i will get ev[ ].code -> keypress code
'len' = predefined memory reserved bytes with info ?
*/
from input-event-codes.h
#define EV_KEY 0x01

'-----input.h -----------------------
/* get device name */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len)
/* Grab/Release device */
#define EVIOCGRAB _IOW('E', 0x90, int)

I tried to give as much information necessary but stripped to the essential, hope this is clear enough to see the errors
or to be able to show the path to straigthen out my lack of knowledge in the gambas world.
Thanks ahead

User avatar
Quincunxian
Posts: 83
Joined: Sunday 25th June 2017 12:14am
Location: Western Australia

Re: How to read keypress from exclusive external USB keypad .

Post by Quincunxian » Saturday 06th June 2020 10:12pm

Hi dinge and welcome to the forum.

I'm trying to understand why/what you are doing before getting down to the code level.
I assume you have a standard keyboard with a number pad on it.
You want to plug in an external usb number pad and distinguish between the keyboard pad and the external pad.

The standard key read process in Gambas makes no distinction between the keyboard & USB pads so if you press a number pad '5' on either device it comes up
with the same key code (53, on my standard Dell keyboard using EN-AU)

What you are trying to achieve is to interrupt the key press process and determine what device instigated the event and redirect input from the external number pad to
a separate function to manage.

Is this an accurate assessment ?
Cheers - Quin.
I code therefore I am

vuott
Posts: 35
Joined: Wednesday 05th April 2017 6:07pm

Re: How to read keypress from exclusive external USB keypad .

Post by vuott » Saturday 06th June 2020 10:22pm

dinge wrote:
Saturday 06th June 2020 8:11pm
Public Enum EVIOCGNAME = &90
Public Enum EVIOCGRAB = &01
Hello,
...excuse me, i have a little curiosity: where did you find those values related to EVIOCGNAME and EVIOCGRAB ?

regards.

dinge
Posts: 6
Joined: Friday 05th June 2020 7:37pm

Re: How to read keypress from exclusive external USB keypad .

Post by dinge » Sunday 07th June 2020 9:38am

Dear Mr Quincunxian and Mr Vuott,
thanks for your swift reaction.
Here my answer to your questions.

*to Mr Quincunxian
Thanks for your welcom.
Indeed more information needed about why, what

Situation:
Laptop ASUS TP300L - 64bit - 6gb memory ( Zorin linux)
keyboard with no numeric keypad

Dekstop 32bit - 4Gb memory ( Bunsenlabs linux)
external small usb keyboard with no num keypad

What:
Use and grab external USB numeric keypad for exclusive use by Gambas program

Why:
Grab keypress events from external USB numeric keypad assigned exclusively to Gambas program.

I want to create a program with assigned macro's to keypad keys from within Gambas program.

The Gambas gui makes it easy for me to test and configure this assigned xdotool commands.

Therefore I have to grab first the keypad and reserve it to my Gb application.
Secondly read the keypress events and execute accordingly a macro what here consist of xdotool command(s) stored in a file to send to application where the cursor is active.

The xdotool commands stored in file works fine in Gambas.
Made a Arduino board with small numeric keypad with USB -arduino serial port- connection which works good.
Arduino board has also IR receiver which works also good with Gb and xdotool file macros (works but not finished yet).

I want to do the same( no IR ) with USB external keypad.

But with the real USB external keypad I am stuck
on getting keydata and grab ecxlusivity with ioctl().

I do not find the correct way to assign arguments
to use ioctl accordingly in Gambas

The Read keypress event in the Gb program does happen,
but gives errors and can't get the keypress code.

*to Mr Vuott

Information from header files which are used by ioctl()

file: /usr/include/linux/input.h
/* get device name */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len)
/* Grab/Release device */
#define EVIOCGRAB _IOW('E', 0x90, int)
/* get event bits */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len)

file: /usr/include/linux/input-event-codes.h
/* Event types */
#define EV_KEY 0x01

as I understand
_IOC_READ = gambas> READ #youreventFile, intoyourvariable, length bytes reserved to read from

'E' = eventfile = gambas> yourfile.handle

'OxHEX' = defined eg ECIOCGRAB which has address 0x90
or in case of read/get keypress = EVIOCGBIT+ EV_KEY = 0x20+0x01

len = name =string of bytes = number of bytes =lentgh ?

int = integer eg. EVIOCGRAB = 1 to grab and O to ungrab

Information gambas wiki italian - ioctl get data from cdrom and player
https://www.gambas-it.org/wiki/index.php?title=Ioctl()


Thanks for your reply , hopefully this helps you.

vuott
Posts: 35
Joined: Wednesday 05th April 2017 6:07pm

Re: How to read keypress from exclusive external USB keypad .

Post by vuott » Sunday 07th June 2020 3:37pm

Hello dinge,

some reflection:

1)
In my humble opinion "EVIOCGRAB" can not have that value 1, because it's a Macro.
Infact #define EVIOCGRAB _IOW('E', 0x90, int) means:

EVIOCGRAB is defined as _IOW('E', 0x90, int)

So you are forced to develop, to translate that Macro - ...or better: that Function _IOW(....) - in Gambas language.


2)
Symbol 'E' in C language corresponds to the ASCII numeric value of the capital letter "E".
Anyway, to find out more about ioctl-numbers:
https://www.mjmwired.net/kernel/Documen ... number.txt


Regards

dinge
Posts: 6
Joined: Friday 05th June 2020 7:37pm

Re: How to read keypress from exclusive external USB keypad .

Post by dinge » Monday 08th June 2020 4:53pm

Dear Mr Vuott,
thanks for your reply.

Unfamiliar with C- programming and the linux inside io lib handling , what you suspected I suppose.
Back to the drawing board !
Very helpfull link you mentioned.

Read the Gambas wiki on Extern, helped to better understand.
Was able to use a math function frexp() from libm library with the for me still nebelous pointer hassle.
The _IOW(... is another piece of cake to handle.
And yes there may be a way to get around it somehow.

Thanks for your information

vuott
Posts: 35
Joined: Wednesday 05th April 2017 6:07pm

Re: How to read keypress from exclusive external USB keypad .

Post by vuott » Monday 08th June 2020 6:12pm

Hello dinge,
Quincunxian wrote:
Saturday 06th June 2020 10:12pm
... determine what device instigated the event
...i want to start with this Quincunxian's sentence.

For a quick and very simple way I would propose this code.
Let's pretend that the file-device "/dev/input/event4" corresponds to the first keyboard, and that the file-device "/dev/input/event13" corresponds to the second keyboard.
...obviously they will have been preliminarily unlocked with chmod.
Therefore we place the two file-devices under observation: if anything can be read, the "File_Read ()" Event sub-routine will be raised.
The two file-devices must be managed in different Modules/Classes, otherwise the solution will not be possible !
The code consists of the main module:
Private fl As File


Public Sub Main()

  Dim cl1 As New Class1
  
  cl1.Event13()

  fl = Open "/dev/input/event4" For Read Watch

End


Public Sub File_Read()
 
  Print "Pressed: event4"
  
  fl.Close
  
  fl = Open "/dev/input/event4" For Read Watch
  
End
In the secondary class we will manage the other file-device:
Private fl As File


Public Sub Event13()

  fl = Open "/dev/input/event13" For Read Watch

End


Public Sub File_Read()
  
  Print "Pressed: event13"
  
  fl.Close
  
  fl = Open "/dev/input/event13" For Read Watch
  
End


dinge wrote:
Monday 08th June 2020 4:53pm
The _IOW(... is another piece of cake to handle.
_IOW(...) is a result of more Macro.

This page from italian wiki could be useful:
Emulare in Gambas le macro IOR, IOW e IOWR usate con la funzione ioctl()

dinge
Posts: 6
Joined: Friday 05th June 2020 7:37pm

Re: How to read keypress from exclusive external USB keypad .

Post by dinge » Sunday 14th June 2020 1:35pm

Dear Mr Quincunxian,
thanks for your reply , indeed interesting to handle two keyboard events.
For the moment I only want to use 1 external usb keypad.
Found a solution by using a small c- file , to use keypress event outside gambas application keypress_event.
Used code I found on and other similar handling the grabbing and reading
https://gist.github.com/matthewaveryusa ... 64fa20fec1
Found a solution to grab usb device by isolating through the xinput float command
https://askubuntu.com/questions/160945/ ... l-keyboard
It is alo possible to use and install two mousepointers or multiple keyboards .
Also thanks to Mr Stevedee and his blog brought me the idea to do the workaround with c-file ( thanks Mr Stevedee)
Overview
'USB' - Show your usbdevices from the lsusb list in lstInfo
'VENDOR' select your keyboard device inlist an d klik
'Select your slave keyboard - youtr usb device
'USE' to activate or choose another device or slave as sometimes one keypad shows two slave keyboards
'Test by typing
From here on you can use the keypress code and save in file
or code actions associatecd with keypress.
This is the next stepin the project.
Included zip program, hopefully this is helpfull and someone can explain me later also how to use
the EV_KEY structure from within gambas with external library

Thanks greetings
Attachments
ExtraKeypad-0.0.2.tar.gz
(18.89 KiB) Downloaded 12 times

vuott
Posts: 35
Joined: Wednesday 05th April 2017 6:07pm

Re: How to read keypress from exclusive external USB keypad .

Post by vuott » Sunday 14th June 2020 11:31pm

dinge wrote:
Sunday 14th June 2020 1:35pm
Used code I found on and other similar handling the grabbing and reading
https://gist.github.com/matthewaveryusa ... 64fa20fec1
Hello dinge,
I transposed to Gambas the part of the code, present in that link, relating to the keyboard:
Library "libc:6"

Public Struct timeval
  tv_sec As Long
  tv_usec As Long
End Struct

Public Struct input_event
  time_ As Struct Timeval
  type As Short
  code As Short
  value As Integer
End Struct

Private Const _IOC_NRSHIFT As Integer = 0
Private Const _IOC_NRBITS As Integer = 8
Private _IOC_TYPESHIFT As Long = _IOC_NRSHIFT + _IOC_NRBITS
Private Const _IOC_TYPEBITS As Long = 8
Private _IOC_SIZESHIFT As Long = _IOC_TYPESHIFT + _IOC_TYPEBITS
Private Const _IOC_SIZEBITS As Long = 14
Private _IOC_DIRSHIFT As Long = _IOC_SIZESHIFT + _IOC_SIZEBITS
Private Const _IOC_WRITE As Long = 1
Private Const _IOC_READ As Long = 2

' int ioctl(int __fd, unsigned long int __request, ...)
' Perform the I/O control operation specified by REQUEST on FD.
Private Extern ioctl_name(__fd As Integer, __request As Long, arg As Byte[]) As Integer Exec "ioctl"

' int ioctl(int __fd, unsigned long int __request, ...)
' Perform the I/O control operation specified by REQUEST on FD.
Private Extern ioctl_grab(__fd As Integer, __request As Long, arg As Integer) As Integer Exec "ioctl"

' ssize_t read (int __fd, void *__buf, size_t __nbytes)
' Read NBYTES into BUF from FD.
Private Extern read_C(__fd As Integer, __buf As Input_event, __nbytes As Long) As Long Exec "read"


Public Sub Main()

  Dim kfl As File
  Dim keyboard_name As New Byte[256]
  Dim rcode As Long
  Dim ke As New Input_event
  Dim tempus As Date
  
'' In my system KEYBOARD event file-device is "event4":
  kfl = Open "/dev/input/event4" For Read
  If kfl.Handle < 0 Then
    kfl.Close
    Error.Raise("Error !")
  Endif
  
  rcode = ioctl_name(kfl.Handle, Eviocname(Asc("E"), &h06, keyboard_name.Count), keyboard_name)
  Print "Reading From: \e[34m"; keyboard_name.ToString(0, keyboard_name.Find(0))

  rcode = ioctl_grab(kfl.Handle, Eviocgrab(Asc("E"), &h90, SizeOf(gb.Integer)), 1)
  Print "\e[0mGetting exclusive access: "; IIf(rcode == 0, "\e[32mSUCCESS\e[0m", "\e[31mFAILURE\e[0m")

Print
  
  tempus = Now
  Repeat
    If read_C(kfl.Handle, ke, Object.SizeOf(ke)) > -1 Then
      Print "keyboard event:  type "; ke.code; " code: "; ke.code; " value: "; ke.value
    Endif 
    Wait 0.01
  Until DateDiff(tempus, Now, gb.Second) == 10  ' We arrange for the cycle to last, for example, 10 seconds: 10 sec. to click on the keyboard.
  
  rcode = ioctl_grab(kfl.Handle, Eviocgrab(Asc("E"), &h90, SizeOf(gb.Integer)), 1)
  kfl.Close

End


Private Function Eviocname(type As Long, nr As Long, size As Long) As Long
  
  Return Shl(_IOC_READ, _IOC_DIRSHIFT) Or Shl(type, _IOC_TYPESHIFT) Or Shl(nr, _IOC_NRSHIFT) Or Shl(size, _IOC_SIZESHIFT)
  
End


Private Function Eviocgrab(type As Long, nr As Long, size As Long) As Long
  
  Return Shl(_IOC_WRITE, _IOC_DIRSHIFT) Or Shl(type, _IOC_TYPESHIFT) Or Shl(nr, _IOC_NRSHIFT) Or Shl(size, _IOC_SIZESHIFT)
  
End
Last edited by vuott on Monday 22nd June 2020 11:33am, edited 1 time in total.

dinge
Posts: 6
Joined: Friday 05th June 2020 7:37pm

Re: How to read keypress from exclusive external USB keypad .

Post by dinge » Sunday 21st June 2020 8:20pm

Dear Mr Vuott,
thanks for your code.
Worked on the macro part, finished and using it for keymacro's with Subtitle Composer.
Thanks again , looking to understand and integrate your code now.
Greetings

Post Reply