Playing with Hammerspoon

I started using Hammerspoon recently. My keyboard remapping of CAPS LOCK to Ctrl when pressing and Esc when tapping had stopped working after upgrading to macOS Sierra. Turns out the current version of Karabiner doesn't work with Sierra (Oct-2016).

After finding out I could emulate the same behavior with Hammerspoon thanks to this gist, I gave it a try to see what else it could do. That's how I ended up writing the following Lua utility.

The idea is to provide an easy way of showing keystrokes on the screen. It's inspired by other tools like Keycastr which for some reason I couldn't get to work.

function showKeyPress(tap_event)
  local duration = 1.5  -- popup duration
  local modifiers = ""  -- key modifiers string representation
  local flags = tap_event:getFlags()
  local character = hs.keycodes.map[tap_event:getKeyCode()]
  -- we only want to read special characters via getKeyCode, so we
  -- use this subset of hs.keycodes.map
  local special_chars = {
    ["f1"] = true, ["f2"] = true, ["f3"] = true, ["f4"] = true,
    ["f5"] = true, ["f6"] = true, ["f7"] = true, ["f8"] = true,
    ["f9"] = true, ["f10"] = true, ["f11"] = true, ["f12"] = true,
    ["f13"] = true, ["f14"] = true, ["f15"] = true, ["f16"] = true,
    ["f17"] = true, ["f18"] = true, ["f19"] = true, ["f20"] = true,
    ["pad"] = true, ["pad*"] = true, ["pad+"] = true, ["pad/"] = true,
    ["pad-"] = true, ["pad="] = true, ["pad0"] = true, ["pad1"] = true,
    ["pad2"] = true, ["pad3"] = true, ["pad4"] = true, ["pad5"] = true,
    ["pad6"] = true, ["pad7"] = true, ["pad8"] = true, ["pad9"] = true,
    ["padclear"] = true, ["padenter"] = true, ["return"] = true,
    ["tab"] = true, ["space"] = true, ["delete"] = true, ["escape"] = true,
    ["help"] = true, ["home"] = true, ["pageup"] = true,
    ["forwarddelete"] = true, ["end"] = true, ["pagedown"] = true,
    ["left"] = true, ["right"] = true, ["down"] = true, ["up"] = true
  }

  -- if we have a simple character (no modifiers), we want a shorter
  -- popup duration.
  if (not flags.shift and not flags.cmd and
        not flags.alt and not flags.ctrl) then
    duration = 0.3
  end

  -- we want to get regular characters via getCharacters as it
  -- "cleans" the key for us (e.g. for a "⇧-5" keypress we want
  -- to show "⇧-%").
  if special_chars[character] == nil then
    character = tap_event:getCharacters(true)
    if flags.shift then
      character = string.lower(character)
    end
  end

  -- make some known special characters look good
  if character == "return" then
    character = "⏎"
  elseif character == "delete" then
    character = "⌫"
  elseif character == "escape" then
    character = "⎋"
  elseif character == "space" then
    character = "SPC"
  elseif character == "up" then
    character = "↑"
  elseif character == "down" then
    character = "↓"
  elseif character == "left" then
    character = "←"
  elseif character == "right" then
    character = "→"
  end

  -- get modifiers' string representation
  if flags.ctrl then
    modifiers = modifiers .. "C-"
  end
  if flags.cmd then
    modifiers = modifiers .. "⌘-"
  end
  if flags.shift then
    modifiers = modifiers .. "⇧-"
  end
  if flags.alt then
    modifiers = modifiers .. "⌥-"
  end

  -- actually show the popup
  hs.alert.show(modifiers .. character, duration)

end


local key_tap = hs.eventtap.new(
  {hs.eventtap.event.types.keyDown},
  showKeyPress
)

-- Enable/Disable Keypress Show Mode with "C-⌘-⇧-p"
k = hs.hotkey.modal.new({"cmd", "shift", "ctrl"}, 'P')
function k:entered()
  hs.alert.show("Enabling Keypress Show Mode", 1.5)
  key_tap:start()
end
function k:exited()
  hs.alert.show("Disabling Keypress Show Mode", 1.5)
end
k:bind({"cmd", "shift", "ctrl"}, 'P', function()
    key_tap:stop()
    k:exit()
end)

Currently it looks like this:

how the keystroke utility looks

As far as I know, there's currently no way of setting the popup position on the screen, so it always appears on the middle. Even so, I'm pretty happy I gave Hammerspoon a try and hope I can come up with other useful hacks.

TIL: You can identify the hostname in an HTTPS request

Today I was talking to someone that said they were blocking HTTPS traffic in a transparent proxy setup. That is, they were blocking specific domains.

I know this can be done by using a certificate in the intercepting device which is trusted by the client (i.e. decrypting the traffic) or by blocking a specific IP range.

However this got me curious if it was possible to get the hostname from an encrypted connection.

A quick google search led me to this.

Turns out the client sends the hostname as part of the ClientHello message during the TLS handshake!

I tried this out by connecting to this site, and there it was.

