PlanetSquires Forums

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: Works with PowerBASIC but not with FireFly  (Read 709 times)

Jean-pierre Leroy

  • Senior Member
  • ***
  • Posts: 469
  • expect nothing, be prepared for everything ...
Works with PowerBASIC but not with FireFly
« on: November 27, 2018, 11:54:09 AM »

Dear FireFly user,

For a specific form I would like to disabled CAPS LOCK (if set); for that purpose I use the function SetNumLock() below:

And in the WM_CREATE handler of the FORM I called it with these parameters:
Code: [Select]
SetNumLock(%VK_CAPITAL, %FALSE)

Code: [Select]
Sub SetNumLock(VKkey As Long, bState As Byte)
   'Turn on and off caps lock, scroll lock and num lock
   'VKkey = %VK_CAPITAL, %VK_SCROLL, %VK_NUMLOCK
   'bState = %TRUE for on, %FALSE for off
   Dim keyState(256) As Byte
   Local pKeyState As Byte Ptr
   pKeyState = VarPtr(keyState(0))
   GetKeyboardState ByVal pKeyState
   If ((bState And Not (keyState(VKkey) And 1)) Or (Not bState And (keyState(VKkey) And 1))) Then
      Keybd_event VKkey, 0, %KEYEVENTF_EXTENDEDKEY, 0
      Keybd_event VKkey, 0, %KEYEVENTF_EXTENDEDKEY + %KEYEVENTF_KEYUP, 0
      keyState(VKkey) = bState
      SetKeyboardState ByVal pKeyState
   End If
End Sub

If CAPS LOCKS is on before starting the program, within FireFly, CAPS LOCK led is switched off but the characters are still capitalized.
Within a PowerBASIC source code it works perfectly.

There is probably something related to FireFly, but I've no idea where to look at.

Thanks for your help.
Jean-Pierre

« Last Edit: November 27, 2018, 04:35:06 PM by Jean-pierre Leroy »
Logged

David Kenny

  • Senior Member
  • ***
  • Posts: 457
  • Windows 7 & 10
Re: Works with PowerBASIC but not with FireFly
« Reply #1 on: November 28, 2018, 02:39:49 AM »

Hello Jean-pierre,

Don't use that code... It's been mangled in some way.  Did some weird stuff on my machine (multi-line, pasted code ended up on the same line as if the CRLFs were stripped out). Had to reboot to fix it. Try this instead:
Code: [Select]
If GetKeyState(%VK_CAPITAL) Then ToggleKey(%VK_CAPITAL) 'If it is on, toggle it off.

Sub ToggleKey(Key As Byte)
    Keybd_event 0, 0, 0, 0
    Keybd_event Key, MapVirtualKey(Key, 0), %KEYEVENTF_EXTENDEDKEY, 0
    Keybd_event Key, MapVirtualKey(Key, 0), %KEYEVENTF_EXTENDEDKEY Or %KEYEVENTF_KEYUP, 0
    Keybd_event 0, 0, %KEYEVENTF_KEYUP, 0
End Sub

It works in PB and FF, I tested both.

Put the calling IF line anywhere.  Since the user can turn the capslock back on, you could check it regularly and keep turning it off.  You didn't tell us how you were going to use it.  Put it in Create if you only want it off at the start of the program. 

You can use it to manage the other toggle keys by changing the argument.

David
Logged

Jean-pierre Leroy

  • Senior Member
  • ***
  • Posts: 469
  • expect nothing, be prepared for everything ...
Re: Works with PowerBASIC but not with FireFly
« Reply #2 on: November 28, 2018, 05:37:11 AM »

Hi David,

Thanks a lot for your code. It works perfectly.

Quote
You didn't tell us how you were going to use it.
I will try describe what I want to achieve.

For an inventory application, we use Zebra digital scanner DS3678.
We use it in what is called "Batch Only Mode" i.e. without any Bluetooth or Wifi connection.
The inventory is done by scanning the barcodes on products; after that the employee launch the inventory application (with a notepad like form to receive the datas); then he inserts the scanner in the cradle; Data transmission is triggered by insertion of the scanner into the cradle; the cradle itself is connected trough a USB HID Keyboard interface.

