[HN Gopher] Buttons as Finite Automata
___________________________________________________________________
Buttons as Finite Automata
Author : picture
Score : 161 points
Date : 2022-03-23 05:44 UTC (1 days ago)
(HTM) web link (web.stanford.edu)
(TXT) w3m dump (web.stanford.edu)
| paxys wrote:
| I don't believe a two-state button is standard HTML.
| FabHK wrote:
| Not sure what you mean.
|
| I've played with some buttons that struck me as fairly standard
| and found that they have exactly the semantics implemented here
| (to fire, you need to press down inside the button area, hold
| down (leaving the area or not), and release inside the area).
| paxys wrote:
| Buttons can't remember their state. The "fire" circle
| shouldn't exist, and after you click and release, it should
| go back to idle up or hover.
|
| This diagram is showing more checkbox behavior rather than
| button.
| kmill wrote:
| Ah, for illustration purposes this is showing a "one-shot"
| button. Notice the "fire" state is a double circle -- this
| means that it's a terminal state for the state machine,
| meaning the state machine is "done" once it enters that. In
| practice, the fire state would be wired up to the start
| state of another state machine, which would be wired up to
| the start state of the button machine to get things going
| again. The "Click to Reset", notice, isn't part of the
| state machine itself, and instead it's modeling the stuff
| that happens between firing and transitioning back through
| "start."
|
| A button that has no "on click," so to speak, could be
| represented by having the fire state transition immediately
| back through "start."
| robinhouston wrote:
| This is fun. Now I'm wondering what it looks like as a regular
| expression.
|
| Here's my first attempt. (Probably wrong, since I did it by
| hand.) (enter,leave,|press,(enter,leave,)*release
| ,|press,enter,release,leave,|enter,press,leave,(enter,leave,)*rel
| ease,)*(enter|press,enter,(leave,enter,)*release),press,(leave,en
| ter,)*,release
|
| I'd never really thought about how many different sequences of
| events can lead to a button activating.
| lowbloodsugar wrote:
| Bug on safari 15.4: release from 'hover, pressed' didn't go to
| hover, and instead went to 'idle,up'. Also, love FSMs.
| blamestross wrote:
| Its all fun and games until somebody managed to click on your
| button without hovering first.
| progval wrote:
| I see two ways to do that:
|
| 1. keyboard navigation (Enter and space are ignored)
|
| 2. hover, then F5 to reload the page (this resets the state,
| and you get your cursor on the button without a state
| transition)
|
| presses are completely ignored either way
| [deleted]
| topspin wrote:
| 3. $('#ohhai').click()
| crate_barre wrote:
| So, any browser testing suites/runners :p
| khafra wrote:
| One place you'll see this in real life is modded flashlights,
| running Anduril. My friend has an absurdly powerful light with 1
| button and 20 modes: https://budgetlightforum.com/node/38364
| caseyross wrote:
| What's also interesting to realize is that the standard HTML
| button is a sort of unholy chimera that doesn't model any sort of
| physical button in common usage.
|
| Physically speaking, we generally have either:
|
| 1. a "push" button, which activates when you press it down fully,
| or
|
| 2. a "hold" button, which activates continuously when you hold it
| down.
|
| In either case, the "action" occurs at the instant you press the
| button down, and perhaps continues until you let go.
|
| But the standard HTML button works differently, and from a
| physical perspective, quite weirdly: when you press it, it only
| gets "cocked", and when you _release_ it, it activates. That 's
| why its state representation feels complex and unintuitive!
|
| Rather than the behavior of a "push" or "hold" button, the
| standard HTML button behavior is more like extracting an SD card:
| you press the card in and then release it to get it out.
|
| (I'm sure there are physical buttons out there _somewhere_ that
| activate on release. And you can also make a great model of a
| "push" or "hold" button with custom JS. But I think it's fair to
| say that the default HTML button doesn't work like real-world
| experience would lead anyone to expect.)
| ynx wrote:
| To be fair, it's not just HTML, "Touch Up Inside" is the usual
| button press event to subscribe to on iOS/macOS, and to my
| personal knowledge this has been true on iOS from day 1 (unsure
| about macOS or at least NeXTSTeP), so there is an argument that
| it is at least somewhat normalized, though your point about it
| not matching up with most IRL buttons makes sense.
|
| However it's also worth noting that IRL buttons tend to require
| more than a feather's touch to detect a press, whereas there is
| no such margin on monitors/pointing devices.
| nikivi wrote:
| XState is useful for modelling these interactions.
|
| https://xstate.js.org
| gentleman11 wrote:
| The visualizer on mobile has issues, I'll try it on desktop
| later. Thanks for sharing
| htiek wrote:
| This is something I created many, many years back for Stanford's
| CS103 course as a lecture demo. Apologies for the lack of mobile
| support - I've always presented this from my laptop. :-)
| SeanLuke wrote:
| There appears to be a mistake in the automaton diagram (not
| operation). The start state is "Idle, Up", and assumes the
| mouse is presently outside the button. But after doing "Click
| to Reset", you're already inside the button and so cannot enter
| it. Thus you should actually, and unfortunately, be in "Idle,
| Up". The demonstration gets around this by magically jumping to
| "hover", but this violates the whole educational point of what
| a start state is.
|
| I know this is nitpicky, and yes, I see that "fire!" is an
| accepting state, but maybe you could have a special transition
| from "fire!" to "hover" labelled "reset".
| ______-_-______ wrote:
| Just think of it as throwing the old button away and buying a
| new one. Buttons come idle from the factory. Once the old
| button is hauled away and the new one is installed under
| where your cursor happens to be, it transitions to hover.
| jmull wrote:
| Well...
|
| You've made a couple mistakes here.
|
| 1. You've made the unfounded leap that the diagram intends to
| represent state after the button has fired. That's manifestly
| incorrect.
|
| 2. You've made the incorrect assumption that a full reset of
| the diagram is accomplished by clicking the button. But
| that's not what it says. Obviously, you also need to move the
| mouse out of the button to return to the start state. So you
| could criticized this for incomplete instruction, however,
| since the context is a demo for a college course, omitting
| over-instruction of obvious and irrelevant details is most
| likely the best decision to reach the overall instructional
| goal.
|
| If you want to be pedantic on the internet, you need to go a
| bit deeper than that. ;-)
| FabHK wrote:
| Beautiful.
|
| Small suggestion for improvement: There are really two boolean
| variables (inside the button area, or not; mouse button down,
| or not). They give rise to more than 4 states because the order
| of actions is important.
|
| But the diagram might be made more intuitive by placing the
| states within a 2x2 chess board corresponding to in/out,
| up/down. Not much change is necessary (for example: shift "held
| outside" left, "pressed" down, and "fire" up).
| picture wrote:
| Woah. This is what I find seriously cool about HN. Was
| searching around for "push button+state machine" the other day
| to learn how to program some menus with a microcontroller, and
| came across this. It's a really neat visualization, thanks for
| your work years ago!
| falcolas wrote:
| Right click locks you in the "press" state, just so you know.
| DaiPlusPlus wrote:
| No repro here (Chrome 99 on Windows): right-clicking the
| button works the same as left-clicking it (yes, there's my
| browser's context-menu, but it doesn't seem to interfere with
| the webpage's logic at my end).
| falcolas wrote:
| Safari on a mac. The context menu pulls up, but even when
| dismissed, it's still stuck in the "idle, down" state.
| scndrycntct wrote:
| Repro's on Chrome/Mac as well--I think it's a macOS
| issue.
| squeaky-clean wrote:
| On Chrome on Mac I get the same, and right clicking outside
| the button makes it stick in the (idle, down) state,
| hovering makes it move between (hover, pressed) and (idle,
| down).
|
| Still a crazy cool demo though. Having worked on ui for my
| hobby games, I always knew it was more complex than just
| onClick, but this makes me understand it perfectly. I'm
| probably going to implement a model based on this in my
| current project.
| zanethomas wrote:
| nice! how about something like that for drag/drop? anyone? :)
| mbildner wrote:
| an oldie but a goodie: https://www.quirksmode.org/blog/archiv
| es/2009/09/the_html5_d...
| gumby wrote:
| What I love about this is back in the archaic days when car
| radios had (mechanical) radio buttons, that was the introductory
| example of a tiny state machine. They were also used in other
| devices but the car radio was the application _everybody_ had
| seen.
|
| Nowadays I imagine only a small proportion of people who deploy
| "radio buttons" have even seen such a car radio, so the metaphor
| is now empty, like the floppy disk icon for "save".
| ______-_-______ wrote:
| Random question, were physical radio buttons ever circular, or
| are they circular on computers only to differentiate from a
| check box? I've only ever seen rectangular radio buttons IRL,
| and a quick image search seems to agree.
|
| https://www.knowahead.in/wp-content/uploads/2012/05/car-radi...
|
| https://41.media.tumblr.com/tumblr_mbyb9qOw8H1rg5mmto1_1280....
|
| https://i.pinimg.com/originals/10/d6/86/10d686376ae39772ac4e...
| gumby wrote:
| I only remember rectangular ones on actual car radios, but on
| other apparatus they were mostly circular.
|
| Basically a "radio button" interface is a mechanical XOR. So
| for example to route a signal to destination A, B, or C you'd
| want to push the A button and be sure B and C weren't
| selected. Often it mechanically latched, so you could also
| see at a glance which option was selected, rather than
| needing to have an indicator (typically a small incandescent
| bulb).
|
| Radios themselves implemented that mechanism slightly
| differently. Each button had a stop (like a tab stop, not an
| organ stop). When you pushed the button it disabled all the
| other stops and then either a spring pulled the arm _right_
| to the stop or your own muscle power pulled it _left_. A
| pully rotated the tuner dial as the arm moved right or left.
| I believe the buttons were rectangular in order to have
| enough surface area for your finger to supply a firm press
| enough to pull the tuner arm all the way from right to left
| (the extrama case). If they 'd been round they would have
| taken up too much vertical space.
|
| The radios typically had five or six favorites, no more. The
| entire mechanism was mechanical.
| leephillips wrote:
| I don't see how to enter the two states at the bottom left (idle,
| down and hover, pressed). I can't press without first hovering.
| Those two states seem to be inaccessible.
| feoren wrote:
| Click/hold the mouse while outside of the button. Middle-bottom
| state is hovering over the button while your mouse is down,
| without having clicked the button. I can see that being useful.
| However, I can't see why the bottom-left state is ever useful,
| except perhaps as the only way to get to the "hover, pressed"
| state.
| FabHK wrote:
| It is useful because you don't want to fire when you click
| and hold outside the button, then enter the button area, then
| release. So, when you release inside the button, you must
| know whether you clicked inside or outside the button. Thus
| you need those states. I think.
| tonyarkles wrote:
| If you imagine DOM elements as each having a separate FSM
| and if you consider the possibility of entry/exit actions
| on each state, "idle, down" in the bottom left could have
| an entry action that primes the system for drag & drop.
| Click down outside, release inside is exactly what D&D
| would have.
| budadre75 wrote:
| you click anywhere else on the webpage
| cylon13 wrote:
| I am able to enter "idle, down" on chromium on linux by
| clicking and holding the very edge of the button.
| leephillips wrote:
| Oh, how silly of me. I can enter that state by clicking
| anywhere outside the button (Vivaldi (basically Chrome) on
| Debian).
| jibbit wrote:
| it was a long time ago, but there used to be a model of the state
| machine for selecting a file in the mac os9 Finder that was often
| shared (yes i'm talking about around the time that OS9 was
| current). I don't suppose anyone remembers that? I'd love to see
| it again
| Animats wrote:
| Now add double-click.
| leggomuhgreggo wrote:
| Nice!
|
| It's funny that buttons are the "Hello World" of frontend
| components, because they're actually feverishly nuanced.
|
| I wrote a proof of concept for one of these, using XState, a few
| months back.
|
| My use case was a cross platform react native button -- which
| means there's technically a difference between "pressed" and
| "hover" -- and there's also a loading state, which required
| special handling for the a11y state.
|
| https://codesandbox.io/s/fervent-shirley-dgesq?file=/src/Pre...
|
| NOTE: this will open a popup (might have to enable popups) with
| the visualizer, and it defaults to the a11y machine, but there's
| a drop down to switch to the main button machine.
| DaiPlusPlus wrote:
| Neat.
|
| ...how do I get the button into the "idle, down" state? (i.e. how
| do you press a button without first hovering over it? I tried
| with [Tab] and spacebar to activate it, but that didn't do
| anything).
|
| ------
|
| I'm thinking this page could likely be reimplemented without any
| JavaScript, using only CSS' interaction state pseudo-classes
| (`:active, :hover, :focus`, etc) as proxies for the button's
| state (with the sibling `~` selector to control the state-diagram
| image). Hmm, though the "held outside" state might be difficult
| (perhaps `body:hover button:not(:hover):active ~ #stateImage`
| would work for that?).
| evan_ wrote:
| > how do I get the button into the "idle, down" state?
|
| Click and hold outside of the button, and drag over it.
| randomcarbloke wrote:
| I figured this out too but I wonder if the button is strictly
| the fsm if the mouse state is also being tracked, in the
| example yes, if there was more than one button probably not...
| but the idea is brilliant and probably worth playing with.
| beaconstudios wrote:
| just hold down the mouse outside the button.
| DaiPlusPlus wrote:
| aaaahh! now I feel silly.
|
| However, the page shouldn't be doing that because the state
| of the <button> is not actually affected by the mouse-
| pointer's state, so that entire "idle, down" state node
| shouldn't be there at all (nor "hover, pressed", as browsers
| use the same `:hover:not(:active)` state for the <button> as
| "hover" in that situation).
| FabHK wrote:
| No, it needs to do that. When you click the mouse down
| outside the button, then enter the button area and release,
| you do not want to fire. So you need those extra states.
| DaiPlusPlus wrote:
| > When you click the mouse down outside the button, then
| enter the button area and release, you do not want to
| fire
|
| If you're referring to not wanting the `mouseup` event to
| fire, you are correct - however web-pages should not be
| using `mouseup` / `mousedown` to detect <button> clicks
| in the first place: they should be listening to only the
| `click` event, which is not raised when the user releases
| a held-down mouse button anyway. And the `click` event is
| also raised when the <button> is activated by other
| means, such as the spacebar which makes it more
| accessible too.
|
| When you have the page open, open your console and run
| this:
|
| `document.querySelector('input[type=button]').addEventLis
| tener('click', e => console.log("button 'click' event")
| )`
|
| and then do the mousedown-and-hover-and-release described
| and you won't see anything logged until you really do
| click on it.
| mirekrusin wrote:
| Seems broken when hovering and you start scrolling - it stays as
| hover state during scrolling when you're actually outside of
| button.
| zevv wrote:
| I am an embedded software engineer, and I love everything about
| this FSM example. It shows that seemingly simple and binary
| things often have more complexity then meets the eye. I love
| using old fashioned finite state machines for implementing all
| kinds of behavior; if forces you to think about every single
| state and transition, and it naturally isolates the different
| cases - basically, it makes it easier to think and talk about the
| implementation.
|
| Buttons get even more fun when you add a "long push" to it. I can
| not recall how often I have had discussions with customers about
| the intended behavior of physical buttons on devices; it takes
| some effort and patience to explain how requirements like
| "Perform action A when the button is pushed, or perform action B
| when the button is pushed for a 3 seconds" simply can not be
| implemented. "Oh, so you mean, perform action A when the button
| us released within 3 seconds?". "Well, no I want it do A when I
| _push_ the button ".
|
| And then I draw a little picture on the white board showing the
| circles and arrows.
| p1necone wrote:
| This isn't quite as impossible as you make it sound. You can
| certainly make it _feel_ like you have this behaviour by
| triggering A on release if the button is held for < ~300ms, or
| whatever feels right as a short press.
|
| Of course now you have to accept the button doing nothing if
| it's held for longer than 300ms but shorter than 3s, but making
| it slowly fill up with another colour or something is probably
| enough to communicate the long press behaviour.
| [deleted]
| agumonkey wrote:
| Been reading a few books about automaton (after going back into
| parsing) and it's indeed nice. There's something universal in
| them.
| atoav wrote:
| You: "So you want action A to happen immediately when the
| button is pushed _AND_ 3 seconds after that when the button is
| still held action B should happen? "
|
| Customer: "No, I _only_ want action B when it is held for 3
| seconds "
|
| You: "Todays technology can't do that"
|
| Customer: "What. Wait. Why?"
|
| You: "Because at the point when action A would be triggered we
| would have to know the future to tell whether the button will
| have been held for 3 seconds or not."
| recuter wrote:
| PM: "Let's not rush into any hasty answers!"
|
| (Under no circumstances should you show them this:
| https://www.youtube.com/watch?v=BKorP55Aqvg)
| mirekrusin wrote:
| He should be fired for not suggesting 7-dimentional plot.
| xsmasher wrote:
| This is entertaining, but also cringe; clients and product
| people aren't generally idiots. They just have requirements
| that they can't adequately express.
|
| Requirements capture is part of every eng job I've had.
| recuter wrote:
| I hear you and I understand what you're saying, those are
| some good points. Can you express what you require out of
| a none cringe comedy skit that this lacks?
| tl wrote:
| Minor nit: right click is interpreted as 'press' with odd
| behavior if the context menu selection is 'Inspect Element'.
___________________________________________________________________
(page generated 2022-03-24 23:01 UTC)