$ tshark -i en0 -x -O TLSv1.2
...
c0 09 c0 13 00 33 00 9c 00 35 00 2f 00 0a 01 00   .....3...5./....
01 95 ff 01 00 01 00 00 00 00 11 00 0f 00 00 0c   ................
6b 69 72 62 75 63 68 69 2e 63 6f 6d 00 17 00 00   kirbuchi.com....
00 23 00 b0 b7 5f 38 49 97 05 5d 33 b6 51 a3 0d   .#..._8I..]3.Q..
df ea b2 60 12 ee b3 5b 21 4e f1 7a 0e 4f 95 7c   ...`...[!N.z.O.|
...

And of course, it's in the certificate reply as well!

2e 6c 65 74 73 65 6e 63 72 79 70 74 2e 6f 72 67   .letsencrypt.org
2f 30 29 06 03 55 1d 11 04 22 30 20 82 0c 6b 69   /0)..U..."0 ..ki
72 62 75 63 68 69 2e 63 6f 6d 82 10 77 77 77 2e   rbuchi.com..www.
6b 69 72 62 75 63 68 69 2e 63 6f 6d 30 81 fe 06   kirbuchi.com0...
03 55 1d 20 04 81 f6 30 81 f3 30 08 06 06 67 81   .U. ...0..0...g.
0c 01 02 01 30 81 e6 06 0b 2b 06 01 04 01 82 df   ....0....+......
13 01 01 01 30 81 d6 30 26 06 08 2b 06 01 05 05   ....0..0&..+....

Sources

Quickly jumping between buffers in Spacemacs

If you're using Spacemacs and want it to behave like other applications in which you can jump around tabs by pressing ⌘-<tab number> (or C-<tab-number>) you can add the following to your .spacemacs under dotspacemacs/config:

(defun dotspacemacs/config ()
  ;; ...
  (global-set-key (kbd "s-1") 'select-window-1)
  (global-set-key (kbd "s-2") 'select-window-2)
  (global-set-key (kbd "s-3") 'select-window-3)
  (global-set-key (kbd "s-4") 'select-window-4)
  (global-set-key (kbd "s-5") 'select-window-5)
  (global-set-key (kbd "s-6") 'select-window-6)
  (global-set-key (kbd "s-7") 'select-window-7)
  (global-set-key (kbd "s-8") 'select-window-8)
  (global-set-key (kbd "s-9") 'select-window-9)
  ;; ...
)

If you're not on OSX I guess the equivalent would be (kbd "C-X") to use Control instead of ⌘.

It seems like a silly thing, but if you use Emacs all day long it goes a long way as I find it a little faster and more intuitive than the default SPC-<buffer-number> (which only works in normal mode).

Emacs: Cycling through workspaces in perspective mode

About two days ago, one of my coworkers who started using emacs around the same time as I did and who comes from a similar vim setup as mine, introduced me to perspective.el.

From the docs:

perspective.el provides multiple workspaces (or "perspectives") for each Emacs frame. This makes it easy to work on many separate projects without getting lost in all the buffers.

Since I inmediatly found it so convenient I wanted to make it faster to switch between perspectives by setting up a keybinding for it. Sadly, the provided way to do it was to use the persp-next function which has the drawback of prompting for a name when you've reached the last perspective. So I went and checked how persp-next works and found this, which is pretty straightforward:

(defun persp-next ()
  "Switch to next perspective (to the right)."
  (interactive)
  (persp-switch (nth (1+ (persp-curr-position))
                     (persp-all-names))))

It showed me that a) (persp-all-names) returns the list of all the available perspectives and b) I can call persp-switch with the name of the perspective I want to go to as an argument. With that in mind, I wrote this little function that makes perspective cycling behave the way I want.

(defun persp-cycle ()
  "Cycle throught the available perspectives."
  (interactive)
  (let ((next-pos (1+ (persp-curr-position)))
        (list-size (length (persp-all-names))))
  (cond ((eq 1 list-size) (persp-switch nil))
         ((>= next-pos list-size) (persp-switch (nth 0 (persp-all-names))))
         (t (persp-next)))))

When there are no other perspectives besides the current one, it'll prompt you for a name. Else, it'll just jump to the next perspective and go back to the first one after reaching the end of the list.

Using the Arduino Mega 2560 as a regular MCU with avrdude

There's a number of reason why you'd want to program your Arduino device as a regular AVR MCU. For me it was having to do some tests I'd later have to run on a normal AVR board and only having an Arduino board available. Turns out the built-in STK500 ISP on the Mega 2560 is supported by avrdude.

The whole compiling/flashing shebang can be done with the following Makefile (slightly modified from the one found here).

You'll probably have to modify the DEVICE variable if you're using something other than OSX and the SOURCES one if you're using C++ instead of C.

NAME := main
HEX := $(NAME).hex
OUT := $(NAME).out
MAP := $(NAME).map
SOURCES := $(wildcard *.c)
HEADERS := $(wildcard *.h)
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))

MCU := atmega2560
MCU_AVRDUDE := m2560
PARTNO := stk500v2
DEVICE := /dev/tty.usbmodem*
BAUDRATE := 115200
AVRDUDE_FLAGS := -F -V -D -v

CC := avr-gcc
OBJCOPY := avr-objcopy
SIZE := avr-size -A

CFLAGS := -Wall -pedantic -mmcu=$(MCU) -std=c99 -g -Os -DF_CPU=16000000UL

all: $(HEX)

clean:
    rm -f $(HEX) $(OUT) $(MAP) $(OBJECTS)

flash: $(HEX)
    avrdude $(AVRDUDE_FLAGS) -c $(PARTNO) -p $(MCU_AVRDUDE) -P $(DEVICE) -b $(BAUDRATE) -U flash:w:$(HEX)

$(HEX): $(OUT)
    $(OBJCOPY) -R .eeprom -O ihex $< $@

$(OUT): $(OBJECTS)
    $(CC) $(CFLAGS) -o $@ -Wl,-Map,$(MAP) $^
    @echo
    @$(SIZE) $@
    @echo

%.o: %.c $(HEADERS)
    $(CC) $(CFLAGS) -c -o $@ $<

%.pp: %.c
    $(CC) $(CFLAGS) -E -o $@ $<

%.ppo: %.c
    $(CC) $(CFLAGS) -E $<

With the Makefile in the same folder as your main.c just run:

make
make flash

And you should have you program running in the Arduino.

To know the pin mappings from the board to the actual ATMega2560 pins, you can check this useful resource.