If CAPS LOCK is set, the barcodes are translated into upper case characters and we don't receive the right codes; it is why I was looking for a solution to disable CAPS LOCK

PS: now i have still to check that the cradle is well connected to the PC through the USB HID Keyboard interface; otherwise the whole data inventory will not be transmitted to the PC and will be probably lost !

Again thanks a lot for your help.
Jean-Pierre
Logged

David Kenny

  • Senior Member
  • ***
  • Posts: 457
  • Windows 7 & 10
Re: Works with PowerBASIC but not with FireFly
« Reply #3 on: November 29, 2018, 04:23:38 AM »

That's quite a coincidence Jean-Pierre.  I am currently working on a device I designed and built (a couple prototypes so far) that also identifies to Windows that it is an HID USB keyboard.  It's looks just like a flash drive, uses Bluetooth, and I control it with an app I wrote for Android phones.

Glad to hear it worked for you.

As for your PS:  It seems that your device should have been designed with that in mind.  It should have a button to send. That would send all the data it has each time it is pushed.  And a second one that must be held in for a bit to identify your wish to purge the data.  There are of course many ways to handle this, I'm only saying that there should be some way to avoid or mitigate loosing the data.

David
« Last Edit: November 29, 2018, 04:30:27 AM by David Kenny »
Logged

Jean-pierre Leroy

  • Senior Member
  • ***
  • Posts: 469
  • expect nothing, be prepared for everything ...
Re: Works with PowerBASIC but not with FireFly
« Reply #4 on: November 29, 2018, 06:21:41 AM »

David,

When the cradle is connected to the PC through the USB HID Keyboard interface, it appears in Windows 10 settings "Symbol Bar Code Scanner"; see the enclosed screenshot.

I'm looking the simplest function that would return %TRUE is the "Symbol Bar Code Scanner" is connected to the PC trough the USB HID Keyboard interface.

I've seen some code from Pierre Bellisle that would probably help me.

https://forum.powerbasic.com/forum/user-to-user-discussions/programming/767631-identify-usb-drive-letter?p=767726#post767726

Please tell me if you have other idea how to do that ?

Thanks,
Jean-Pierre
Logged

David Kenny

  • Senior Member
  • ***
  • Posts: 457
  • Windows 7 & 10
Re: Works with PowerBASIC but not with FireFly
« Reply #5 on: November 30, 2018, 05:49:41 AM »

