diff --git a/input-native.ts b/input-native.ts index f2f6300..86aa009 100644 --- a/input-native.ts +++ b/input-native.ts @@ -43,14 +43,29 @@ export const KEY_TAB = 0x09; export const KEY_BACKSPACE = 0x7F; export const KEY_SPACE = 0x20; -export const OFF_TYPE = 0; -export const OFF_MOD = 1; -export const OFF_KEY = 2; -export const OFF_CH = 4; -export const OFF_X = 8; -export const OFF_Y = 12; -export const OFF_W = 16; -export const OFF_H = 20; +import { int32, offsets, struct, uint8, uint16, uint32 } from "./typedef.ts"; + +const InputEventLayout = struct({ + type: uint8(), + mod: uint8(), + key: uint16(), + ch: uint32(), + x: int32(), + y: int32(), + w: int32(), + h: int32(), +}); + +const { + type: OFFSET_TYPE, + mod: OFFSET_MOD, + key: OFFSET_KEY, + ch: OFFSET_CH, + x: OFFSET_X, + y: OFFSET_Y, + w: OFFSET_W, + h: OFFSET_H, +} = offsets(InputEventLayout); export interface NativeInputEvent { type: number; @@ -65,14 +80,14 @@ export interface NativeInputEvent { export function readEvent(view: DataView, ptr: number): NativeInputEvent { return { - type: view.getUint8(ptr + OFF_TYPE), - mod: view.getUint8(ptr + OFF_MOD), - key: view.getUint16(ptr + OFF_KEY, true), - ch: view.getUint32(ptr + OFF_CH, true), - x: view.getInt32(ptr + OFF_X, true), - y: view.getInt32(ptr + OFF_Y, true), - w: view.getInt32(ptr + OFF_W, true), - h: view.getInt32(ptr + OFF_H, true), + type: view.getUint8(ptr + OFFSET_TYPE), + mod: view.getUint8(ptr + OFFSET_MOD), + key: view.getUint16(ptr + OFFSET_KEY, true), + ch: view.getUint32(ptr + OFFSET_CH, true), + x: view.getInt32(ptr + OFFSET_X, true), + y: view.getInt32(ptr + OFFSET_Y, true), + w: view.getInt32(ptr + OFFSET_W, true), + h: view.getInt32(ptr + OFFSET_H, true), }; } diff --git a/typedef.ts b/typedef.ts new file mode 100644 index 0000000..c145aae --- /dev/null +++ b/typedef.ts @@ -0,0 +1,119 @@ +export type Attrs = { + [K in keyof T]: TypeDef; +}; + +export type Alignment = 1 | 2 | 4 | 8; + +export type LayoutElement = { + type: "padding"; + byteLength: number; +} | { + type: "field"; + name: string; + offset: number; + typedef: Attrs[keyof Attrs]; +}; + +export type Struct = { + type: "struct"; + byteLength: number; + byteAlign: Alignment; + layout: LayoutElement[]; +}; + +export type Num = { + type: "i32" | "f32" | "f64" | "uint8" | "uint16" | "uint32" | "int16" | "int32"; + byteAlign: Alignment; + byteLength: number; + T?: T; +}; + +export type TypeDef = Num | Struct; + +export const int32 = (): TypeDef => ({ + type: "int32", + byteLength: 4, + byteAlign: 4, +}); +export const uint8 = (): TypeDef => ({ + type: "uint8", + byteLength: 1, + byteAlign: 1, +}); +export const uint16 = (): TypeDef => ({ + type: "uint16", + byteLength: 2, + byteAlign: 2, +}); +export const uint32 = (): TypeDef => ({ + type: "uint32", + byteAlign: 4, + byteLength: 4, +}); + +export function struct( + attrs: Attrs, +): Struct { + let entries = Object.entries(attrs) as [ + keyof Attrs, + Attrs[keyof Attrs], + ][]; + + let acc = { + layout: [] as Struct["layout"], + offset: 0, + }; + + let byteAlign = Math.max( + ...entries.map(([, typedef]) => typedef.byteAlign), + ) as Alignment; + + for (let [name, typedef] of entries) { + let padding = pad(acc.offset, typedef.byteAlign); + if (padding > 0) { + acc.layout.push({ type: "padding", byteLength: padding }); + acc.offset += padding; + } + + acc.layout.push({ + type: "field", + name: name as string, + offset: acc.offset, + typedef, + }); + acc.offset += typedef.byteLength; + } + + let padding = pad(acc.offset, byteAlign); + if (padding > 0) { + acc.layout.push({ type: "padding", byteLength: padding }); + acc.offset += padding; + } + + return { + type: "struct", + layout: acc.layout, + byteLength: acc.offset, + byteAlign, + }; +} + +export function offsets( + def: Struct, +): { [K in keyof T]: number } { + let result = {} as { [K in keyof T]: number }; + for (let element of def.layout) { + if (element.type === "field") { + result[element.name as keyof T] = element.offset; + } + } + return result; +} + +export function pad(offset: number, alignment: number): number { + if ((offset % alignment) !== 0) { + return alignment - (offset % alignment); + } else { + return 0; + } +}