Aros/Developer/Docs/Libraries/LowLevel
History
editThe lowlevel.library, introduced in Workbench/Kickstart 3.1, offers timer and keyboard/joystick support functions to game and demo programmers.
The original library was designed by Commodore and had the following issues...
- Input functions are polling based while AmigaOS is event driven.
- Input functions are system wide, not application based. If left is pressed, it is expected only the active applications detects it. With lowlevel, the others also detect it.
- Some features can only be used by one application at a time. Really a bad idea in a multitasking environment.
- Some other timer function only works for 16 hours. Then it returns wrong results.
- Programmers are invited to use software interruption instead of high priority thread.
lowlevel.library does not maintain a list of interrupt handlers, it maintains only a single interrupt handler, which is added additionally to standard keyboard processing.
Current
editReadJoyPort() is patched for USB usage.
In the original AmigaOS lowlevel.library and keyboard.device are tightly glued together and in fact just two interfaces of one module and can't be separated. Anyway, two new HIDDs which now manages the keyboard and mouse drivers. Now it is possible to plug in several lowlevel drivers at once, their input streams will be merged. See rom/hidd/keyboard and rom/hidd/mouse.
Analogue Programming
editReadJoyPort(unit) to get the usual digital positions ReadJoyPort(unit + JP_TYPE_ANALOGUE) to get the new analog positions which contains two eight bit counters holding the absolute position of two joystick axis.
The analogue axis information is an unsigned integer from 0 to 255 and has not necessarily been calibrated to be centered at 128.
An application can also take control and can explicitly demand JP_TYPE_ANALOGUE data by either adding JP_ANALOGUE_PORT_MAGIC to the portNumber or setting SJA_TYPE to SJA_TYPE_ANALOGUE in SetJoyPortAttrs().
- To use the second analog joy, you must assign it like a second joystick (for example left joy as joy in port 0 and the other in port 1 ) and enable the analog hack on this "second" joypad
- use JP_ANALOGUE_PORT_MAGIC on two lowlevel units. Then you map the second analog stick of your joypad to the axis of lowlevel unit 0
- Your game can now read the two analog sticks of one single joypad :-)
Rumble Programming
editSetJoyPortAttrsA() adds three options for force feedback and rumble pack support. These are currently very basic controls of two motors found in the joypad.
- portNumber - the joyport in question (0-3).
- SJA_Type (ULONG) - Sets the current controller type to the mouse, joystick, or game controller. Supply one of SJA_TYPE_GAMECTLR, SJA_TYPE_MOUSE, SJA_TYPE_JOYSTK, or SJA_TYPE_AUTOSENSE. If SJA_TYPE_AUTOSENSE is used, SJA_TYPE_ANALOGUE, or SJA_TYPE_AUTOSENSE.
If SJA_TYPE_AUTOSENSE is used, ReadJoyPort() will attempt to determine the type of controller plugged into the given port automatically. If one of the other types is used, ReadJoyPort() will forcing a port to deallocate any allocated resources; return the implied type to SJA_TYPE_AUTOSENSE.
- SJA_RumbleSetSlowMotor (UBYTE) - If a rumble pack is available, using this tag will set the speed of the slow motor to the given value (0 - 255).
- SJA_RumbleSetFastMotor (UBYTE) - If a rumble pack is available, using this tag will set the speed of the fast motor to the given value (0 - 255).
- SJA_RumbleOff (BOOL) - If set, this will turn the rumble pack motors off.
RESULT success - TRUE if everything went according to plan, or FALSE upon failure
The call to turn rumble on is
SetJoyPortAttrsA(joy, SJA_RumbleSetFastMotor, 255, TAG_DONE);
where joy is the appropriate unit
ReadJoyPort() ignores buttons 8-12 on the gamepad, even though they work fine in Preferences
Examples
edit#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/lowlevel.h>
#include <libraries/lowlevel_ext.h>
#include <stdio.h>
#include <stdlib.h>
struct Library *LowLevelBase;
static void printbuttons(ULONG val)
{
if (val & JPF_BUTTON_PLAY) printf("[PLAY/MMB]");
if (val & JPF_BUTTON_REVERSE) printf("[REVERSE]");
if (val & JPF_BUTTON_FORWARD) printf("[FORWARD]");
if (val & JPF_BUTTON_GREEN) printf("[SHUFFLE]");
if (val & JPF_BUTTON_RED) printf("[SELECT/LMB/FIRE]");
if (val & JPF_BUTTON_BLUE) printf("[STOP/RMB]");
}
static void printmousedirections(ULONG val)
{
printf("[%d,%d]", (val & JP_MHORZ_MASK), (val & JP_MVERT_MASK) >> 8);
}
static void printajoydirections(ULONG val)
{
printf("[%d, %d]", (val & JP_XAXIS_MASK), (val & JP_YAXIS_MASK) >> 8);
}
static void printjoydirections(ULONG val)
{
if (val & JPF_JOY_UP) printf("[UP]");
if (val & JPF_JOY_DOWN) printf("[DOWN]");
if (val & JPF_JOY_LEFT) printf("[LEFT]");
if (val & JPF_JOY_RIGHT) printf("[RIGHT]");
}
static void printjoyport(ULONG val)
{
int i;
for(i = 31; i >= 0; i--)
{
printf("%d", (val & (1 << i)) ? 1 : 0);
}
printf(" - ");
if ((val & JP_TYPE_MASK) == JP_TYPE_NOTAVAIL) printf("NOT AVAILABLE");
if ((val & JP_TYPE_MASK) == JP_TYPE_UNKNOWN) printf("UNKNOWN");
if ((val & JP_TYPE_MASK) == JP_TYPE_JOYSTK)
{
printf("JOYSTICK - ");
printjoydirections(val);
printbuttons(val);
}
if ((val & JP_TYPE_MASK) == JP_TYPE_GAMECTLR)
{
printf("GAME CONTROLLER - ");
printjoydirections(val);
printbuttons(val);
}
if ((val & JP_TYPE_MASK) == JP_TYPE_MOUSE)
{
printf("MOUSE - ");
printmousedirections(val);
printbuttons(val);
}
if ((val & JP_TYPE_MASK) == JP_TYPE_ANALOGUE)
{
printf("JOYSTICK[ANALOGUE] - ");
printajoydirections(val);
printbuttons(val);
}
printf("\n");
}
int main(int argc, char **argv)
{
int unit = 1;
if (argc == 2) unit = atoi(argv[1]);
LowLevelBase = OpenLibrary("lowlevel.library", 0);
if (LowLevelBase)
{
ULONG old = 0;
while(!CheckSignal(SIGBREAKF_CTRL_C))
{
ULONG new;
new = ReadJoyPort(unit);
if (new != old)
{
old = new;
printjoyport(new);
}
Delay(1);
}
CloseLibrary(LowLevelBase);
}
return 0;
}
value other than JP_TYPE_NOTAVAIL) this function may be used in interrupts. As an extension to the former available data, analogue joystick data may be returned. This is currently only supported by the Poseidon USB HID class, however, in future other devices may also add support for it. The user may specify the analogue data override option in the HID class and the data returned by ReadJoyPort() will be of type JP_TYPE_ANALOGUE, which contains two eight bit counters holding the absolute position of two joystick axis. An application can also take control and can explicitly demand JP_TYPE_ANALOGUE data by either adding JP_ANALOGUE_PORT_MAGIC to the portNumber or setting SJA_TYPE to SJA_TYPE_ANALOGUE in SetJoyPortAttrs(). The analogue axis information is an unsigned integer from 0 to 255 and has not necessarily been calibrated to be centered at 128. Compatibility issues: - If the HID class is not loaded, use of SJA_TYPE_ANALOGUE will have no effect and JP_TYPE_NOTAVAIL will be returned on ReadJoyPort(). - If the HID class is not loaded, and JP_ANALOGUE_PORT_MAGIC is used, JP_TYPE_NOTAVAIL will be returned on ReadJoyPort(). - If SetJoyPortAttrs() has been set to SJA_TYPE_JOYSTK or SJA_TYPE_GAMECTRL, using portNumbers from 0 to 3 still will return digitally interpreted data, whereas using portNumbers from JP_ANALOGUE_PORT_MAGIC to JP_ANALOGUE_PORT_MAGIC+3 will return the analogue data from the ports. INPUTS portNumber - port to read, in the range 0 to 3. If the JP_ANALOGUE_PORT_MAGIC bit is set additionally, the returned bitmask will be of JP_TYPE_ANALOGUE, even if the port was set to JP_TYPE_GAMECTRL or JP_TYPE_JOYSTK before. RESULT portState - bit map that identifies the device and the current JP_TYPE_GAMECTLR game controller JP_TYPE_MOUSE mouse JP_TYPE_JOYSTK joystick JP_TYPE_ANALOGUE analogue stick (EXT) JP_TYPE_UNKNOWN unknown device If type = JP_TYPE_GAMECTLR the bit map of portState is: JP_MVERT_MASK Mask for vertical counter JP_MHORZ_MASK Mask for horizontal counter If type = JP_TYPE_ANALOGUE the bit map of portState is: JPF_BUTTON_RED Button 1 (standard fire) JPF_BUTTON_BLUE Button 2 JPF_BUTTON_GREEN Button 3 JPF_BUTTON_YELLOW Button 4 JPF_BUTTON_FORWARD Button 5 JPF_BUTTON_REVERSE Button 6 JPF_BUTTON_PLAY Button 7 JP_XAXIS_MASK Mask for horizontal position JP_YAXIS_MASK Mask for vertical position SEE ALSO SetJoyPortAttrs() time attempting to sense which type of controller is in use -- and, optionally, to force ReadJoyPort() into utilizing a certain controller type. SetJoyPortAttrs() adds three options for force feedback and rumble pack support. These are currently very basic controls of two motors found in the joypad. INPUTS portNumber - the joyport in question (0-3). SJA_Type (ULONG) - Sets the current controller type to the mouse, joystick, or game controller. Supply one of SJA_TYPE_GAMECTLR, SJA_TYPE_MOUSE, SJA_TYPE_JOYSTK, or SJA_TYPE_AUTOSENSE. If SJA_TYPE_AUTOSENSE is used, SJA_TYPE_ANALOGUE, or SJA_TYPE_AUTOSENSE. If SJA_TYPE_AUTOSENSE is used, ReadJoyPort() will attempt to determine the type of controller plugged into the given port automatically. If one of the other types is used, ReadJoyPort() will forcing a port to deallocate any allocated resources; return the implied type to SJA_TYPE_AUTOSENSE. SJA_RumbleSetSlowMotor (UBYTE) - If a rumble pack is available, using this tag will set the speed of the slow motor to the given value (0 - 255). SJA_RumbleSetFastMotor (UBYTE) - If a rumble pack is available, using this tag will set the speed of the fast motor to the given value (0 - 255). SJA_RumbleOff (BOOL) - If set, this will turn the rumble pack motors off. success - TRUE if everything went according to plan, or FALSE upon failure <libraries/lowlevel.h>
References
editimplemented ULONG ReadJoyPort(ULONG port) UBYTE GetLanguageSelection() ULONG GetKey() VOID QueryKeys(struct KeyQuery * queryArray, UBYTE arraySize) APTR AddKBInt(const APTR intRoutine, const APTR intData) VOID RemKBInt(APTR intHandle) ULONG SystemControlA(const struct TagItem * tagList) ULONG SystemControl(Tag tagList, ...) APTR AddTimerInt(const APTR intRoutine, const APTR intData) VOID RemTimerInt(APTR intHandle) ULONG ElapsedTime(struct EClockVal * context) APTR AddVBlankInt(const APTR intRoutine, const APTR intData) VOID RemVBlankInt(APTR intHandle) BOOL SetJoyPortAttrsA(ULONG portNumber, const struct TagItem * tagList) not implemented BOOL SetJoyPortAttrs(ULONG portNumber, Tag tagList, ...) VOID StopTimerInt(APTR intHandle) VOID StartTimerInt(APTR intHandle, ULONG timeInterval, BOOL continuous)
The type of device can be determined by applying the mask JP_TYPE_MASK to the return value and comparing the resultant value with the following:
JP_TYPE_NOTAVAIL | port data unavailable |
JP_TYPE_GAMECTLR | game controller |
JP_TYPE_MOUSE | mouse |
JP_TYPE_JOYSTK | joystick |
JP_TYPE_ANALOGUE | analog stick |
JP_TYPE_UNKNOWN | unknown device |
If type = JP_TYPE_GAMECTL R the bit map of portState is: | |
---|---|
JPF_BUTTON_BLUE | Blue - Stop |
JPF_BUTTON_RED | Red - Select |
JPF_BUTTON_YELLOW | Yellow - Repeat |
JPF_BUTTON_GREEN | Green - Shuffle |
JPF_BUTTON_FORWARD | Charcoal - Forward |
JPF_BUTTON_REVERSE | Charcoal - Reverse |
JPF_BUTTON_PLAY | Grey - Play/Pause |
JPF_JOY_UP | Up |
JPF_JOY_DOWN | Down |
JPF_JOY_LEFT | Left |
JPF_JOY_RIGHT | Right |
If type = JP_TYPE_JOYSTK the bit map of portState is: | |
JPF_BUTTON_BLUE | Right |
JPF_BUTTON_RED | Fire |
JPF_JOY_UP | Up |
JPF_JOY_DOWN | Down |
JPF_JOY_LEFT | Left |
JPF_JOY_RIGHT | Right |
If type = JP_TYPE_MOUSE the bit map of portState is: | |
JPF_BUTTON_BLUE | Right mouse |
JPF_BUTTON_RED | Left mouse |
JPF_BUTTON_PLAY | Middle mouse |
JP_MVERT_MASK | Mask for vertical counter |
JP_MHORZ_MASK | Mask for horizontal counter |
If type = JP_TYPE_ANALOGUE the bit map of portState is: | |
JPF_BUTTON_RED | Button 1 (standard fire) |
JPF_BUTTON_BLUE | Button 2 |
JPF_BUTTON_GREEN | Button 3 |
JPF_BUTTON_YELLOW | Button 4 |
JPF_BUTTON_FORWARD | Button 5 |
JPF_BUTTON_REVERSE | Button 6 |
JPF_BUTTON_PLAY | Button 7 |
JP_XAXIS_MASK | Mask for horizontal position |
JP_YAXIS_MASK | Mask for vertical position |