For over 15 years (I'm guessing) I've relied on many of Pierre excellent example programs to dig useful information out of windows. The only problem is when I had an interest in something that he wasn't interested in.

Once I discovered Josť Roca's WMIGENX program, there hasn't been very much I can't find.  WMIGEN generates templates for WMI Classes. I put together a little program that might help you out. 

Code: [Select]
'Created using Jose's WMI Templates Generator C:\PB\WMIGENX   DBK

' ########################################################################################
' WMI Template
' Namespace = root\CIMV2
' WMI Class = Win32_PnPEntity
' ########################################################################################

#Compile Exe
#Dim All
#Include "WMI.INC"    'Since you are using FF, I know you are using Jose's include files

' ========================================================================================
' Retrieves the values of all of the properties of the Win32_PnPEntity class
' ========================================================================================
Function WMI_Win32_PnPEntity (Optional ByVal bstrComputer As WSTRING) As Long

   Local hr As Long                                  ' // HRESULT
   Local pLocator As IWbemLocator                    ' // IWbemLocator interface reference
   Local pService As IWbemServices                   ' // IWbemServices interface reference
   Local pEnumClassObject As IEnumWbemClassObject    ' // IEnumWbemClassObject collection reference
   Local pClassObject As IWbemClassObject            ' // IWbemClassObject interface reference
   Local bstrResource As WSTRING                     ' // Path of the correct WMI namespace
   Local bstrLanguage As WSTRING                     ' // Query language
   Local bstrQuery As WSTRING                        ' // Query filter
   Local uReturned As Dword                          ' // Number of returned references

   ' // Variants to store the property values
   Local vAvailability As VARIANT                    ' // Unsigned 16-bit integer
   Local vCaption As VARIANT                         ' // String
   Local vClassGuid As VARIANT                       ' // String
   Local vCompatibleID As VARIANT                    ' // Array - String
   Local vConfigManagerErrorCode As VARIANT          ' // Unsigned 32-bit integer
   Local vConfigManagerUserConfig As VARIANT         ' // Boolean value
   Local vCreationClassName As VARIANT               ' // String
   Local vDescription As VARIANT                     ' // String
   Local vDeviceID As VARIANT                        ' // String
   Local vErrorCleared As VARIANT                    ' // Boolean value
   Local vErrorDescription As VARIANT                ' // String
   Local vHardwareID As VARIANT                      ' // Array - String
   Local vInstallDate As VARIANT                     ' // Date/time value
   Local vLastErrorCode As VARIANT                   ' // Unsigned 32-bit integer
   Local vManufacturer As VARIANT                    ' // String
   Local vName As VARIANT                            ' // String
   Local vPNPDeviceID As VARIANT                     ' // String
   Local vPowerManagementCapabilities As VARIANT     ' // Array - Unsigned 16-bit integer
   Local vPowerManagementSupported As VARIANT        ' // Boolean value
   Local vService As VARIANT                         ' // String
   Local vStatus As VARIANT                          ' // String
   Local vStatusInfo As VARIANT                      ' // Unsigned 16-bit integer
   Local vSystemCreationClassName As VARIANT         ' // String
   Local vSystemName As VARIANT                      ' // String

   ' // Sets the default security values for the process
   hr = CoInitializeSecurity(ByVal %Null, -1, ByVal %Null, %Null, %RPC_C_AUTHN_LEVEL_DEFAULT, %RPC_C_IMP_LEVEL_IMPERSONATE, ByVal %Null, %EOAC_NONE, %Null)
   If hr <> %S_OK Then Function = hr : Exit Function

   ' // Creates an instance of the IWbemLocator interface
   pLocator = NEWCOM CLSID $CLSID_WbemLocator
   If IsNothing(pLocator) Then Function = %E_FAIL: Exit Function

   ' // Connects with the specified machine
   If Len(bstrComputer) And Right$(bstrComputer, 1) <> "\" Then bstrComputer +="\"
   bstrResource = bstrComputer & "root\CIMV2"
   hr = pLocator.ConnectServer(bstrResource, "", "", "", 0, "", Nothing, pService)
   If hr <> %S_OK Then Function = hr : Exit Function

   ' // Sets security levels on the proxy
   hr = CoSetProxyBlanket(pService, %RPC_C_AUTHN_WINNT, %RPC_C_AUTHZ_NONE, %Null, %RPC_C_AUTHN_LEVEL_CALL, %RPC_C_IMP_LEVEL_IMPERSONATE, %Null, %EOAC_NONE)
   If hr <> %S_OK Then Function = hr : Exit Function

   ' // Executes the query
   bstrLanguage = "WQL"
   bstrQuery = "SELECT Name,DeviceID FROM Win32_PnPEntity " 'where DeviceID like '%VID_04D8%'"
   hr = pService.ExecQuery(bstrLanguage, bstrQuery, %WBEM_FLAG_FORWARD_ONLY Or %WBEM_FLAG_RETURN_IMMEDIATELY, Nothing, pEnumClassObject)
   hr = pService.ExecQuery(bstrLanguage, bstrQuery, %WBEM_FLAG_FORWARD_ONLY Or %WBEM_FLAG_RETURN_IMMEDIATELY, Nothing, pEnumClassObject)
   ' // Iterate through the collection of objects
   Do
      ' // Retrieve a reference to the next object in the collection
      hr = pEnumClassObject.Next(%WBEM_INFINITE, 1, pClassObject, uReturned)
      If uReturned = 0 Then Exit Do
      ' // Retrieve the values of the properties
      hr = pClassObject.Get("Availability", 0, vAvailability, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("Caption", 0, vCaption, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("ClassGuid", 0, vClassGuid, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("CompatibleID", 0, vCompatibleID, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("ConfigManagerErrorCode", 0, vConfigManagerErrorCode, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("ConfigManagerUserConfig", 0, vConfigManagerUserConfig, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("CreationClassName", 0, vCreationClassName, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("Description", 0, vDescription, ByVal %Null, ByVal %Null)
 
      hr = pClassObject.Get("DeviceID", 0, vDeviceID, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("ErrorCleared", 0, vErrorCleared, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("ErrorDescription", 0, vErrorDescription, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("HardwareID", 0, vHardwareID, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("InstallDate", 0, vInstallDate, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("LastErrorCode", 0, vLastErrorCode, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("Manufacturer", 0, vManufacturer, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("Name", 0, vName, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("PNPDeviceID", 0, vPNPDeviceID, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("PowerManagementCapabilities", 0, vPowerManagementCapabilities, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("PowerManagementSupported", 0, vPowerManagementSupported, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("Service", 0, vService, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("Status", 0, vStatus, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("StatusInfo", 0, vStatusInfo, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("SystemCreationClassName", 0, vSystemCreationClassName, ByVal %Null, ByVal %Null)
      hr = pClassObject.Get("SystemName", 0, vSystemName, ByVal %Null, ByVal %Null)           
      Local sPorts As String
 '     If Left$(Variant$(vCaption),30)="Standard Serial over Bluetooth" Then sPorts += Variant$(vCaption)  & $Cr

       If InStr(Variant$(vName) & "  "  & Variant$(vDeviceID), "VID_04D8")>0 Then MsgBox _     '  <--------- Replace the 4 Hex digits with yours.
         Variant$(vName)  & "  " & Variant$(vDeviceID)


      ' // Release the object
      pClassObject = Nothing
   Loop
   
   ' // Release the enumerator
   pEnumClassObject = Nothing
   ' // Release the service
   pService = Nothing
   ' // Release the locator
   pLocator = Nothing

End Function
' ========================================================================================

' ========================================================================================
' Main
' ========================================================================================
Function PBMain

   WMI_Win32_PnPEntity

End Function
' ========================================================================================

How I found my device:
In device manager, look at the Keyboards.  I had two HID Keyboards. It wasn't hard to figure out which one I was looking for.
On the Details tab of the device properties, select Hardware Ids in the Property dropdown.  I copied the VID (vendor ID) and pasted it in my code mentioned above.
Compile and run it.  I get two msgboxes pop up when my device is plugged in.  None when it is not.

You can cut most of the code out of that but I left it to let you see what it looks like right out of WMIGenX.  The vName field won't be needed, but it lets you know the entry you are looking at is for a Keyboard.

I don't know if you are versed in SQL, but you can also leave off the "If" part of the Msgbox if you delete the   " ' (DQ SQ)  in the Select statement so that the Where statement is included in the query.

Let me know if you need further assistance because I didn't spend too much time putting this together for you.  It's kind of sloppy.

David

BTW The PNPEntity was the best template for you because it deals with devices that can come and go.  Somewhere in there we could find the name displayed in the screen capture you showed.  Not sure that you need it, because you can detect if it's present with this code.  I didn't go into how to use WMIGenX, it took a while to figure it out.  Feel free to ask more about it if you need more info.  I'll help where I can.
« Last Edit: November 30, 2018, 07:24:28 AM by David Kenny »
Logged

Josť Roca

  • Guru Member
  • *****
  • Posts: 3205
Re: Works with PowerBASIC but not with FireFly
« Reply #6 on: November 30, 2018, 06:13:20 AM »

There are two versions: WMIGEN and WMIGENX.

See: http://www.jose.it-berater.org/smfforum/index.php?board=395.0

The code generated by WMIGEN is somewhat easier to understand to PowwrBasic users because it allows the use of monikers, like VBScript.
« Last Edit: November 30, 2018, 08:32:00 AM by Josť Roca »
Logged

David Kenny

  • Senior Member
  • ***
  • Posts: 457
  • Windows 7 & 10
Re: Works with PowerBASIC but not with FireFly
« Reply #7 on: November 30, 2018, 07:22:22 AM »

I'll have to take a look at it... not sure why I decided on WMIGENX.  It's been a while.  Great tool though, and thanks for all the great work you do!
Logged