auto identification of connected printer (Mac)

Peter Brigham MD pmbrig at gmail.com
Thu Oct 28 12:21:46 EDT 2010


In case anyone else would find it useful, I've finally managed to tune  
up my handlers for LiveCode printing from a Mac laptop, designed to  
avoid any unnecessary printing dialogs. This is useful if you, like  
me, use a LiveCode app on your laptop in a number of different venues  
and need to print using the currently connected printer. I got annoyed  
that every time I switched venues I had to tell the system what  
printer to use (I do a lot of printing of patient notes,  
prescriptions, etc.). The system knows what's connected, right? So if  
I have one and only one printer connected why should it have to ask me  
to choose my printer?

The set of handlers below will detect the currently available printer,  
whether connected by USB or on a wireless network, and automatically  
send the print job to that printer (if I'm printing from a LiveCode  
script).

The way it works is this -- the IO registry is queried with a shell  
call and the result is parsed to identify USB-connected printers (not  
a foolproof algorithm, but seems to work so far). If the IOR listing  
is already associated with a printer name then that printer is used,  
all done. If no printer name has been associated with the IOR listing  
then the user is asked to identify the printer to be used and the IOR  
listing / printerName association is stored as a custom prop, so that  
thereafter it will be used automatically.

If there are no USB printers identified, a shell call fetches the MAC  
address of any wireless network you are connected to. If none, then  
the user gets "not connected to any printer," and printing is aborted.  
Otherwise, the user is asked once, as above, to identify the printer  
on that network, and the MAC address / printerName association is  
stored for future use.

To use, just call "checkPrinter" before any printing command in  
LiveCode, and everything else is taken care of. Should work on Mac  
laptops. Sorry, I don't have a Windows or Linux laptop to develop the  
corresponding routines on for the other OSes, but that should be do- 
able for anyone with the need.

Thanks to the dozen or more members of this list that have helped me  
with ideas, shell calls, etc. I absolutely could not have done it  
without you.

-- Peter

Peter M. Brigham
pmbrig at gmail.com
http://home.comcast.net/~pmbrig

-----------------

constant storageStack = "<yourStackNameHere>"
-- the short name of the stack that stores the customprops for the  
printer names

on checkPrinter printingWhat
    if the controlkey is down then
       -- bypass the routines entirely
       answer printer
       exit checkPrinter
    end if
    -- get listing of connected printer in IO registry, and MAC  
address for wireless
    put getActivePrinter() into tLivePrinterInIOR
    put sr(tLivePrinterInIOR) into tLivePrinterInIOR
    put tLivePrinterInIOR into IORrawPrinterList
    put the printername into origPrinterName
    put getWirelessMACaddress() into MACaddr

    if tLivePrinterInIOR = empty then
       -- no USB printer detected
       if MACaddr = empty then
          put "You are not connected to any active printer. Please  
check that" && \
                 "your printer is turned on and connected properly."  
into cmt
          answer cmt as sheet
          exit to top -- abort printing
       else -- connected to a network
          put the MACaddrToPrinterName[MACaddr] of stack storageStack  
into tLivePrinterName
          if tLivePrinterName <> empty then
             set the printername to tPossiblePrinterName
          else
             put "Please choose the wireless printer on this network"  
&& \
                    "so it can be identified in the future." into cmt
             answer cmt as sheet
             set the systemprintselector to true
             answer printer
             -- sets the printername (used by Rev for printing)
             if the result = "cancel" then exit to top
             -- abort printing
             put the printername into tPrinterName
             set the MACaddrToPrinterName[MACaddr] of stack  
storageStack to tPrinterName
             -- store printer name for this device
          end if
          exit checkPrinter -- proceed to printing
       end if
    end if

    -- the following is when there is a possible USB printer and no  
wireless printer

    -- more than one device might be a printer
    -- but we might know this printer already
    repeat for each line p in tLivePrinterInIOR
       put the IORtoPrinterName[p] of stack "PDdata" into  
tPossiblePrinterName
       if tPossiblePrinterName <> empty then
          -- found a known printer, set it, then done
          set the printername to tPossiblePrinterName
          exit checkPrinter -- proceed to printing
       end if
    end repeat
    -- no known printers found,
    -- ask user to sort it out
    -- have to construct answer dialog
    -- with buttons for each device
    if the number of lines of tLivePrinterInIOR > 1 then
       put q("cancel") into btnList
       repeat for each line p in tLivePrinterInIOR
          put q(truncate(p,18)) into btnName
          put q(truncate(p,35)) into promptLine
          put " and " & btnName after btnList
          put " & cr &" && promptLine after promptList
       end repeat
       put "There are several USB devices currently connected. Please  
identify the" \
              && "one that is the printer so it will be recognized in  
