Repository navigation
Command Reference
This page lists every ojd command. Every command also accepts the global options in Command line.
Note: This page applies to OpenJoystickDriver 0.6.0-alpha.1 and later. Version 0.5.0-beta.4 and earlier do not have all of the features on this page.
- status
- controller
- profile
- binding
- virtual
- record
- mod
- service
- permission
- extension
- setting
- config
- access
- log
- diagnose
- update
- explain
- Further Reading
Show the service, the DriverKit extension, macOS permissions, and connected controllers in one summary.
ojd status
ojd status works when the service is not running. It then reports the service as stopped, shows the extension state, and exits with code 0. Permissions and controllers appear only while the service runs.
With --json, the output is one SystemStatus object with these keys:
-
service:state(runningorstopped) andversion. -
extension:bundle(present,missing, orinvalid) andregistration(active,inactive,absent, orunavailable). -
commandLineTool: theojdlink that the app installs.stateisinstalled(a link to this app's executable),linkedElsewhere(a link to another existing file, such as another copy of the app),broken(a link whose target is gone),blockedByFile(a file or folder that is not a link; the app never replaces it), ormissing(nothing atpath).pathis where the link goes, andtargetis what it points at, when it is a link. -
permissions:inputMonitoringandaccessibility. -
virtualDevice:enabled,status, andoverrideError. -
controllers: each withid,name,vendorID,productID, andconnection. -
unboundDevices: devices that OpenJoystickDriver does not support, each withvendorID,productID,connection, andreason. -
passThroughDevices: devices that OpenJoystickDriver leaves to macOS. -
skippedRecords: your controller record files that OpenJoystickDriver skipped, each withfileandproblem. -
ignoredDefaults: yourControllers/all.patch.jsonwhen OpenJoystickDriver ignored it whole, withfileandproblem. The key is absent when the file is valid or does not exist. -
skippedPersonas: your persona files that OpenJoystickDriver skipped, each withfileandproblem.
Keys that need the service are absent when it is stopped.
With --plain, the first field of each line is service, extension, command-line-tool, permission, virtual-device, controller, unbound, pass-through, skipped-record, ignored-defaults, or skipped-persona.
List connected controllers, inspect them, and test their input and outputs. Every controller command needs the service running.
ojd controller list
ojd controller show CONTROLLER
ojd controller watch CONTROLLER [--duration SECONDS] [--first-press] [--output]
ojd controller watch --all [--duration SECONDS] [--output]
ojd controller capture CONTROLLER [--duration SECONDS]
ojd controller rumble CONTROLLER [--left N] [--right N] [--left-trigger N] [--right-trigger N] [--duration SECONDS]
ojd controller light CONTROLLER [--color RRGGBB] [--brightness N]
ojd controller player CONTROLLER 1|2|3|4|off
ojd controller claim CONTROLLER [--dry-run]
ojd controller release CONTROLLER [--dry-run]
ojd controller suspend CONTROLLER
ojd controller resume CONTROLLER
ojd controller disconnect CONTROLLER
ojd controller calibrate CONTROLLER [start|pause|reset]
ojd controller pair LEFT RIGHT --profile PROFILE
ojd controller unpair PAIR
CONTROLLER is an ID from ojd controller list, or VVVV:PPPP, the hexadecimal vendor and product ID, in either case. A VVVV:PPPP that matches two connected controllers is rejected, and the error lists them. Use an ID to pick one. An ID (E- and 16 characters) is a session token: it lasts until the controller disconnects, and the controller gets a new one each time it connects. By design, tokens from different connections cannot be linked to the same controller, so scripts should use VVVV:PPPP or a unit ID instead of a stored token. A unit ID (U- and 16 characters) also names one controller. It comes from the controller's model, the USB port it uses, and its interface, never its serial number. It stays the same across reconnects and service restarts while the controller uses the same port, and changes when it moves to another port. A controller with no location ID has no unit ID. Scripts can store a unit ID.
-
controller list: List connected controllers. Each line shows the unit ID after the ID, and with--json,unitgives each controller's unit ID. With--plain, the unit ID follows the name, empty when the controller has none. The battery level and charging state follow it, empty when the service reports no power state. The human output shows the battery level after the connection. -
controller show: Show a controller's unit ID (unitwith--json, which prints aControllerobject with the controller's fields at the top level), identity, ownership, capabilities, effective record, and virtual gamepad. The Record line says whether the record is bundled or one of your records, and names the file of your record. It reads your records from disk when you run the command, so a controller that connected before you changed a record can still run on the older one until it connects again. With--json,recordhaslayer(bundled,package, oruser) and, for a record from a package or your own,file.ownershiphasserver(systemorojd) andserverSource, which is the layer that setsserver(bundled,package, oruser), ordefaultwhen no layer sets it.recordis absent when no record matches the controller's model, as for a generic HID controller. The Battery line shows the battery level, such as73%, or a range such as0-9%when the controller reports its charge in steps, and the charging state. With--json,powerhascharging(unknown,discharging,charging,full, ornotChargeable),battery.percentageas the lowest and highest percentage, absent when the level is unknown, andwiredPower, absent when the controller does not report it.controller list --jsonhas the samepowerfor each controller, andpoweris absent when the service reports no power state. With--plain, thepowerline has the charging state, the battery level, andwiredPower. The Publication line says whether a virtual gamepad publishes the controller and, when none does, why, such asnativeGamepadfor a controller macOS serves itself. With--json,publicationhasstate(published,notPublished, orfailed),reason, andtarget. The Tuning line lists the record's tuning values as applied, such asstickDeadzone=0.2, and is absent when the record sets none; with--json,tuninghas the values named as in the record file. With--json,capabilities.outputOwnerissystemwhen macOS serves the controller natively, so the rumble and lighting lists hold only what macOS leaves undone, orojdwhen OJD drives all of its output; the Output owner line appears only forsystem. The Output checks section lists the commands that exercise each rumble motor and light, with what to observe. -
controller watch: Print the controller's input state each time it changes, until you press Control-C.--durationstops after that many seconds.--first-pressprints the first control pressed and exits. It fails when--durationpasses first. With--json, it prints oneControllerStateobject per line, or oneControlPressobject with--first-press. Stick Y points up.--outputalso prints what the virtual gamepad sends after stick transfer and remapping, on anoutline, orout nonewhen no virtual gamepad publishes the controller. Its stick Y points down, as in the HID report. With--jsonand--output, each object hasinputand, when the controller is published,output.--allwatches every controller instead of one. Each line names its controller by itsojd controller listID, and other lines report each controller that connects or disconnects, starting with the controllers already connected. With--json, each line is a watch line withtype(ADDED,MODIFIED, orDELETED) andobject, aControllerwith its ownapiVersionandkind, and noapiVersionorkindon the line. Theobjectof anADDEDline has the fields of oneojd controller listentry, and theobjectof aMODIFIEDline has the same fields andinputand, with--output,output. -
controller capture: Print the raw packets the controller sends and receives, each with its time, direction (rxortx), length, and hex bytes. It runs until you press Control-C, or until--durationseconds pass. With--json, it prints oneUSBPacketobject per line. -
controller rumble: Run the rumble motors.--left,--right,--left-trigger, and--right-triggerset each motor's intensity from 0 to 255. With none of them, both main motors run at 180.--durationis in seconds, above 0 and at most 5, and is 0.45 by default. Set every intensity to 0 to stop the motors. -
controller light: Set the lightbar color with--color, as hex such asFF8000, or the LED brightness with--brightness, from 0 to 255. -
controller player: Set the player indicator lights to 1 to 4, or turn them off withoff. -
controller claimandcontroller release:claimmakes OpenJoystickDriver (ojd) serve the controller's model, andreleasegives it back to macOS (system). It setsserverin your record for the model,vvvv-pppp.jsonorvvvv-pppp.patch.json, and creates aControllerPatchfile when you have none and the bundled catalog or an installed package has a record of the model. It needs the service running to find the controller. It keeps the other fields of the record. The choice applies to every controller of the model, and the running service applies it without a replug.--dry-run(-n) writes nothing. It exits with code 1 and E2023 for a controller that uses raw USB, for one that macOS does not serve natively, and for a model that has no record at all. For the last case,ojd record draftstarts a record.controller shownames the choice and the layer it comes from, and the serving route and persona the serving policy decides (servingwithroute,persona, andreasonin--json). With--json, it prints thecontroller,identity,serverandprevious(systemorojd),file,created, anddryRun. For more information, see Choose who drives the controller. -
controller suspend: Stop OpenJoystickDriver from driving the controller until you resume it. -
controller resume: Let OpenJoystickDriver drive a suspended controller again. -
controller disconnect: Close a Bluetooth controller's connection. The controller stays paired and reconnects when you turn it on again. The command waits at least 6 seconds for Bluetooth to confirm. -
controller calibrate: Show the motion calibration of a controller with a gyro.startcollects gyro drift while the controller lies still,pausestops the collection, andresetremoves the calibration. Motion lean and steering bindings use the calibration. With--json, it prints aCalibrationobject withcontroller,calibrated,collecting, andoffsetDegreesPerSecondwithx,y, andz. -
controller pair: Combine a left and a right Joy-Con into one controller that usesPROFILE.PROFILEmust be a paired Joy-Con profile. For more information, see Sticks, triggers, touchpad, and motion. Hardware behavior of Joy-Con pairing is not verified. -
controller unpair: Separate a Joy-Con pair.PAIRis the session ID thatcontroller pairprints, or the ID of either Joy-Con.
With --json, controller pair and controller unpair print a JoyConPair object with session, left, right, profile, and gyro. controller suspend, resume, and disconnect print a ControllerSession object. controller rumble, light, and player print a Status with status Success, and details has controller and results. When the controller does not deliver a result, the command prints no JSON: it exits with a non-zero code and writes the error on standard error.
Create, change, activate, and move remapping profiles. Every profile command needs the service running. For more information, see Creating a profile.
ojd profile list
ojd profile show PROFILE
ojd profile create NAME --controller CONTROLLER [--app BUNDLE-ID] [--virtual-gamepad disabled|mapped|passthrough] [--physical-input shared|exclusive]
ojd profile duplicate PROFILE NEW-NAME
ojd profile rename PROFILE NEW-NAME
ojd profile delete PROFILE [--force] [--dry-run]
ojd profile activate PROFILE [--allow-empty]
ojd profile deactivate PROFILE
ojd profile edit PROFILE
ojd profile recover [--force] [--dry-run]
ojd profile import FILE|-
ojd profile validate FILE|-
ojd profile export PROFILE [--output FILE]
ojd profile get PROFILE KEY
ojd profile set PROFILE KEY VALUE
PROFILE is a profile ID, or a profile name in any letter case. A name that two profiles share is rejected, and the error lists their IDs. Use an ID to pick one.
-
profile list: List each profile with its ID, name, controller model, app scope, and number of bindings, and show which profiles are active. When a saved profile cannot be loaded, it also reports each issue on stderr, followed by "Repair them with 'ojd profile recover'." -
profile show: Show a profile's settings and bindings. Bindings use theSOURCEandTARGETforms ofojd binding set. -
profile create: Create an empty, inactive profile for one controller model.--controllerisVVVV:PPPPor the ID of a connected controller. The profile applies in every app unless--appgives an app's bundle ID.--virtual-gamepadsets what the virtual gamepad sends: nothing (disabled), bound controls only (mapped), or also every control that no binding uses (passthrough, the default).--physical-inputsets whether macOS still sees the controller (shared, the default) or OpenJoystickDriver takes it (exclusive). -
profile duplicate: Copy a profile under a new name. The copy is inactive. -
profile rename: Give a profile a new name of 1 to 80 characters. -
profile delete: Delete a profile. An active profile stops applying. It asks first on a terminal and needs--forceotherwise.--dry-run(-n) prints what would change and changes nothing. -
profile activate: Apply a profile. It replaces the active profile of the same controller model and app scope. A profile with the virtual gamepad set tomappedthat sends nothing to the gamepad, keyboard, pointer, or controller and sets no light color produces no output. To activate such a profile, add--allow-empty. -
profile deactivate: Stop applying a profile. The controller then sends its own input. -
profile edit: Open the profile file in$VISUAL,$EDITOR, orvi, then check and save it. Use it to change chords, sequences, layers, stick and trigger tuning, and the app scope. It needs a terminal. Without one, export the profile, change the file, and import it. For the file format, see Profile file reference. -
profile recover: Repair the problems thatprofile listreports. It acts on each issue: it removes a damaged profile file and resets a damaged active profile list. The service first backs up each file beside the original, under a name that contains.backup-. It asks first on a terminal and needs--forceotherwise.--dry-run(-n) prints what would change and changes nothing. With--plain, it prints one line for each issue, with its ID and kind. -
profile import: Add a profile from a file thatprofile exportwrote. Use-to read the file from stdin. A profile with the same ID as an existing profile replaces it. -
profile validate: Check a profile file without importing it. Use-to read the file from stdin. It needs no running service and exits 1 when the profile is invalid. -
profile export: Print a profile file to stdout, or write it to--output. The file is JSON, so--jsonand--plaindo not change the output. -
profile get: Print one value from the profile file.KEYis a path of member names and array indexes joined by dots, such asstickMappings.0.tuning.innerDeadzone. A string prints alone, and any other value prints as JSON. A key with no value exits 1. -
profile set: Change one value in the profile file.VALUEis read as JSON, or as a string when it is not JSON, so0.2is a number andspaceis a string. To set the stringtrue, write'"true"'.nullremoves the key or the array item, and the index one past the end of an array adds an item. OJD checks the whole profile before it saves it and refuses a change that makes it invalid or changesid. For example,ojd profile set Racing physicalColor '{"red":255,"green":0,"blue":0}'.
With --json, a profile is an object with id, name, controller, scope (global or app:BUNDLE-ID), active, and bindings, the number of bindings. profile list prints a ProfileList with items, one profile each, and an empty metadata. The issues it finds go to stderr as warnings, one line each. profile show prints a Profile with profile and document, the full profile file. profile create, duplicate, rename, activate, deactivate, edit, set, and import print a Profile too, with profile and changed (replaced for import). profile get prints a ProfileValue with key and value. profile delete and profile recover print a Status, and details holds deleted and dryRun for delete, and recovered, each with id, kind, and message, and dryRun for recover. profile validate prints a ProfileValidation with valid, then id, name, controller, and scope for a valid profile or problem for an invalid one.
List, set, and clear the bindings of a profile. A binding sends a target when you use a control on the controller. Every binding command needs the service running. For more information, see Assigning buttons and actions.
ojd binding list PROFILE
ojd binding set PROFILE SOURCE TARGET [options]
ojd binding clear PROFILE SOURCE... [--force] [--dry-run]
ojd binding clear PROFILE --all [--force] [--dry-run]
SOURCE is one of these forms:
-
button:NAME, such asbutton:Southorbutton:LeftShoulder dpad:DIRECTION-
axis:NAME, oraxis:NAME:negativeoraxis:NAME:positivefor one direction, such asaxis:LeftStickX:positive trigger:NAME:STAGEmotion:lean:DIRECTION-
touch:SURFACE:contact,touch:SURFACE:grid:COLUMNS:ROWS:COLUMN:ROW, ortouch:SURFACE:swipe:DIRECTION:DISTANCE
TARGET is one of these forms:
-
key:KEY, with modifiers askey:KEY:mods=command,control,option,shift -
mouse:BUTTON,move:x,move:y,scroll:x, orscroll:y -
gamepad:button:NAME,gamepad:dpad:DIRECTION, orgamepad:axis:NAME -
physical:...for rumble, lights, and adaptive triggers
ojd profile show prints bindings in the same forms.
-
binding list: List a profile's bindings. -
binding set: Bind a source to a target. A source has one binding, so this replaces the binding that the source has, and keeps its ID. The options are:-
--behavior: When the target fires:hold(the default for a new binding),toggle,tap_on_press,tap_on_release,pulse,press, orrelease. -
--pulse-ms: How longpulseholds the target, 1 to 5000 ms. The default is 100. -
--deadzone,--gain,--invert,--response-curve, and--digital-threshold: Tuning for axis sources. The dead zone is 0 to 0.95 (default 0.1), the gain is 0.1 to 10 (default 1), and the response curve islinear(the default),ease_in,ease_out, orsmooth_step. The digital threshold is the travel that counts as a press for button targets (default 0.5). -
--turbo-rateand--turbo-duty: Repeat the target this many times a second while the source is held. The duty is the part of each cycle that the target is held, above 0 and below 1. Turbo cannot be used with--long-holdor--double-tap. -
--long-hold MS:TARGET: Send another target when the source is held this long, such as500:key:b. -
--double-tap MS:TARGET: Send another target when the source is pressed twice in this time, such as300:key:c. -
--actions-json: More actions, as a JSON array in the form thatojd profile exportwrites.
-
-
binding clear: Remove the bindings of the given sources. It exits with code 1 and changes nothing when a source has no binding.--allremoves every binding, chord, sequence, and layer. Stick, trigger, touch, motion, and output settings stay.--allasks first on a terminal and needs--forceotherwise.--dry-run(-n) prints what would change and changes nothing. When the result leaves a profile that is active on a connected controller with no inputs while OJD seizes the physical input, the command prints a warning on stderr that namesojd binding setandojd profile deactivate, and still exits with code 0.
With --json, a binding is an object with id, source, target, and behavior. binding list prints a BindingList with items, one binding each, and an empty metadata. Each item also has profile, the profile it came from. binding set prints a Binding with profile, binding, and replaced, and binding clear prints a Status, with profile, removed (the sources), all, and dryRun in details.
Show and choose the virtual gamepad that OpenJoystickDriver publishes for a controller. A choice applies to every controller of the same model, unless you add --unit: then it applies to that controller only, by its unit ID, and wins over its model's choice.
ojd virtual show [CONTROLLER]
ojd virtual set PROFILE CONTROLLER [--unit]
ojd virtual reset [CONTROLLER] [--unit] [--all] [--force] [--dry-run]
ojd virtual feed --as PROFILE
-
virtual show: Show each controller's virtual gamepad and the profiles you can choose. Name a controller to show only that one. With--json, it prints aVirtualGamepadConfiguration, andoverrideScopesays whether a stored choice is the controller's own (unit) or its model's (model). -
virtual set: Choose the profile for the controller's model. With--unit, choose it for that controller only. A controller with no unit ID cannot take--unit. The profiles aresdl-compatibleandgeneric. -
virtual reset: Return the controller's model to automatic selection. With--unit, it removes only that controller's own choice, so its model's choice applies again.--unitcannot be used with--all.--allreturns every model, including models that are not connected. It asks first on a terminal and needs--forceotherwise.--dry-run(-n) prints what would change and changes nothing. With--json,virtual setandvirtual resetprint aVirtualGamepadChange, exceptvirtual reset --all, which prints aStatuswith{"reset":"all"}indetails. -
virtual feed: Publish a virtual gamepad with the--asprofile and drive it from standard input. Write one JSON object per line, such as{"buttons":["South"],"dpad":["up"],"axes":{"LeftStickX":0.5,"RightTrigger":1}}. Buttons, D-pad directions, and stick axes take the names ofbutton:,dpad:, andaxis:binding sources, and the triggers are the axesLeftTriggerandRightTrigger. A missing control is neutral. Sticks run from -1 to 1 with Y up, and triggers run from 0 to 1. Frames play in order, each for at least 8 ms;holdMilliseconds, from 0 to 60000, keeps a frame longer. The command ends after the last frame has played. Each rumble command a game sends to the virtual gamepad is printed as oneRumbleCommandobject per line, with atypeofsetRumbleorstopRumble. The gamepad is removed when the input ends, on Control-C, or when the service gets no update for 2 seconds. A line that is not a frame, such as one with an unknown key or a button listed twice, exits with code 64. The service runs at most 4 feeds from this command, and endpoint clients have 4 more of their own.
Draft, list, check, install, or remove controller records. Only record draft needs the service. For more information, see Adding or changing a controller record.
ojd record draft CONTROLLER [--duration SECONDS]
ojd record list [--bundled]
ojd record show VVVV:PPPP
ojd record validate FILE|-
ojd record install FILE|- [--force] [--dry-run]
ojd record remove VVVV:PPPP [--force] [--dry-run]
ojd record test VVVV:PPPP --packets CAPTURE --expect STATE
FILE is a record file. Use - to read the record from stdin.
-
record draft: Read a connected controller's HID report descriptor, capture its input reports for--durationseconds (10 by default) while you press each control, and print a record to start from. The record is aControllerfor a model without a bundled record and aControllerPatchotherwise. It maps the buttons, sticks, triggers, and hat that the descriptor states plainly, with thehid.report-layoutfamily, or nameshid.descriptorwhen nothing maps. Each report byte that changed during the capture is listed on stderr with its lowest and highest value. It exits with code 1 when nothing maps for a model with a bundled record. -
record list: List every controller record, with its model, protocol family, layer (bundled,package, oruser), and file. It names each of your files that OpenJoystickDriver skipped, and each package record that it ignores, and why, on stderr, also with--json.--bundledlists the bundled records alone. -
record show: Show one model's effective record and the layer of each top-level field. It exits with code 1 when no record exists for the model. -
record validate: Check a record without installing it. It shows the kind (ControllerorControllerPatch), the model, the family, the file name, and whether the USB driver extension can claim the controller. It exits with code 1 when the record is not valid. -
record install: Check a record and write it to your record folder asvvvv-pppp.json. To replace the record already installed for that model, it asks first on a terminal and needs--forceotherwise.--dry-run(-n) checks the record and prints where it would go, and writes nothing. It exits with code 1 and writes nothing when the record is not valid. -
record remove: Delete your record for a model. It asks first on a terminal and needs--forceotherwise.--dry-run(-n) prints what would change and changes nothing. It exits with code 1 when you have no record for the model. -
record test: Replay captured reports through a model's record and compare the parsed controller state with the state you expect. It needs no service.CAPTUREis a file of the lines thatojd controller capture --jsonprints, one packet per line, and only received packets count.STATEis a JSON file in the shape of one line ofojd controller watch --json. Theconnectionfield is not compared. The state after the last report that carried input is the one compared. On a match it exits with code 0. On a mismatch it prints each field that differs, with its expected and parsed value, and exits with code 1 and errorE2022. It exits with code 1 and errorE2011when the capture or the state is not valid, no report in the capture carries input, the parser rejects a report, or the record has no parser that runs without a device. It exits with code 64 when a file cannot be read.
With --json, record test prints a RecordTestResult with identity, matches, inputReports, and differences, each with field, expected, and actual. record draft prints a RecordDraft with identity, name, operation, family, report (id and length, absent when no report was chosen), capturedReports, changedBytes, each with byte, minimum, and maximum, and record. With --plain, it prints one line for each changed byte: its offset, lowest value, and highest value. record list prints a ControllerRecordList with items, each with identity, vendorID, productID, family, layer, and file, and an empty metadata. record show prints a ControllerRecord with identity, family, layer, file, transport (hid or usb), usbExtension (claims or doesNotClaim, for usb only), fields, and record. record validate prints a RecordValidation with valid, and problem or the record's operation, identity, family, fileName, transport, and usbExtension. record install prints a ControllerRecord with installed, replaced, dryRun, and record, and record remove prints a Status, with removed and dryRun in details.
Validate, install, list, or remove mod packages. A package is a folder with a mod.json manifest. None of these commands needs the service. For more information, see Writing controller mods.
ojd mod validate FOLDER
ojd mod install FOLDER [--force] [--dry-run]
ojd mod list
ojd mod remove NAME [--force] [--dry-run]
-
mod validate: Check a package folder without installing it: the manifest, whetherrequiresincludes this version, the listed files, and clashes with your files and other packages. It exits with code 1 and theE4xxxorE5001code when the package is refused. -
mod install: Check the package and install it toPackages/NAMEin the OpenJoystickDriver folder. The running service applies it. A package of the same name that is installed is refused with E4005 unless you pass--force.--forcenever overridesrequires, a clash, or an invalid file.--dry-run(-n) checks the package and writes nothing. -
mod list: List each installed package with its version, author, and files. A package that OpenJoystickDriver does not use, such as one whoserequiresleaves out this version, shows the reason and its code. -
mod remove: Delete one installed package. It asks first on a terminal and needs--forceotherwise.--dry-run(-n) changes nothing. It exits with code 1 and E4006 when the package is not installed.
Start or stop the OpenJoystickDriver service, or wait until it accepts requests. With --timeout, each command waits at most that many seconds. The default is 5 seconds.
ojd service start
ojd service stop
ojd service wait
-
service start: Open the app in the background and wait until its service accepts requests. It does nothing when the service already runs. It needs theojdinsideOpenJoystickDriver.app, or a link to it. -
service stop: Stop the service and wait until it exits. Connected controllers return to macOS. -
service wait: Wait until the service accepts requests. It exits with code 69 when the time runs out.
With --json, each command prints a Service object, {"state": "running"} or {"state": "stopped"} besides apiVersion and kind. With --plain, it prints state and the state.
List the macOS permissions OpenJoystickDriver needs, or ask the service to request them.
ojd permission list
ojd permission request [input-monitoring] [accessibility]
-
permission list: Show each permission, its state (granted,denied, orunknown), and what OpenJoystickDriver uses it for. The permissions areinput-monitoring,accessibility, anddriver-extension. When the service is stopped,ojdreads the states itself and says so on stderr. -
permission request: Ask the service to request each permission you name, or bothinput-monitoringandaccessibilitywhen you name none. macOS shows its own prompt. The command never prompts in the terminal. It exits with code 77 when a permission is still not granted.
With --json, permission list prints a PermissionList with items, each with id, name, state, and purpose.
Show, activate, or deactivate the DriverKit system extension.
ojd extension status
ojd extension activate
ojd extension deactivate
-
extension status: Show whether the extension is in the app (bundle:present,missing, orinvalid) and registered with macOS (registration:active,inactive,absent, orunavailable). It works when the service is stopped. It exits with code 1 when the registration isunavailable. -
extension activate: Ask macOS to activate the extension. macOS can ask you to approve it in System Settings. The command then reports that it awaits approval (awaitingApprovalwith--json) and exits with code 0. -
extension deactivate: Ask macOS to deactivate the extension. Connected controllers return to macOS.
activate and deactivate need the ojd inside /Applications/OpenJoystickDriver.app, or a link to it. With --json, status, activate, and deactivate print a DriverExtension, and activate and deactivate have state: active, inactive, or awaitingApproval.
List, read, or change app settings. The service applies each setting, so these commands need it running.
ojd setting list
ojd setting get KEY
ojd setting set KEY true|false
The keys are:
-
launchAtLogin: the macOS login item.getreads it from macOS, so it includes changes made in System Settings, andsetregisters or unregisters the item. A change made withojd settingor in the app also records whether you opted out, so OJD does not register itself again at the next start. A change made only in System Settings records nothing. -
notify.controllerConnected: notify when a controller connects or needs attention. -
notify.controllerDisconnected: notify when a controller disconnects. -
notify.profileActivated: notify when a profile is activated or switched. -
notify.profileDeactivated: notify when the active profile is turned off. -
notify.sounds: play a sound with notifications. It is on by default; every other key is off by default. -
updates.includePrereleases: include prereleases when checking for updates. -
developerTools: show the developer tools.
Settings live in Settings.json. A setting your file at ~/Library/Application Support/OpenJoystickDriver/Settings.json leaves out takes its built-in default. setting set writes that file. The first time a newer version starts and finds no file, the app copies the settings an older version kept in macOS preferences into it and removes the old preferences, so a login-item opt-out survives the upgrade. A file with an unsupported apiVersion is refused with E5001. setting get prints true or false alone. With --json, setting list prints a SettingList with items, each with key, value, and description, and setting get and setting set print a Setting with key and value.
Show the effective tuning values and the layer that set each one. It works without the service, which adds only the profile rows.
ojd config show [--controller VVVV:PPPP]
Without --controller, it shows Controllers/all.patch.json against the driver defaults, and marks each key with the protocol families whose drivers read it, such as read by: sony.dualshock4 for inputLivenessTimeoutMs. The families come from the controller records, so they follow the catalog. When the service runs with a controller connected and all.patch.json sets a key that no connected controller reads, it prints one warning for that key on stderr, which --json and --plain leave out of stdout. When some record ignores a key that Controllers/all.patch.json sets but the service is not running or no controller is connected, it prints one note on stderr that the check was skipped. With --controller, it shows the record for that model: each value comes from driver, global, bundled, or user. When the service runs and a profile is active for that model, it adds one profile row per stick mapping, keyed as profile get names it, such as stickMappings.0.tuning.innerDeadzone. A profile value calibrates that mapping and does not replace the record's stickDeadzone. See Set a Default for Every Controller. With --json, it prints a Configuration with profile (the active profile's name, when it shows rows), defaultsFile, defaultsProblem when the file is invalid, and values, each with key, layer, value when set, and families (the reading families) without --controller. --plain prints key, value, and layer per line, plus the families joined by commas without --controller.
Turn on the endpoint and choose which programs may read controllers or drive a virtual gamepad through it. The endpoint is a local socket that granted programs use, and an optional WebSocket for web pages. For its protocol, see Read the Endpoint. These commands need the service running.
ojd access status
ojd access enable [--force]
ojd access disable
ojd access list
ojd access grant CLIENT [--scope read|control]... [--force]
ojd access grant --token NAME [--origin URL]... [--scope read|control]... [--force]
ojd access revoke CLIENT|token:NAME [--scope read|control]...
ojd access web enable [--port PORT] [--force]
ojd access web disable
-
access status: Show whether the endpoint is on, the path of its socket, and the connected clients. It also shows the WebSocket and the number of tokens. With--json, it prints anEndpointAccesswithenabled,socketPath,connections,grants,refused,web,tokens, andrefusedTokens, andaccess enableandaccess disableprint the same kind.access web enableandaccess web disableprint aWebAccess, andaccess listprints anAccessSummary. A grant and a refused client have anidentityKind. Each connection has atransport:socketorweb. -
access enable: Turn on the endpoint. It asks first. In a script, it needs--force. The endpoint is off until you run this command. -
access disable: Turn off the endpoint and close its connections. The grants stay. -
access list: List the granted clients and tokens, and the clients and tokens that the endpoint refused in the last 24 hours. Each client has an 8-character ID, and each token has the IDtoken:NAME. -
access grant: Allow a program to use the endpoint.CLIENTis the path of the program's app bundle or executable, or an ID fromaccess list.--scopeisreadby default. The grant names the program's signature, so it stays valid when the program is updated or moved. It asks first, and in a script it needs--force. -
access grant --token: Create a token namedNAMEinstead of granting a program. The command prints the token once; the service keeps only its hash. A client signs the service's challenge with the token in itshelloand does not send the token. Each--origin, such ashttp://127.0.0.1:8080, lets web pages from that origin use the token on the WebSocket. A token without--originworks on the socket, and on the WebSocket from a program that sends noOriginheader, such as a sandboxed app. With--json, it prints anAccessTokenwithtokenandgrant.access grantwithout--tokenprints anAccessGrant. -
access revoke: Remove a client's or a token's grant. With--scope, it removes only those scopes. The endpoint closes each connection that loses a scope. With--json, it prints aStatus. -
access web enable: Turn on the WebSocket on127.0.0.1. Without--port, it uses the saved port; the first time, the system picks a free port.--portnames another from 1024 to 65535. The port is saved, andaccess statusshows it. It asks first, and in a script it needs--force. It is independent ofaccess enable. -
access web disable: Turn off the WebSocket and close its connections. The tokens stay.
access grant accepts only a program signed with a Developer ID or Apple Development certificate, or signed by Apple. It refuses an ad-hoc signed or unsigned program, because any program can claim that signature. For a program that Apple signed, such as python3, every script that the program runs gets the access.
The control scope lets a program drive a virtual gamepad, so it can press buttons in any game. read does not include it, and control does not include read. A granted program uses control on the socket. On the WebSocket, only a token without --origin can use it, from a program that sends no Origin header; a web page cannot. access grant --token refuses --origin together with --scope control. When a grants file from an earlier build holds that combination, the service ignores the control scope of that token. See Drive a virtual gamepad through the endpoint.
Any local program that reads a token can use it, including programs of other users on the same Mac when the WebSocket is on. Treat a token as a password, and revoke it when you no longer need it.
Show the service logs or print the folder that holds them.
ojd log show [--lines COUNT] [--follow]
ojd log path
ojd log export FILE [--lines COUNT] [--force]
-
log show: Print the last lines of each service log, 100 by default and at most 10000. On a terminal, the output goes through$PAGER, orless -FRXwhen it is unset. SetPAGERto an empty value to turn paging off.--followkeeps printing new lines until you press Control-C. With--json, it prints aLogSnapshot, and with--followoneLogEntryper line, withstreamandline. -
log path: Print the log folder. To open it in Finder, runopen "$(ojd log path)". -
log export: Write the last lines of each service log toFILE, 2000 by default and at most 10000, with your home folder shown as~. It does not replace an existing file unless you pass--force. Review the file before you share it. With--json,log pathprints aLogLocationandlog exportprints aStatuswithlinesandpathindetails.
Run every check and report what is wrong.
ojd diagnose [--bundle PATH] [--soak SECONDS]
The checks are service, extension-bundle, extension-registration, input-monitoring, accessibility, controller-records, config-files, usb-access, virtual-device, and runtime-health. Each reports pass, warn, fail, or skip. The controller-records check warns when OpenJoystickDriver skipped one of your controller record files. The config-files check warns when it ignored your Controllers/all.patch.json or skipped one of your persona files. Checks that need the service are skipped while it is stopped. The command exits with code 1 when any check fails.
-
--bundle PATH: Also write a support report toPATH. Read it before you share it. -
--soak SECONDS: Run theruntime-healthcheck. It samples the service's memory, file descriptors, and CPU for 1 to 86400 seconds. Without--soak, that check is skipped.--interval-ms,--rss-limit-mib, and--footprint-limit-mibtune the sampling and set failure limits.
With --json, the output is a Diagnosis with checks, each with id, status, and detail, and bundle when you wrote one.
Each connected controller also lists the timing of its newest frames. Every frame carries a time in nanoseconds on the service's monotonic uptime clock for each stage it reached: read, parse, dispatch, delivery-virtual-device, and delivery-endpoint. The service keeps the last 8 frames of each controller, and the list is empty while the service is stopped. delivery-virtual-device is present only when the report reached the virtual device, so a failed or suppressed publish leaves it out. The endpoint polls the controller state, so delivery-endpoint goes on the controller's newest frame when the poll runs, and a frame replaced by a newer one before the poll gets none. With --json, the timings are timings, each with controller, name, and frames. With --plain, each stage is a row of timing, controller, frame sequence, stage, and nanoseconds. Without either, each frame is one line after the checks. --bundle writes the same frames to data.frameTimings of the support report, with the same stage names and nanoseconds, and an empty list while the service is stopped.
Check whether a newer release exists.
ojd update check [--prerelease]
--prerelease includes prerelease versions. The command exits with code 1 when the check fails. With --json, it prints an UpdateCheck with status (upToDate or available), currentVersion, latestVersion, includePrereleases, and releaseURL when an update is available.
Explain an error code.
ojd explain CODE
CODE is an error code such as E2004, in any letter case.
The command works offline.
It prints the code, its area (endpoint, command line, or remapping), what it means, and the exit code of a command-line code or the wire value of a remapping code.
A retired code prints that it is retired and in which version.
An unknown code is a usage error.
With --json, the output is an ErrorExplanation with code, area, explanation, and exitCode, wire, or retiredIn.
- Home
- Start here
- Controllers
- Games
- Remapping
- Your Mac
- Command line
- Help
- Advanced