February 26th, 2007

more automation

At work we have some frequently-used web forms that accept telephone numbers. They're arranged as a set of three inputs:

Unfortunately, that makes it pretty hard to cut & paste a phone number out of email, from a web page, etc. into the form. So I put together a small bit of CLX that fetches the current selection as a string, does some pattern matching and text extraction, and launches a browser tab with the form pre-filled with the right number. Here's a short useful bit from it:

(defpackage #:cliptricks
  (:use #:cl #:xlib)
  (:export #:current-selection))

(in-package #:cliptricks)

(defmacro with-display ((display) &body body)
  `(let ((,display))
     (unwind-protect
          (progn
            (setf ,display (open-default-display))
            ,@body)
       (when ,display
         (close-display ,display)))))
                 
(defun selection-to-text (selection)
  (let ((octets (make-array (length selection)
                            :element-type '(unsigned-byte 8)
                            :initial-contents selection)))
    (ignore-errors (sb-ext:octets-to-string octets))))

(defun current-selection ()
  "Return the current X selection as a string, or NIL if no selection is
   active."
  (with-display (display)
    (let* ((screen (display-default-screen display))
           (root (screen-root screen))
           (window (create-window :parent root
                                  :width 1 :height 1
                                  :x 0 :y 0)))
      (change-property window :selection-target "" :string 8)
      (convert-selection :primary :utf8_string window :selection-target)
      (event-case (display :timeout 1 :discard-p t :force-output-p t)
        (:selection-notify
         (property)
         (when property
           (selection-to-text (get-property window property
                               :result-type 'vector
                               :delete-p t))))))))