the future:" \
              & quote & promptList into theDo
       put "answer" && quote before theDo
       put " with" && btnList && "as sheet" after theDo
       do theDo
       put it into whichDevice
       if whichDevice = "cancel" then exit to top
       if char -1 of whichDevice = "…" then delete char -1 of  
whichDevice
       put lineoffsets(whichDevice,tLivePrinterInIOR) into pOffset
       if the number of items of pOffset > 1 then
         answer "Having difficulty identifying your printer. Please  
unplug" \
                 && "all USB devices except the active printer and try  
printing again." \
                 as sheet
          exit to top
       else
          put line pOffset of tLivePrinterInIOR into tLivePrinterInIOR
       end if
    end if
    -- now tLivePrinterInIOR contains one line
    put the IORtoPrinterName[tLivePrinterInIOR] of stack "PDdata" into  
tLivePrinterName
    -- system prefs name of currently live printer,
    -- stored when printer first encountered
    if origPrinterName = tLivePrinterName and origPrinterName <> empty  
then
       -- currently connected to the chosen printer,
       -- proceed to printing
       exit checkPrinter
    end if
    -- else:
    if tLivePrinterName = empty then
       -- never seen this printer
       setupicons
       put "Please choose the current printer (" & tLivePrinterInIOR & \
              ") so it can be identified in the future." into cmt
       answer cmt as sheet
       set the systemprintselector to true
       answer printer
       -- sets the printername (used by Rev for printing)
       if the result = "cancel" then exit to top
       -- abort printing
       put the printername into tPrinterName
       set the IORtoPrinterName[tLivePrinterInIOR] of stack  
storageStack to tPrinterName
       -- store printer name for this device
    else if tCurrentRevPrinterName <> tLivePrinterName then
       -- a different known printer is currently live, just tell Rev  
to use it
      set the printername to tLivePrinterName
    end if
end checkPrinter

function getUSBdevices
    --  returns list of currently connected USB devices
    --  with tab-indented list of properties for each

    -- get USB device info from system profiler
    set the hideconsolewindows to true
    put shell("system_profiler -detailLevel full SPUSBDataType") into  
tData

    -- convert data to one line per USB device
    replace (colon & cr & cr) with numToChar(245) in tData -- device  
name
    replace (cr & cr) with numtoChar(250) in tData
    replace cr with tab in tData
    replace numtoChar(245) with (colon & tab) in tData
    replace numtoChar(250) with cr in tData
    replace tab with cr & tab in tData
    repeat until cr & space is not in tData
       replace cr & space with cr in tData
    end repeat
    repeat until tab & space is not in tData
       replace tab & space with tab in tData
    end repeat
    delete word 1 of tData
    return tData
end getUSBdevices

function getWirelessMACaddress
    put shell("cd /usr/sbin;system_profiler SPNetworkDataType  
#####REVEXCLUDEDSTRING#####grep -i signature") into s
    set the itemdel to "="
    put line 1 of (item -1 of s) into tMAC
    return tMAC
end getWirelessMACaddress

function getActivePrinter
    set the hideconsolewindows to true
    put shell("ioreg") into tList
    filter tList with "*<class IOUSBDevice*"
    filter tList without "*UserClient*"
    filter tList without "*Keyboard*"
    filter tList without "* IR *"
    filter tList without "*Wireless*"
    filter tList without "*mouse*"
    filter tList without "*iSight*"
    filter tList without "*Store 'n' Go*"
    filter tList without "*iPhone*"

    -- more filtering needed for other devices?

    filter tList without empty
    repeat for each line d in tList
       -- could be more than one
       put offset("+-o",d)+4 into startChar
       put offset("@",d)-1 into endChar
       put (char startChar to endChar of d) & cr after printerList
    end repeat
    delete char -1 of printerList
    return printerList
end getActivePrinter

function sr str
    -- strips white space fore and aft
    return word 1 to -1 of str
end sr

function q str
    return quote & str & quote
end q

function truncate str, n
    -- returns a string of at most n chars
    if length(str) <= n then return str
    return char 1 to n-1 of str & "…" -- ellipsis
end truncate

function offsets str,ctr
    -- returns a comma-delimited list of all the offsets of str in ctr
    put "" into mosList
    put 0 into startPoint
    repeat
       put offset(str,ctr,startPoint) into os
       if os = 0 then exit repeat
       add os to startPoint
       put startPoint & "," after mosList
    end repeat
    if char -1 of mosList = "," then delete last char of mosList
    if mosList = "" then return "0"
    return mosList
end offsets

function lineOffsets str,ctr
    -- returns a comma-delimited list of all the lineoffsets of str in  
ctr
    put offsets(str,ctr) into charList
    if charList = "0" then return "0"
    put the number of items of charList into nbr
    put "" into mlo
    repeat for each item n in charList
       put the number of lines of (char 1 to n of ctr) & "," after mlo
    end repeat
    if char -1 of mlo = "," then delete char -1 of mlo
    return mlo
end lineOffsets




More information about the use-livecode mailing list